Răsfoiți Sursa

活动收集/支付多通道

licailing 3 ani în urmă
părinte
comite
9702e2ddca
26 a modificat fișierele cu 1418 adăugiri și 39 ștergeri
  1. 1 0
      src/main/java/com/izouma/nineth/config/AdapayProperties.java
  2. 5 0
      src/main/java/com/izouma/nineth/config/EventNames.java
  3. 40 0
      src/main/java/com/izouma/nineth/domain/AdapayMerchant.java
  4. 4 0
      src/main/java/com/izouma/nineth/dto/UserBankCard.java
  5. 116 0
      src/main/java/com/izouma/nineth/dto/adapay/AccountInfo.java
  6. 17 0
      src/main/java/com/izouma/nineth/dto/adapay/DivMembersItem.java
  7. 206 0
      src/main/java/com/izouma/nineth/dto/adapay/MemberInfo.java
  8. 88 0
      src/main/java/com/izouma/nineth/dto/adapay/PaymentItem.java
  9. 28 0
      src/main/java/com/izouma/nineth/dto/adapay/PaymentList.java
  10. 94 0
      src/main/java/com/izouma/nineth/dto/adapay/SettleAccountsItem.java
  11. 43 0
      src/main/java/com/izouma/nineth/listener/BroadcastEventListener.java
  12. 52 0
      src/main/java/com/izouma/nineth/listener/CreateOrderListener.java
  13. 30 0
      src/main/java/com/izouma/nineth/listener/MintListener.java
  14. 27 0
      src/main/java/com/izouma/nineth/listener/OrderNotifyListener.java
  15. 28 0
      src/main/java/com/izouma/nineth/listener/UpdateActivityStockListener.java
  16. 27 0
      src/main/java/com/izouma/nineth/listener/UpdateSaleListener.java
  17. 27 0
      src/main/java/com/izouma/nineth/listener/UpdateStockListener.java
  18. 16 0
      src/main/java/com/izouma/nineth/repo/AdapayMerchantRepo.java
  19. 7 2
      src/main/java/com/izouma/nineth/repo/CollectionRepo.java
  20. 6 6
      src/main/java/com/izouma/nineth/service/ActivityOrderService.java
  21. 295 0
      src/main/java/com/izouma/nineth/service/AdapayMerchantService.java
  22. 65 28
      src/main/java/com/izouma/nineth/service/UserService.java
  23. 66 0
      src/main/java/com/izouma/nineth/web/ActivityCollectionController.java
  24. 60 0
      src/main/java/com/izouma/nineth/web/ActivityMaterialController.java
  25. 67 0
      src/main/java/com/izouma/nineth/web/ActivityOrderController.java
  26. 3 3
      src/main/java/com/izouma/nineth/web/UserController.java

+ 1 - 0
src/main/java/com/izouma/nineth/config/AdapayProperties.java

@@ -6,6 +6,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
 @Data
 @ConfigurationProperties(prefix = "adapay")
 public class AdapayProperties {
+    private String  merchant;
     private String  appId;
     private boolean debug;
     private boolean prod;

+ 5 - 0
src/main/java/com/izouma/nineth/config/EventNames.java

@@ -0,0 +1,5 @@
+package com.izouma.nineth.config;
+
+public class EventNames {
+    public final static String SWITCH_ACCOUNT = "switchAccount";
+}

+ 40 - 0
src/main/java/com/izouma/nineth/domain/AdapayMerchant.java

@@ -0,0 +1,40 @@
+package com.izouma.nineth.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+
+@Data
+@Entity
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class AdapayMerchant extends BaseEntity {
+
+    @Column(unique = true, length = 72)
+    private String name;
+
+    @Column(unique = true, length = 72)
+    private String appId;
+
+    private String apiKey;
+
+    private String mockKey;
+
+    @Column(columnDefinition = "TEXT")
+    private String publicKey;
+
+    @Column(columnDefinition = "TEXT")
+    private String privKey;
+
+    private String wxAppId;
+
+    private String status;
+
+    private boolean selected;
+
+}

+ 4 - 0
src/main/java/com/izouma/nineth/dto/UserBankCard.java

@@ -28,4 +28,8 @@ public class UserBankCard extends BaseEntity {
     private String bankNo;
 
     private String phone;
+
+    private String realName;
+
+    private String idNo;
 }

+ 116 - 0
src/main/java/com/izouma/nineth/dto/adapay/AccountInfo.java

@@ -0,0 +1,116 @@
+package com.izouma.nineth.dto.adapay;
+
+import com.alibaba.fastjson.annotation.JSONField;
+
+public class AccountInfo{
+
+	@JSONField(name="bank_code")
+	private String bankCode;
+
+	@JSONField(name="cert_type")
+	private String certType;
+
+	@JSONField(name="tel_no")
+	private String telNo;
+
+	@JSONField(name="area_code")
+	private String areaCode;
+
+	@JSONField(name="bank_name")
+	private String bankName;
+
+	@JSONField(name="card_name")
+	private String cardName;
+
+	@JSONField(name="cert_id")
+	private String certId;
+
+	@JSONField(name="bank_acct_type")
+	private String bankAcctType;
+
+	@JSONField(name="prov_code")
+	private String provCode;
+
+	@JSONField(name="card_id")
+	private String cardId;
+
+	public void setBankCode(String bankCode){
+		this.bankCode = bankCode;
+	}
+
+	public String getBankCode(){
+		return bankCode;
+	}
+
+	public void setCertType(String certType){
+		this.certType = certType;
+	}
+
+	public String getCertType(){
+		return certType;
+	}
+
+	public void setTelNo(String telNo){
+		this.telNo = telNo;
+	}
+
+	public String getTelNo(){
+		return telNo;
+	}
+
+	public void setAreaCode(String areaCode){
+		this.areaCode = areaCode;
+	}
+
+	public String getAreaCode(){
+		return areaCode;
+	}
+
+	public void setBankName(String bankName){
+		this.bankName = bankName;
+	}
+
+	public String getBankName(){
+		return bankName;
+	}
+
+	public void setCardName(String cardName){
+		this.cardName = cardName;
+	}
+
+	public String getCardName(){
+		return cardName;
+	}
+
+	public void setCertId(String certId){
+		this.certId = certId;
+	}
+
+	public String getCertId(){
+		return certId;
+	}
+
+	public void setBankAcctType(String bankAcctType){
+		this.bankAcctType = bankAcctType;
+	}
+
+	public String getBankAcctType(){
+		return bankAcctType;
+	}
+
+	public void setProvCode(String provCode){
+		this.provCode = provCode;
+	}
+
+	public String getProvCode(){
+		return provCode;
+	}
+
+	public void setCardId(String cardId){
+		this.cardId = cardId;
+	}
+
+	public String getCardId(){
+		return cardId;
+	}
+}

+ 17 - 0
src/main/java/com/izouma/nineth/dto/adapay/DivMembersItem.java

@@ -0,0 +1,17 @@
+package com.izouma.nineth.dto.adapay;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+@Data
+public class DivMembersItem {
+
+    @JSONField(name = "member_id")
+    private String memberId;
+
+    @JSONField(name = "amount")
+    private String amount;
+
+    @JSONField(name = "fee_flag")
+    private String feeFlag;
+}

+ 206 - 0
src/main/java/com/izouma/nineth/dto/adapay/MemberInfo.java

@@ -0,0 +1,206 @@
+package com.izouma.nineth.dto.adapay;
+
+import com.alibaba.fastjson.annotation.JSONField;
+
+import java.util.List;
+
+public class MemberInfo {
+
+    @JSONField(name = "member_id")
+    private String memberId;
+
+    @JSONField(name = "created_time")
+    private String createdTime;
+
+    @JSONField(name = "cert_type")
+    private String certType;
+
+    @JSONField(name = "gender")
+    private String gender;
+
+    @JSONField(name = "identified")
+    private String identified;
+
+    @JSONField(name = "tel_no")
+    private String telNo;
+
+    @JSONField(name = "prod_mode")
+    private String prodMode;
+
+    @JSONField(name = "nickname")
+    private String nickname;
+
+    @JSONField(name = "disabled")
+    private String disabled;
+
+    @JSONField(name = "location")
+    private String location;
+
+    @JSONField(name = "app_id")
+    private String appId;
+
+    @JSONField(name = "settle_accounts")
+    private List<SettleAccountsItem> settleAccounts;
+
+    @JSONField(name = "email")
+    private String email;
+
+    @JSONField(name = "object")
+    private String object;
+
+    @JSONField(name = "status")
+    private String status;
+
+    @JSONField(name = "error_type")
+    private String errorType;
+
+    @JSONField(name = "error_code")
+    private String errorCode;
+
+    @JSONField(name = "error_msg")
+    private String errorMsg;
+
+    public void setMemberId(String memberId) {
+        this.memberId = memberId;
+    }
+
+    public String getMemberId() {
+        return memberId;
+    }
+
+    public void setCreatedTime(String createdTime) {
+        this.createdTime = createdTime;
+    }
+
+    public String getCreatedTime() {
+        return createdTime;
+    }
+
+    public void setCertType(String certType) {
+        this.certType = certType;
+    }
+
+    public String getCertType() {
+        return certType;
+    }
+
+    public void setGender(String gender) {
+        this.gender = gender;
+    }
+
+    public String getGender() {
+        return gender;
+    }
+
+    public void setIdentified(String identified) {
+        this.identified = identified;
+    }
+
+    public String getIdentified() {
+        return identified;
+    }
+
+    public void setTelNo(String telNo) {
+        this.telNo = telNo;
+    }
+
+    public String getTelNo() {
+        return telNo;
+    }
+
+    public void setProdMode(String prodMode) {
+        this.prodMode = prodMode;
+    }
+
+    public String getProdMode() {
+        return prodMode;
+    }
+
+    public void setNickname(String nickname) {
+        this.nickname = nickname;
+    }
+
+    public String getNickname() {
+        return nickname;
+    }
+
+    public void setDisabled(String disabled) {
+        this.disabled = disabled;
+    }
+
+    public String getDisabled() {
+        return disabled;
+    }
+
+    public void setLocation(String location) {
+        this.location = location;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setSettleAccounts(List<SettleAccountsItem> settleAccounts) {
+        this.settleAccounts = settleAccounts;
+    }
+
+    public List<SettleAccountsItem> getSettleAccounts() {
+        return settleAccounts;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setObject(String object) {
+        this.object = object;
+    }
+
+    public String getObject() {
+        return object;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public String getErrorType() {
+        return errorType;
+    }
+
+    public void setErrorType(String errorType) {
+        this.errorType = errorType;
+    }
+
+    public String getErrorCode() {
+        return errorCode;
+    }
+
+    public void setErrorCode(String errorCode) {
+        this.errorCode = errorCode;
+    }
+
+    public String getErrorMsg() {
+        return errorMsg;
+    }
+
+    public void setErrorMsg(String errorMsg) {
+        this.errorMsg = errorMsg;
+    }
+}

+ 88 - 0
src/main/java/com/izouma/nineth/dto/adapay/PaymentItem.java

@@ -0,0 +1,88 @@
+package com.izouma.nineth.dto.adapay;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class PaymentItem {
+
+    @JSONField(name = "order_no")
+    private String orderNo;
+
+    @JSONField(name = "created_time")
+    private String createdTime;
+
+    @JSONField(name = "pay_amt")
+    private String payAmt;
+
+    @JSONField(name = "open_id")
+    private String openId;
+
+    @JSONField(name = "confirmed_amt")
+    private String confirmedAmt;
+
+    @JSONField(name = "end_time")
+    private String endTime;
+
+    @JSONField(name = "fee_mode")
+    private String feeMode;
+
+    @JSONField(name = "coupon_infos")
+    private String couponInfos;
+
+    @JSONField(name = "discount_amt")
+    private String discountAmt;
+
+    @JSONField(name = "cash_pay_amt")
+    private String cashPayAmt;
+
+    @JSONField(name = "reserved_amt")
+    private String reservedAmt;
+
+    @JSONField(name = "out_trans_id")
+    private String outTransId;
+
+    @JSONField(name = "party_order_id")
+    private String partyOrderId;
+
+    @JSONField(name = "pay_mode")
+    private String payMode;
+
+    @JSONField(name = "div_members")
+    private List<DivMembersItem> divMembers;
+
+    @JSONField(name = "refunded_amt")
+    private String refundedAmt;
+
+    @JSONField(name = "prod_mode")
+    private String prodMode;
+
+    @JSONField(name = "pay_channel")
+    private String payChannel;
+
+    @JSONField(name = "has_more")
+    private boolean hasMore;
+
+    @JSONField(name = "id")
+    private String id;
+
+    @JSONField(name = "app_id")
+    private String appId;
+
+    @JSONField(name = "fee_amt")
+    private String feeAmt;
+
+    @JSONField(name = "object")
+    private String object;
+
+    @JSONField(name = "status")
+    private String status;
+
+    @JSONField(name = "error_msg")
+    private String errorMsg;
+
+    @JSONField(name = "error_code")
+    private String errorCode;
+}

+ 28 - 0
src/main/java/com/izouma/nineth/dto/adapay/PaymentList.java

@@ -0,0 +1,28 @@
+package com.izouma.nineth.dto.adapay;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class PaymentList {
+
+    @JSONField(name = "payments")
+    private List<PaymentItem> payments;
+
+    @JSONField(name = "prod_mode")
+    private String prodMode;
+
+    @JSONField(name = "has_more")
+    private boolean hasMore;
+
+    @JSONField(name = "app_id")
+    private String appId;
+
+    @JSONField(name = "object")
+    private String object;
+
+    @JSONField(name = "status")
+    private String status;
+}

+ 94 - 0
src/main/java/com/izouma/nineth/dto/adapay/SettleAccountsItem.java

@@ -0,0 +1,94 @@
+package com.izouma.nineth.dto.adapay;
+
+import com.alibaba.fastjson.annotation.JSONField;
+
+public class SettleAccountsItem{
+
+	@JSONField(name="member_id")
+	private String memberId;
+
+	@JSONField(name="upd_ts")
+	private long updTs;
+
+	@JSONField(name="account_info")
+	private AccountInfo accountInfo;
+
+	@JSONField(name="channel")
+	private String channel;
+
+	@JSONField(name="id")
+	private String id;
+
+	@JSONField(name="type")
+	private String type;
+
+	@JSONField(name="app_id")
+	private String appId;
+
+	@JSONField(name="cre_ts")
+	private long creTs;
+
+	public void setMemberId(String memberId){
+		this.memberId = memberId;
+	}
+
+	public String getMemberId(){
+		return memberId;
+	}
+
+	public void setUpdTs(long updTs){
+		this.updTs = updTs;
+	}
+
+	public long getUpdTs(){
+		return updTs;
+	}
+
+	public void setAccountInfo(AccountInfo accountInfo){
+		this.accountInfo = accountInfo;
+	}
+
+	public AccountInfo getAccountInfo(){
+		return accountInfo;
+	}
+
+	public void setChannel(String channel){
+		this.channel = channel;
+	}
+
+	public String getChannel(){
+		return channel;
+	}
+
+	public void setId(String id){
+		this.id = id;
+	}
+
+	public String getId(){
+		return id;
+	}
+
+	public void setType(String type){
+		this.type = type;
+	}
+
+	public String getType(){
+		return type;
+	}
+
+	public void setAppId(String appId){
+		this.appId = appId;
+	}
+
+	public String getAppId(){
+		return appId;
+	}
+
+	public void setCreTs(long creTs){
+		this.creTs = creTs;
+	}
+
+	public long getCreTs(){
+		return creTs;
+	}
+}

+ 43 - 0
src/main/java/com/izouma/nineth/listener/BroadcastEventListener.java

@@ -0,0 +1,43 @@
+package com.izouma.nineth.listener;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.izouma.nineth.config.EventNames;
+import com.izouma.nineth.service.AdapayMerchantService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.ConsumeMode;
+import org.apache.rocketmq.spring.annotation.MessageModel;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Service;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+@RocketMQMessageListener(
+        messageModel = MessageModel.BROADCASTING,
+        consumerGroup = "${general.broadcast-event-group}",
+        topic = "${general.broadcast-event-topic}",
+        consumeMode = ConsumeMode.CONCURRENTLY)
+public class BroadcastEventListener implements RocketMQListener<JSONObject> {
+    private AdapayMerchantService adapayMerchantService;
+
+    @Override
+    public void onMessage(JSONObject message) {
+        log.info("接收到广播事件 {}", JSONObject.toJSONString(message, SerializerFeature.PrettyFormat));
+        String name = message.getString("name");
+        if (name != null) {
+            switch (name) {
+                case EventNames.SWITCH_ACCOUNT:
+                    try {
+                        Long id = message.getLong("data");
+                        adapayMerchantService.select(id);
+                    } catch (Exception e) {
+                        log.error("event error", e);
+                    }
+                    break;
+            }
+        }
+    }
+}

+ 52 - 0
src/main/java/com/izouma/nineth/listener/CreateOrderListener.java

@@ -0,0 +1,52 @@
+package com.izouma.nineth.listener;
+
+import com.izouma.nineth.config.RedisKeys;
+import com.izouma.nineth.domain.Order;
+import com.izouma.nineth.event.CreateOrderEvent;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.service.OrderService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.ConsumeMode;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+@RocketMQMessageListener(
+        consumerGroup = "${general.create-order-group}",
+        topic = "${general.create-order-topic}",
+        consumeMode = ConsumeMode.ORDERLY)
+//@ConditionalOnProperty(value = "general.notify-server", havingValue = "false", matchIfMissing = true)
+public class CreateOrderListener implements RocketMQListener<CreateOrderEvent> {
+    private OrderService                  orderService;
+    private RedisTemplate<String, Object> redisTemplate;
+
+    @Override
+    public void onMessage(CreateOrderEvent event) {
+        log.info("收到订单创建消息: {}", event.getId());
+        Map<String, Object> map = new HashMap<>();
+        try {
+            Order order = orderService.create(event.getUserId(), event.getCollectionId(), event.getQty(),
+                    event.getAddressId(), event.getUserCouponId(), event.getInvitor(), event.getId());
+            map.put("success", true);
+            map.put("data", order);
+        } catch (Exception e) {
+            if (e instanceof BusinessException) {
+                log.error("订单创建失败 {}", e.getMessage());
+            } else {
+                log.error("订单创建失败", e);
+            }
+            map.put("success", false);
+            map.put("data", e.getMessage());
+        }
+        redisTemplate.boundValueOps(RedisKeys.CREATE_ORDER + event.getId()).set(map, 1, TimeUnit.DAYS);
+    }
+}

+ 30 - 0
src/main/java/com/izouma/nineth/listener/MintListener.java

@@ -0,0 +1,30 @@
+package com.izouma.nineth.listener;
+
+import com.izouma.nineth.service.AssetMintService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.ConsumeMode;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Service;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+@RocketMQMessageListener(
+        consumerGroup = "${general.mint-group}",
+        topic = "${general.mint-topic}",
+        consumeMode = ConsumeMode.ORDERLY)
+//@ConditionalOnProperty(value = "general.notify-server", havingValue = "true")
+public class MintListener implements RocketMQListener<Long> {
+    private AssetMintService assetMintService;
+
+    @Override
+    public void onMessage(Long assetId) {
+        try {
+            assetMintService.mint(assetId);
+        } catch (Exception e) {
+            log.error("铸造失败 " + assetId, e);
+        }
+    }
+}

+ 27 - 0
src/main/java/com/izouma/nineth/listener/OrderNotifyListener.java

@@ -0,0 +1,27 @@
+package com.izouma.nineth.listener;
+
+import com.izouma.nineth.event.OrderNotifyEvent;
+import com.izouma.nineth.service.OrderService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.ConsumeMode;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Service;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+@RocketMQMessageListener(
+        consumerGroup = "${general.order-notify-group}",
+        topic = "${general.order-notify-topic}",
+        consumeMode = ConsumeMode.ORDERLY)
+//@ConditionalOnProperty(value = "general.notify-server", havingValue = "true")
+public class OrderNotifyListener implements RocketMQListener<OrderNotifyEvent> {
+    private OrderService orderService;
+
+    @Override
+    public void onMessage(OrderNotifyEvent e) {
+        orderService.notifyOrder(e.getOrderId(), e.getPayMethod(), e.getTransactionId());
+    }
+}

+ 28 - 0
src/main/java/com/izouma/nineth/listener/UpdateActivityStockListener.java

@@ -0,0 +1,28 @@
+package com.izouma.nineth.listener;
+
+import com.izouma.nineth.service.ActivityCollectionService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.ConsumeMode;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Service;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+@RocketMQMessageListener(
+        consumerGroup = "${general.update-activity-stock-group}",
+        topic = "${general.update-activity-stock-topic}",
+        consumeMode = ConsumeMode.ORDERLY)
+@ConditionalOnProperty(value = "general.notify-server", havingValue = "false", matchIfMissing = true)
+public class UpdateActivityStockListener implements RocketMQListener<Long> {
+
+    private ActivityCollectionService activityCollectionService;
+
+    @Override
+    public void onMessage(Long id) {
+        activityCollectionService.syncStock(id);
+    }
+}

+ 27 - 0
src/main/java/com/izouma/nineth/listener/UpdateSaleListener.java

@@ -0,0 +1,27 @@
+package com.izouma.nineth.listener;
+
+import com.izouma.nineth.service.CollectionService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.ConsumeMode;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Service;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+@RocketMQMessageListener(
+        consumerGroup = "${general.update-sale-group}",
+        topic = "${general.update-sale-topic}",
+        consumeMode = ConsumeMode.ORDERLY)
+//@ConditionalOnProperty(value = "general.notify-server", havingValue = "false", matchIfMissing = true)
+public class UpdateSaleListener implements RocketMQListener<Long> {
+
+    private CollectionService collectionService;
+
+    @Override
+    public void onMessage(Long id) {
+        collectionService.syncSale(id);
+    }
+}

+ 27 - 0
src/main/java/com/izouma/nineth/listener/UpdateStockListener.java

@@ -0,0 +1,27 @@
+package com.izouma.nineth.listener;
+
+import com.izouma.nineth.service.CollectionService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.ConsumeMode;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Service;
+
+@Service
+@Slf4j
+@AllArgsConstructor
+@RocketMQMessageListener(
+        consumerGroup = "${general.update-stock-group}",
+        topic = "${general.update-stock-topic}",
+        consumeMode = ConsumeMode.ORDERLY)
+//@ConditionalOnProperty(value = "general.notify-server", havingValue = "false", matchIfMissing = true)
+public class UpdateStockListener implements RocketMQListener<Long> {
+
+    private CollectionService collectionService;
+
+    @Override
+    public void onMessage(Long id) {
+        collectionService.syncStock(id);
+    }
+}

+ 16 - 0
src/main/java/com/izouma/nineth/repo/AdapayMerchantRepo.java

@@ -0,0 +1,16 @@
+package com.izouma.nineth.repo;
+
+import com.izouma.nineth.domain.AdapayMerchant;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+import javax.transaction.Transactional;
+
+public interface AdapayMerchantRepo extends JpaRepository<AdapayMerchant, Long>, JpaSpecificationExecutor<AdapayMerchant> {
+    @Query("update AdapayMerchant t set t.del = true where t.id = ?1")
+    @Modifying
+    @Transactional
+    void softDelete(Long id);
+}

+ 7 - 2
src/main/java/com/izouma/nineth/repo/CollectionRepo.java

@@ -36,8 +36,6 @@ public interface CollectionRepo extends JpaRepository<Collection, Long>, JpaSpec
     @Cacheable("collection")
     Optional<Collection> findById(Long id);
 
-    Optional<Collection> findByIdAndDelFalse(Long id);
-
     @Query("update Collection t set t.likes = t.likes + ?2 where t.id = ?1")
     @Modifying
     @Transactional
@@ -100,4 +98,11 @@ public interface CollectionRepo extends JpaRepository<Collection, Long>, JpaSpec
     Integer getStock(Long id);
     List<Collection> findAllByIdIn(java.util.Collection<Long> ids);
 
+    @Modifying
+    @Transactional
+    void deleteAllByIdIn(java.util.Collection<Long> id);
+
+    @Query("select c.id from Collection c where c.assetId = ?1 and c.source = 'TRANSFER'")
+    List<Long> findAllByAssetId(Long assetId);
+
 }

+ 6 - 6
src/main/java/com/izouma/nineth/service/ActivityOrderService.java

@@ -84,14 +84,14 @@ public class ActivityOrderService {
                         }
                         Collection collection = collectionRepo.findById(asset.getPublicCollectionId())
                                 .orElseThrow(new BusinessException("无展示记录"));
-//                        List<Long> collectionIds = collectionRepo.findAllByAssetId(collection.getAssetId());
-//                        if (CollectionUtils.isNotEmpty(collectionIds)) {
-//                            log.info("删除collection {}", collectionIds);
-//                            collectionRepo.deleteAllByIdIn(collectionIds);
-//                        } else {
+                        List<Long> collectionIds = collectionRepo.findAllByAssetId(collection.getAssetId());
+                        if (CollectionUtils.isNotEmpty(collectionIds)) {
+                            log.info("删除collection {}", collectionIds);
+                            collectionRepo.deleteAllByIdIn(collectionIds);
+                        } else {
                             log.info("删除collection {}", collection.getId());
                             collectionRepo.delete(collection);
-//                        }
+                        }
                     }
                 }
             });

+ 295 - 0
src/main/java/com/izouma/nineth/service/AdapayMerchantService.java

@@ -0,0 +1,295 @@
+package com.izouma.nineth.service;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.huifu.adapay.Adapay;
+import com.huifu.adapay.core.exception.BaseAdaPayException;
+import com.huifu.adapay.model.*;
+import com.izouma.nineth.config.AdapayProperties;
+import com.izouma.nineth.config.EventNames;
+import com.izouma.nineth.config.GeneralProperties;
+import com.izouma.nineth.domain.AdapayMerchant;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.dto.adapay.MemberInfo;
+import com.izouma.nineth.dto.adapay.PaymentItem;
+import com.izouma.nineth.dto.adapay.PaymentList;
+import com.izouma.nineth.dto.adapay.SettleAccountsItem;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.AdapayMerchantRepo;
+import com.izouma.nineth.utils.JpaUtils;
+import com.izouma.nineth.utils.ObjUtils;
+import com.izouma.nineth.utils.SnowflakeIdWorker;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.MapUtils;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+@Service
+@AllArgsConstructor
+@Slf4j
+public class AdapayMerchantService {
+
+    private final AdapayMerchantRepo adapayMerchantRepo;
+    private final AdapayProperties  adapayProperties;
+    private final RocketMQTemplate  rocketMQTemplate;
+    private final GeneralProperties generalProperties;
+
+    @PostConstruct
+    public void init() {
+        log.info("init AdapayMerchantService");
+        for (AdapayMerchant merchant : adapayMerchantRepo.findAll()) {
+            addMerchant(merchant);
+            if (merchant.isSelected()) {
+                try {
+                    select(merchant.getId());
+                    log.info("select merchant success={}", merchant.getName());
+                } catch (Exception e) {
+                    log.error("select merchant error", e);
+                }
+            }
+        }
+    }
+
+    public Page<AdapayMerchant> all(PageQuery pageQuery) {
+        return adapayMerchantRepo.findAll(JpaUtils.toSpecification(pageQuery, AdapayMerchant.class), JpaUtils.toPageRequest(pageQuery));
+    }
+
+    public AdapayMerchant save(AdapayMerchant record) {
+        record = adapayMerchantRepo.save(record);
+        addMerchant(record);
+        return record;
+    }
+
+    public AdapayMerchant update(AdapayMerchant record) {
+        if (record.getId() == null) {
+            throw new BusinessException("id不能为空");
+        }
+        AdapayMerchant orig = adapayMerchantRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+        ObjUtils.merge(orig, record);
+        record = adapayMerchantRepo.save(orig);
+        addMerchant(record);
+        return record;
+    }
+
+
+    public void sendSelectEvent(Long id) {
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("name", EventNames.SWITCH_ACCOUNT);
+        jsonObject.put("data", id);
+        rocketMQTemplate.convertAndSend(generalProperties.getBroadcastEventTopic(), jsonObject);
+
+        try {
+            Thread.sleep(500);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void select(Long id) throws Exception {
+        AdapayMerchant merchant = adapayMerchantRepo.findById(id).orElseThrow(new BusinessException("商户不存在"));
+
+        MerConfig merConfig = new MerConfig();
+        merConfig.setApiKey(merchant.getApiKey());
+        merConfig.setApiMockKey(merchant.getMockKey());
+        merConfig.setRSAPrivateKey(merchant.getPrivKey());
+        merConfig.setRSAPublicKey(merchant.getPublicKey());
+        Adapay.initWithMerConfig(merConfig);
+
+        adapayProperties.setApiKey(merchant.getApiKey());
+        adapayProperties.setMockKey(merchant.getMockKey());
+        adapayProperties.setPrivKey(merchant.getPrivKey());
+        adapayProperties.setPublicKey(merchant.getPublicKey());
+        adapayProperties.setMerchant(merchant.getName());
+        adapayProperties.setAppId(merchant.getAppId());
+
+        List<AdapayMerchant> list = adapayMerchantRepo.findAll();
+        list.forEach(m -> m.setSelected(m.getId().equals(id)));
+        adapayMerchantRepo.saveAll(list);
+    }
+
+    public void addMerchant(AdapayMerchant merchant) {
+        try {
+            MerConfig merConfig = new MerConfig();
+            merConfig.setApiKey(merchant.getApiKey());
+            merConfig.setApiMockKey(merchant.getMockKey());
+            merConfig.setRSAPrivateKey(merchant.getPrivKey());
+            merConfig.setRSAPublicKey(merchant.getPublicKey());
+            Adapay.addMerConfig(merConfig, merchant.getName());
+        } catch (Exception e) {
+            log.error("add Merchant Error", e);
+        }
+    }
+
+    public void createMemberForAll(String memberId, String tel, String realName, String idno) throws BaseAdaPayException {
+        AtomicReference<BaseAdaPayException> ex = new AtomicReference<>();
+        adapayMerchantRepo.findAll().parallelStream().forEach(merchant -> {
+            try {
+                createMember(merchant.getName(), merchant.getAppId(), memberId, tel, realName, idno);
+            } catch (BaseAdaPayException e) {
+                log.error("createMemberForAll", e);
+                ex.set(e);
+            }
+        });
+        if (ex.get() != null) {
+            throw ex.get();
+        }
+    }
+
+    public void createMember(String merchant, String appId, String memberId, String tel, String realName, String idno) throws BaseAdaPayException {
+        Map<String, Object> memberParams = new HashMap<>();
+        memberParams.put("adapay_func_code", "members.realname");
+        memberParams.put("member_id", memberId);
+        memberParams.put("app_id", appId);
+        memberParams.put("tel_no", tel);
+        memberParams.put("user_name", realName);
+        memberParams.put("cert_type", "00");
+        memberParams.put("cert_id", idno);
+        Map<String, Object> res = AdapayCommon.requestAdapay(memberParams, merchant);
+        log.info("createMember merchant={} response={}", merchant, JSON.toJSONString(res, SerializerFeature.PrettyFormat));
+        if (!("succeeded".equals(MapUtils.getString(res, "status"))
+                || "member_id_exists".equals(MapUtils.getString(res, "error_code")))) {
+            String errMsg = MapUtils.getString(res, "error_msg");
+            String errCode = MapUtils.getString(res, "error_code");
+            log.error("createMember error merchant={} memberId={}", merchant, memberId);
+            throw new BusinessException(errMsg + "(" + errCode + ")");
+        }
+    }
+
+    public String createSettleAccountForAll(String memberId, String realName, String idNo, String phone, String bankNo) throws BaseAdaPayException {
+        String id = null;
+        for (AdapayMerchant merchant : adapayMerchantRepo.findAll()) {
+            id = createSettleAccount(merchant.getName(), merchant.getAppId(), memberId, realName, idNo, phone, bankNo);
+        }
+        return id;
+    }
+
+    public String createSettleAccount(String merchant, String appId, String memberId, String realName, String idNo, String phone, String bankNo) throws BaseAdaPayException {
+        Map<String, Object> settleCountParams = new HashMap<>();
+        Map<String, Object> accountInfo = new HashMap<>();
+        accountInfo.put("card_id", bankNo);
+        accountInfo.put("card_name", realName);
+        accountInfo.put("cert_id", idNo);
+        accountInfo.put("cert_type", "00");
+        accountInfo.put("tel_no", phone);
+        accountInfo.put("bank_acct_type", "2");
+        settleCountParams.put("member_id", memberId);
+        settleCountParams.put("app_id", appId);
+        settleCountParams.put("channel", "bank_account");
+        settleCountParams.put("account_info", accountInfo);
+        Map<String, Object> res = SettleAccount.create(settleCountParams, merchant);
+        log.info("createSettleAccount merchant={} response={}", merchant, JSON.toJSONString(res, SerializerFeature.PrettyFormat));
+        if (!("succeeded".equals(MapUtils.getString(res, "status"))
+                || "account_exists".equals(MapUtils.getString(res, "error_code")))) {
+            String errMsg = MapUtils.getString(res, "error_msg");
+            String errCode = MapUtils.getString(res, "error_code");
+            log.error("createSettleAccount error merchant={} memberId={}", merchant, memberId);
+            throw new BusinessException(errMsg + "(" + errCode + ")");
+        }
+        return MapUtils.getString(res, "id");
+    }
+
+    public void delSettleAccountForAll(String memberId) throws BaseAdaPayException {
+        for (AdapayMerchant merchant : adapayMerchantRepo.findAll()) {
+            delSettleAccount(merchant.getName(), merchant.getAppId(), memberId);
+        }
+    }
+
+    public void delSettleAccount(String merchant, String appId, String memberId) throws BaseAdaPayException {
+        Map<String, Object> memberParams = new HashMap<>();
+        memberParams.put("member_id", memberId);
+        memberParams.put("app_id", appId);
+        Map<String, Object> member = Member.query(memberParams, merchant);
+        log.info("query member, merchant={} member={} res={}",
+                merchant, memberId, JSON.toJSONString(member, SerializerFeature.PrettyFormat));
+        MemberInfo memberInfo = JSON.parseObject(JSON.toJSONString(member), MemberInfo.class);
+        if ("succeeded".equals(memberInfo.getStatus())) {
+            if (memberInfo.getSettleAccounts() != null && memberInfo.getSettleAccounts().size() > 0) {
+                SettleAccountsItem settleAccountsItem = memberInfo.getSettleAccounts().get(0);
+                Map<String, Object> settleCountParams = new HashMap<>();
+                settleCountParams.put("settle_account_id", settleAccountsItem.getId());
+                settleCountParams.put("member_id", memberId);
+                settleCountParams.put("app_id", appId);
+                Map<String, Object> settleCount = SettleAccount.delete(settleCountParams, merchant);
+                log.info("delSettleAccount, merchant={} member={} res={}",
+                        merchant, memberId, JSON.toJSONString(settleCount, SerializerFeature.PrettyFormat));
+                checkSuccess(settleCount);
+            }
+        } else if ("member_not_exists".equals(memberInfo.getErrorCode())) {
+            log.info("delSettleAccount member_not_exists, merchant={} member={}", merchant, memberId);
+        } else {
+            throw new BusinessException(memberInfo.getErrorMsg() + memberInfo.getErrorCode());
+        }
+    }
+
+    public void queryMembers(String merchant, String appId) {
+        boolean hasMore = true;
+        while (hasMore) {
+            try {
+                Map<String, Object> memberParams = new HashMap<>(2);
+                memberParams.put("page_index", "1");
+                memberParams.put("app_id", appId);
+                memberParams.put("page_size", "20");
+                memberParams.put("created_gte", String.valueOf(System.currentTimeMillis() - 5 * 60 * 1000));
+                memberParams.put("created_lte", String.valueOf(System.currentTimeMillis()));
+                Map<String, Object> member = Member.queryList(memberParams);
+                MapUtils.getBoolean(member, "has_more", false);
+            } catch (Exception e) {
+                log.error("queryMembers error", e);
+                hasMore = false;
+            }
+        }
+    }
+
+    public Object query(Long merchantId, String id) throws BaseAdaPayException {
+        AdapayMerchant merchant = adapayMerchantRepo.findById(merchantId).orElseThrow(new BusinessException("商户不存在"));
+        Map<String, Object> paymentParams = new HashMap<>();
+        paymentParams.put("app_id", merchant.getAppId());
+        paymentParams.put("payment_id", id);
+        Map<String, Object> paymentList = Payment.queryList(paymentParams, merchant.getName());
+        log.info(JSON.toJSONString(paymentList, SerializerFeature.PrettyFormat));
+        return paymentList;
+    }
+
+    public Object refund(Long merchantId, String id) throws BaseAdaPayException {
+        AdapayMerchant merchant = adapayMerchantRepo.findById(merchantId).orElseThrow(new BusinessException("商户不存在"));
+
+        Map<String, Object> paymentParams = new HashMap<>();
+        paymentParams.put("app_id", merchant.getAppId());
+        paymentParams.put("payment_id", id);
+        Map<String, Object> res = Payment.queryList(paymentParams, merchant.getName());
+        log.info(JSON.toJSONString(res, SerializerFeature.PrettyFormat));
+        PaymentList paymentList = JSON.parseObject(JSON.toJSONString(res), PaymentList.class);
+
+        if (paymentList.getPayments() != null && paymentList.getPayments().size() == 1) {
+            PaymentItem paymentItem = paymentList.getPayments().get(0);
+            Map<String, Object> refundParams = new HashMap<>();
+            refundParams.put("refund_amt", paymentItem.getPayAmt());
+            refundParams.put("refund_order_no", new SnowflakeIdWorker(0, 0).nextId() + "");
+            Map<String, Object> response = Refund.create(id, refundParams, merchant.getName());
+            log.info(JSON.toJSONString(response, SerializerFeature.PrettyFormat));
+            return response;
+        }
+        return res;
+    }
+
+    public static void checkSuccess(Map<String, Object> map) {
+        String status = MapUtils.getString(map, "status");
+        if (!("succeeded".equals(status))) {
+            String errMsg = MapUtils.getString(map, "error_msg");
+            String errCode = MapUtils.getString(map, "error_code");
+            if ("account_exists".equals(errCode)) {
+                return;
+            }
+            throw new BusinessException(errMsg + "(" + errCode + ")");
+        }
+    }
+}

+ 65 - 28
src/main/java/com/izouma/nineth/service/UserService.java

@@ -42,12 +42,14 @@ import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.jpa.domain.Specification;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.stereotype.Service;
 
 import javax.persistence.criteria.Predicate;
 import java.text.SimpleDateFormat;
 import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
@@ -55,23 +57,22 @@ import java.util.stream.Collectors;
 @Slf4j
 @AllArgsConstructor
 public class UserService {
-    private UserRepo          userRepo;
-    private WxMaService       wxMaService;
-    private WxMpService       wxMpService;
-    private SmsService        smsService;
-    private StorageService    storageService;
-    private JwtTokenUtil      jwtTokenUtil;
-    private CaptchaService    captchaService;
-    private FollowService     followService;
-    private FollowRepo        followRepo;
-    private IdentityAuthRepo  identityAuthRepo;
-    private SysConfigService  sysConfigService;
-    private CollectionService collectionService;
-    private AdapayService     adapayService;
-    private UserBankCardRepo  userBankCardRepo;
-    private CacheService      cacheService;
-    private InviteRepo        inviteRepo;
-    private AdapayProperties  adapayProperties;
+    private UserRepo              userRepo;
+    private WxMaService           wxMaService;
+    private WxMpService           wxMpService;
+    private SmsService            smsService;
+    private StorageService        storageService;
+    private JwtTokenUtil          jwtTokenUtil;
+    private FollowService         followService;
+    private FollowRepo            followRepo;
+    private IdentityAuthRepo      identityAuthRepo;
+    private SysConfigService      sysConfigService;
+    private AdapayService         adapayService;
+    private UserBankCardRepo      userBankCardRepo;
+    private CacheService          cacheService;
+    private InviteRepo            inviteRepo;
+    private AdapayProperties      adapayProperties;
+    private AdapayMerchantService adapayMerchantService;
 
     @CacheEvict(value = "user", key = "#user.username")
     public User update(User user) {
@@ -444,8 +445,7 @@ public class UserService {
 
     public void addBankCard(Long userId, String bankNo, String phone, String code) throws BaseAdaPayException {
         User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
-        IdentityAuth identityAuth = identityAuthRepo
-                .findFirstByUserIdAndStatusAndDelFalseOrderByCreatedAtDesc(userId, AuthStatus.SUCCESS)
+        IdentityAuth identityAuth = identityAuthRepo.findFirstByUserIdAndStatusAndDelFalseOrderByCreatedAtDesc(userId, AuthStatus.SUCCESS)
                 .orElseThrow(new BusinessException("用户未认证"));
         if (identityAuth.isOrg()) {
             //throw new BusinessException("企业认证用户请绑定对公账户");
@@ -457,15 +457,16 @@ public class UserService {
         if (!bankValidate.isValidated()) {
             throw new BusinessException("暂不支持此卡");
         }
-        if (StringUtils.isEmpty(user.getMemberId())) {
-            user.setMemberId(adapayService.createMember(userId, user.getPhone(), identityAuth.getRealName(),
-                    identityAuth.getIdNo()));
-            userRepo.save(user);
-        }
         smsService.verify(phone, code);
-        String accountId = adapayService.createSettleAccount(user.getMemberId(), identityAuth.getRealName(),
-                identityAuth.getIdNo(), phone, bankNo);
-        user.setSettleAccountId(accountId);
+
+        adapayMerchantService.createMemberForAll(userId.toString(), user.getPhone(), identityAuth.getRealName(), identityAuth.getIdNo());
+        user.setMemberId(user.getId().toString());
+        userRepo.save(user);
+
+        String accountId = adapayMerchantService.createSettleAccountForAll
+                (user.getMemberId(), identityAuth.getRealName(),
+                        identityAuth.getIdNo(), phone, bankNo);
+        user.setSettleAccountId(Optional.ofNullable(accountId).orElse("1"));
         userRepo.save(user);
 
         userBankCardRepo.save(UserBankCard.builder()
@@ -476,13 +477,15 @@ public class UserService {
                 .cardTypeDesc(bankValidate.getCardTypeDesc())
                 .userId(userId)
                 .phone(phone)
+                .realName(identityAuth.getRealName())
+                .idNo(identityAuth.getIdNo())
                 .build());
     }
 
     public void removeBankCard(Long userId) throws BaseAdaPayException {
         User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
         if (StringUtils.isNotBlank(user.getSettleAccountId()) && StringUtils.isNotBlank(user.getMemberId())) {
-            adapayService.delSettleAccount(user.getMemberId(), user.getSettleAccountId());
+            adapayMerchantService.delSettleAccountForAll(user.getMemberId());
             user.setSettleAccountId(null);
             userRepo.save(user);
             userBankCardRepo.deleteByUserId(userId);
@@ -606,4 +609,38 @@ public class UserService {
         }
         return MapUtils.getString(res, "id");
     }
+
+    @Async
+    public void checkSettleAccountAsync() {
+        checkSettleAccount();
+    }
+
+    public void checkSettleAccount() {
+        List<User> list = userRepo.findBySettleAccountIdIsNotNull();
+        AtomicInteger count = new AtomicInteger();
+        list.forEach(user -> {
+            try {
+                Thread.sleep(500);
+                IdentityAuth identityAuth = identityAuthRepo.findFirstByUserIdAndStatusAndDelFalseOrderByCreatedAtDesc(user.getId(), AuthStatus.SUCCESS)
+                        .orElseThrow(new BusinessException("用户未认证"));
+                UserBankCard userBankCard = userBankCardRepo.findByUserId(user.getId()).stream().findAny()
+                        .orElseThrow(new BusinessException("未绑卡"));
+                adapayMerchantService.createMemberForAll(
+                        user.getId().toString(), Optional.ofNullable(userBankCard.getPhone()).orElse(user.getPhone()),
+                        identityAuth.getRealName(), identityAuth.getIdNo());
+                adapayMerchantService.createSettleAccountForAll(
+                        user.getId().toString(), identityAuth.getRealName(),
+                        identityAuth.getIdNo(), Optional.ofNullable(userBankCard.getPhone()).orElse(user.getPhone()),
+                        userBankCard.getBankNo());
+                userBankCard.setPhone(Optional.ofNullable(userBankCard.getPhone()).orElse(user.getPhone()));
+                userBankCardRepo.save(userBankCard);
+            } catch (Exception e) {
+                user.setSettleAccountId(null);
+                userRepo.save(user);
+                userBankCardRepo.deleteByUserId(user.getId());
+            }
+            count.getAndIncrement();
+            log.info("checkSettleAccount {}/{}", count.get(), list.size());
+        });
+    }
 }

+ 66 - 0
src/main/java/com/izouma/nineth/web/ActivityCollectionController.java

@@ -0,0 +1,66 @@
+package com.izouma.nineth.web;
+
+import com.izouma.nineth.domain.ActivityCollection;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.ActivityCollectionRepo;
+import com.izouma.nineth.service.ActivityCollectionService;
+import com.izouma.nineth.utils.ObjUtils;
+import com.izouma.nineth.utils.excel.ExcelUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@RequestMapping("/activityCollection")
+@AllArgsConstructor
+public class ActivityCollectionController extends BaseController {
+    private ActivityCollectionService activityCollectionService;
+    private ActivityCollectionRepo    activityCollectionRepo;
+
+    @PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public ActivityCollection save(@RequestBody ActivityCollection record) {
+        if (record.getCollectionId().equals(record.getAwardCollectionId())) {
+            throw new BusinessException("兑换的藏品不能和领取的藏品相同");
+        }
+        if (record.getId() != null) {
+            ActivityCollection orig = activityCollectionRepo.findById(record.getId())
+                    .orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+            return activityCollectionRepo.save(orig);
+        }
+        record.setStock(record.getStock());
+        return activityCollectionRepo.save(record);
+    }
+
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<ActivityCollection> all(@RequestBody PageQuery pageQuery) {
+        return activityCollectionService.all(pageQuery);
+    }
+
+    @GetMapping("/get/{id}")
+    public ActivityCollection get(@PathVariable Long id) {
+        return activityCollectionRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        activityCollectionRepo.softDelete(id);
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<ActivityCollection> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+}
+

+ 60 - 0
src/main/java/com/izouma/nineth/web/ActivityMaterialController.java

@@ -0,0 +1,60 @@
+package com.izouma.nineth.web;
+
+import com.izouma.nineth.domain.ActivityMaterial;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.ActivityMaterialRepo;
+import com.izouma.nineth.service.ActivityMaterialService;
+import com.izouma.nineth.utils.ObjUtils;
+import com.izouma.nineth.utils.excel.ExcelUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@RequestMapping("/activityMaterial")
+@AllArgsConstructor
+public class ActivityMaterialController extends BaseController {
+    private ActivityMaterialService activityMaterialService;
+    private ActivityMaterialRepo activityMaterialRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public ActivityMaterial save(@RequestBody ActivityMaterial record) {
+        if (record.getId() != null) {
+            ActivityMaterial orig = activityMaterialRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+            return activityMaterialRepo.save(orig);
+        }
+        return activityMaterialRepo.save(record);
+    }
+
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<ActivityMaterial> all(@RequestBody PageQuery pageQuery) {
+        return activityMaterialService.all(pageQuery);
+    }
+
+    @GetMapping("/get/{id}")
+    public ActivityMaterial get(@PathVariable Long id) {
+        return activityMaterialRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        activityMaterialRepo.softDelete(id);
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<ActivityMaterial> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+}
+

+ 67 - 0
src/main/java/com/izouma/nineth/web/ActivityOrderController.java

@@ -0,0 +1,67 @@
+package com.izouma.nineth.web;
+
+import com.izouma.nineth.domain.ActivityOrder;
+import com.izouma.nineth.domain.Asset;
+import com.izouma.nineth.dto.PageQuery;
+import com.izouma.nineth.exception.BusinessException;
+import com.izouma.nineth.repo.ActivityOrderRepo;
+import com.izouma.nineth.service.ActivityOrderService;
+import com.izouma.nineth.utils.ObjUtils;
+import com.izouma.nineth.utils.SecurityUtils;
+import com.izouma.nineth.utils.excel.ExcelUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@RequestMapping("/activityOrder")
+@AllArgsConstructor
+public class ActivityOrderController extends BaseController {
+    private ActivityOrderService activityOrderService;
+    private ActivityOrderRepo    activityOrderRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public ActivityOrder save(@RequestBody ActivityOrder record) {
+        if (record.getId() != null) {
+            ActivityOrder orig = activityOrderRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+            return activityOrderRepo.save(orig);
+        }
+        return activityOrderRepo.save(record);
+    }
+
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<ActivityOrder> all(@RequestBody PageQuery pageQuery) {
+        return activityOrderService.all(pageQuery);
+    }
+
+    @GetMapping("/get/{id}")
+    public ActivityOrder get(@PathVariable Long id) {
+        return activityOrderRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        activityOrderRepo.softDelete(id);
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<ActivityOrder> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+
+    @PostMapping("/create")
+    public Asset create(@RequestParam Long mintActivityId) {
+        return activityOrderService.create(SecurityUtils.getAuthenticatedUser(), mintActivityId);
+    }
+}
+

+ 3 - 3
src/main/java/com/izouma/nineth/web/UserController.java

@@ -240,9 +240,9 @@ public class UserController extends BaseController {
     }
 
     @PreAuthorize("hasAnyRole('ADMIN')")
-    @GetMapping("/switchAccount")
-    public String switchAccount() {
-        userService.switchAccount();
+    @GetMapping("/checkSettleAccount")
+    public String checkSettleAccount() {
+        userService.checkSettleAccountAsync();
         return "ok";
     }
 }