liujc hai 1 ano
pai
achega
e3da318269
Modificáronse 23 ficheiros con 1401 adicións e 43 borrados
  1. 11 0
      cooleshow-common/pom.xml
  2. 5 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/constant/SysConfigConstant.java
  3. 30 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/EPayerType.java
  4. 1 0
      cooleshow-gateway/gateway-web/src/main/java/com/yonge/gateway/web/config/SwaggerDocumentConfig.java
  5. 138 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantMemberController.java
  6. 134 3
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/UserPaymentClient.java
  7. 5 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/PaymentMerchantConfig.java
  8. 198 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/TenantMember.java
  9. 35 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/TenantMemberMapper.java
  10. 0 9
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/PaymentMerchantConfigService.java
  11. 62 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/TenantMemberService.java
  12. 0 18
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/PaymentMerchantConfigServiceImpl.java
  13. 10 3
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/StudentServiceImpl.java
  14. 268 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantMemberServiceImpl.java
  15. 1 1
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserPaymentCoreServiceImpl.java
  16. 5 4
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/StudentWrapper.java
  17. 373 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/TenantMemberWrapper.java
  18. 3 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/UserPaymentOrderWrapper.java
  19. 59 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/TenantMemberMapper.xml
  20. 3 1
      cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/UserOrderController.java
  21. 24 0
      cooleshow-user/user-tenant/src/main/java/com/yonge/cooleshow/tenant/controller/StudentController.java
  22. 34 2
      cooleshow-user/user-tenant/src/main/java/com/yonge/cooleshow/tenant/controller/open/OpenStudentController.java
  23. 2 2
      cooleshow-user/user-tenant/src/main/java/com/yonge/cooleshow/tenant/vo/StudentVo.java

+ 11 - 0
cooleshow-common/pom.xml

@@ -60,5 +60,16 @@
 			<artifactId>mybatis-plus-annotation</artifactId>
 			<version>3.0.7.1</version>
 		</dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-core</artifactId>
+            <version>5.8.9</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-extra</artifactId>
+            <version>5.8.9</version>
+        </dependency>
 	</dependencies>
 </project>

+ 5 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/constant/SysConfigConstant.java

@@ -379,4 +379,9 @@ public interface SysConfigConstant {
      */
     String ICON_FANS_GROUP_DEFAULT = "icon_fans_group_default";
 
+
+    /**
+     *  子账户创建回调url
+     */
+    String SUB_ACCOUNT_CREATE_CALLBACK_URL = "sub_account_create_callback_url";
 }

+ 30 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/EPayerType.java

@@ -0,0 +1,30 @@
+package com.yonge.cooleshow.common.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+
+public enum EPayerType implements BaseEnum<String, EPayerType> {
+
+    ADAPAY("adapay"),
+    YEEPAY("yeepay"),
+    ;
+
+    @EnumValue
+    private String code;
+
+    private String desc;
+
+    EPayerType(String desc) {
+        this.code = this.name();
+        this.desc = desc;
+    }
+
+    @Override
+    public String getCode() {
+        return name();
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 1 - 0
cooleshow-gateway/gateway-web/src/main/java/com/yonge/gateway/web/config/SwaggerDocumentConfig.java

@@ -28,6 +28,7 @@ public class SwaggerDocumentConfig implements SwaggerResourcesProvider {
 		resources.add(swaggerResource("MALL_ADMIN服务", "/mall-admin-server/v2/api-docs", "2.0"));
 		resources.add(swaggerResource("MALL_PORTAL服务", "/mall-portal-server/v2/api-docs", "2.0"));
 		resources.add(swaggerResource("网络教室", "/classroom-server/v2/api-docs", "2.0"));
+		resources.add(swaggerResource("TENANT服务", "/tenant-server/v2/api-docs", "2.0"));
 		return resources;
 	}
 

+ 138 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantMemberController.java

@@ -0,0 +1,138 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.response.template.R;
+
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+import com.yonge.cooleshow.biz.dal.service.TenantMemberService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantMemberWrapper;
+import com.yonge.cooleshow.biz.dal.entity.TenantMember;
+
+import javax.validation.Valid;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+/**
+ * @Author:haonan
+ * @Date:2023/8/10 13:40
+ * @Filename:TenantMemberController
+ */
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/tenantMember")
+@Api(tags = "机构子账户表")
+public class TenantMemberController extends BaseController {
+
+    @Autowired
+    private TenantMemberService tenantMemberService;
+
+    @ApiOperation(value = "详情", notes = "机构子账户表-根据详情ID查询单条, 传入id")
+    @PreAuthorize("@pcs.hasPermissions('tenantMember/detail', {'BACKEND'})")
+    @PostMapping("/detail/{id}")
+    public R<TenantMember> detail(@PathVariable("id") Long id) {
+
+        TenantMember wrapper = tenantMemberService.detail(id);
+
+        return R.from(wrapper);
+    }
+
+    @ApiOperation(value = "查询分页", notes = "机构子账户表- 传入 TenantMemberWrapper.TenantMemberQuery")
+    @PreAuthorize("@pcs.hasPermissions('tenantMember/page', {'BACKEND'})")
+    @PostMapping("/page")
+    public HttpResponseResult<PageInfo<TenantMemberWrapper.TenantMember>> page(@RequestBody TenantMemberWrapper.TenantMemberQuery query) {
+
+        IPage<TenantMemberWrapper.TenantMember> pages = tenantMemberService.selectPage(QueryInfo.getPage(query), query);
+
+        return succeed(QueryInfo.pageInfo(pages));
+    }
+
+    @ApiOperation(value = "新增", notes = "机构子账户表- 传入 TenantMemberWrapper.InsertTenantMember")
+    @PreAuthorize("@pcs.hasPermissions('tenantMember/add', {'BACKEND'})")
+    @PostMapping("/add")
+    public HttpResponseResult add(@Valid @RequestBody TenantMemberWrapper.InsertOrUpdateTenantMember tenantMember) throws IOException {
+
+        File file = new File("/var/tmp/" + tenantMember.getMultipartFile().getOriginalFilename());
+        tenantMember.setFile(file);
+        InputStream inputStream = tenantMember.getMultipartFile().getInputStream();
+
+        try {
+            if (!file.getParentFile().exists()) {
+                file.getParentFile().mkdirs();
+            }
+            FileOutputStream fos = new FileOutputStream(file);
+            IOUtils.copy(inputStream, fos);
+            // 新增数据
+            return HttpResponseResult.succeed(tenantMemberService.add(tenantMember));
+        } catch (Exception e) {
+            return failed(e.getMessage());
+        } finally {
+            IOUtils.closeQuietly(inputStream);
+            FileUtils.deleteQuietly(file);
+        }
+    }
+
+    @ApiOperation(value = "修改", notes = "机构子账户表- 传入 TenantMemberWrapper.InsertTenantMember")
+    @PreAuthorize("@pcs.hasPermissions('tenantMember/update', {'BACKEND'})")
+    @PostMapping("/update")
+    public HttpResponseResult update(@RequestBody TenantMemberWrapper.InsertOrUpdateTenantMember tenantMember) throws IOException {
+        File file = new File("/var/tmp/" + tenantMember.getMultipartFile().getOriginalFilename());
+        tenantMember.setFile(file);
+        InputStream inputStream = tenantMember.getMultipartFile().getInputStream();
+
+        try {
+            if (!file.getParentFile().exists()) {
+                file.getParentFile().mkdirs();
+            }
+            FileOutputStream fos = new FileOutputStream(file);
+            IOUtils.copy(inputStream, fos);
+            // 新增数据
+            return HttpResponseResult.succeed(tenantMemberService.update(tenantMember));
+        } catch (Exception e) {
+            return failed(e.getMessage());
+        } finally {
+            IOUtils.closeQuietly(inputStream);
+            FileUtils.deleteQuietly(file);
+        }
+    }
+
+
+    @ApiOperation(value = "修改结算账户", notes = "机构子账户表- 传入 TenantMemberWrapper.UpdateCount")
+    @PreAuthorize("@pcs.hasPermissions('tenantMember/updateCount', {'BACKEND'})")
+    @PostMapping("/updateCount")
+    public HttpResponseResult updateCount(@RequestBody TenantMemberWrapper.UpdateCount tenantMember) {
+
+        // 更新数据
+        return HttpResponseResult.succeed(tenantMemberService.updateCount(tenantMember));
+    }
+
+
+    @ApiOperation(value = "删除", notes = "机构子账户表- 传入id")
+    @PreAuthorize("@pcs.hasPermissions('tenantMember/remove', {'BACKEND'})")
+    @PostMapping("/remove")
+    public R<Boolean> remove(@RequestParam Long id) {
+
+        return R.from(tenantMemberService.removeById(id));
+    }
+}

+ 134 - 3
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/UserPaymentClient.java

@@ -1,16 +1,24 @@
 package com.yonge.cooleshow.admin.controller.open;
 
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.huifu.adapay.core.AdapayCore;
+import com.huifu.adapay.core.util.AdapaySign;
 import com.microsvc.toolkit.common.response.template.R;
 import com.microsvc.toolkit.common.webportal.exception.BizException;
 import com.microsvc.toolkit.config.jwt.utils.JwtUserInfo;
 import com.microsvc.toolkit.middleware.payment.common.api.PaymentServiceContext;
 import com.microsvc.toolkit.middleware.payment.common.api.entity.PaymentResp;
 import com.microsvc.toolkit.middleware.payment.common.api.entity.RefundResp;
-import com.yonge.cooleshow.biz.dal.service.UserOrderService;
-import com.yonge.cooleshow.biz.dal.service.UserPaymentCoreService;
-import com.yonge.cooleshow.biz.dal.service.UserPaymentOrderService;
+import com.yeepay.g3.sdk.yop.encrypt.DigitalEnvelopeDTO;
+import com.yeepay.g3.sdk.yop.utils.DigitalEnvelopeUtils;
+import com.yeepay.g3.sdk.yop.utils.RSAKeyUtils;
+import com.yonge.cooleshow.biz.dal.entity.PaymentMerchantConfig;
+import com.yonge.cooleshow.biz.dal.entity.TenantMember;
+import com.yonge.cooleshow.biz.dal.enums.AuthStatusEnum;
+import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.wrapper.UserPaymentOrderWrapper;
+import com.yonge.cooleshow.common.enums.EPayerType;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
@@ -22,6 +30,9 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Date;
 import java.util.Objects;
 
 @Slf4j
@@ -40,6 +51,12 @@ public class UserPaymentClient {
     @Autowired
     private UserOrderService userOrderService;
 
+    @Autowired
+    private TenantMemberService tenantMemberService;
+
+    @Autowired
+    private PaymentMerchantConfigService paymentMerchantConfigService;
+
     /**
      * 支付消息回调
      * @param request HttpServletRequest
@@ -96,4 +113,118 @@ public class UserPaymentClient {
         return R.from(paymentConfig);
     }
 
+
+    @PostMapping("/callback/adapay")
+    public String callback(HttpServletRequest request) {
+        try {
+            // 验签请参data
+            String data = request.getParameter("data");
+            // 验签请参sign
+            String sign = request.getParameter("sign");
+
+            // 验签
+            if (!AdapaySign.verifySign(data, sign, AdapayCore.PUBLIC_KEY)) {
+                return "验签失败";
+            }
+
+            JSONObject dataObj = JSON.parseObject(data);
+
+            String memberId = dataObj.getString("member_id");
+
+            TenantMember tenantMember = tenantMemberService.getByMemberId(memberId, EPayerType.YEEPAY);
+            if(tenantMember == null){
+                return "账户["+ memberId +"]在系统中不存在";
+            }
+            tenantMember.setUpdateTime(new Date());
+
+            String transType = request.getParameter("type");
+
+            switch (transType) {
+
+                case "corp_member.succeeded":// 企业子账户开户成功
+                    String settleAccountId = dataObj.getString("settle_account_id");
+                    tenantMember.setSettleAccountId(settleAccountId);
+                    tenantMember.setStatus(AuthStatusEnum.PASS);
+
+                    break;
+
+                case "corp_member.failed":// 企业子账户开户失败
+                    tenantMember.setStatus(AuthStatusEnum.UNPASS);
+                    tenantMember.setMemo(dataObj.getString("audit_desc"));
+
+                    break;
+
+                case "corp_member_update.succeeded":// 更新企业用户对象成功
+                    tenantMember.setStatus(AuthStatusEnum.PASS);
+
+                    break;
+
+                case "corp_member_update.failed":// 更新企业用户对象失败
+                    tenantMember.setStatus(AuthStatusEnum.UNPASS);
+                    tenantMember.setMemo(dataObj.getString("audit_desc"));
+
+                    break;
+
+                default:
+                    break;
+            }
+
+            tenantMemberService.updateById(tenantMember);
+
+        } catch (Exception e) {
+            return e.getMessage();
+        }
+
+        return "succeeded";
+    }
+
+
+    @PostMapping("/callback/yeepay/{requestNo}")
+    public String callback(@PathVariable("requestNo") String requestNo, HttpServletRequest request) {
+
+        TenantMember tenantMember = tenantMemberService.getByRequestNo(requestNo);
+        if(tenantMember == null){
+            return "请求编号["+ requestNo +"]在系统中不存在";
+        }
+        tenantMember.setUpdateTime(new Date());
+
+        PaymentMerchantConfig paymentMerchantConfig = paymentMerchantConfigService.getByPaymentVendor(tenantMember.getPayerName());
+        if(paymentMerchantConfig == null){
+            throw new BizException("机构[{}][{}]商户信息找不到", tenantMember.getTenantId(), EPayerType.YEEPAY.getCode());
+        }
+
+        try {
+
+            String content = request.getParameter("response");
+
+            // 构造结果通知请求对象
+            DigitalEnvelopeDTO dto = new DigitalEnvelopeDTO();
+            dto.setCipherText(content);
+            PrivateKey privateKey = RSAKeyUtils.string2PrivateKey(paymentMerchantConfig.getRsaPrivateKey());
+            PublicKey publicKey = RSAKeyUtils.string2PublicKey(paymentMerchantConfig.getRsaPublicKey());
+
+            dto = DigitalEnvelopeUtils.decrypt(dto, privateKey, publicKey);
+
+            log.info("易宝支付回调信息:response:{} plaintText:{}", content, dto.getPlainText());
+
+            JSONObject dataObj = JSON.parseObject(dto.getPlainText());
+
+            if("COMPLETED".equals(dataObj.getString("applicationStatus"))) {
+                //审核成功
+                tenantMember.setStatus(AuthStatusEnum.PASS);
+                tenantMemberService.updateById(tenantMember);
+            }else if("REVIEW_BACK".equals(dataObj.getString("applicationStatus"))) {
+                //审核驳回
+                tenantMember.setStatus(AuthStatusEnum.UNPASS);
+                tenantMember.setMemo(dataObj.getString("auditOpinion"));
+                tenantMemberService.updateById(tenantMember);
+            }
+
+            return "SUCCESS";
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        return null;
+    }
 }

+ 5 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/PaymentMerchantConfig.java

@@ -38,6 +38,11 @@ public class PaymentMerchantConfig implements Serializable {
 	@TableField(value = "payer_name_")
     private String payerName;
 
+    @ApiModelProperty("平台收款商户号")
+    @TableField(value = "platform_payee_member_id_")
+    private String platformPayeeMemberId;
+
+
     @ApiModelProperty("商户ID") 
 	@TableField(value = "app_id_")
     private String appId;

+ 198 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/TenantMember.java

@@ -0,0 +1,198 @@
+package com.yonge.cooleshow.biz.dal.entity;
+
+
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.yonge.cooleshow.biz.dal.enums.AuthStatusEnum;
+import com.yonge.cooleshow.common.enums.EPayerType;
+import lombok.Data;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import java.math.BigDecimal;
+
+/**
+ * @Author:haonan
+ * @Date:2023/8/10 13:42
+ * @Filename:TenantMember
+ */
+
+
+/**
+ * 机构子账户表
+ * 2023-08-10 13:36:39
+ */
+@Data
+@ApiModel(" TenantMember-机构子账户表")
+@TableName("tenant_member")
+public class TenantMember implements Serializable {
+
+    @TableId(value = "id_")
+    private Long id;
+
+    @ApiModelProperty("支付类型 ADAPAY,YEEPAY")
+    @TableField(value = "payer_type_")
+    private EPayerType payerType;
+
+
+    @ApiModelProperty("支付渠道 ADAPAY,YEEPAY")
+    @TableField(value = "payer_name_")
+    private String payerName;
+
+    @ApiModelProperty("商户ID")
+    @TableField(value = "app_id_")
+    private String appId;
+
+    @ApiModelProperty("请求id")
+    @TableField(value = "request_no_")
+    private String requestNo;
+
+    @ApiModelProperty("机构ID")
+    @TableField(value = "tenant_id_")
+    private Long tenantId;
+
+    @ApiModelProperty("公司名称")
+    @TableField(value = "name_")
+    private String name;
+
+    @ApiModelProperty("商户号")
+    @TableField(value = "member_id_")
+    private String memberId;
+
+    @ApiModelProperty("商家类型(企业-ENTERPRISE,个体户-INDIVIDUAL)")
+    @TableField(value = "merchant_Type_")
+    private String merchantType;
+
+    @ApiModelProperty("省份编号")
+    @TableField(value = "prov_code_")
+    private String provCode;
+
+    @ApiModelProperty("城市编号")
+    @TableField(value = "area_code_")
+    private String areaCode;
+
+    @ApiModelProperty("区编号")
+    @TableField(value = "district_code_")
+    private String districtCode;
+
+    @ApiModelProperty("公司地址")
+    @TableField(value = "address_")
+    private String address;
+
+    @ApiModelProperty("统一社会信用码")
+    @TableField(value = "social_credit_code_")
+    private String socialCreditCode;
+
+    @ApiModelProperty("统一社会信用码有效期")
+    @TableField(value = "social_credit_code_expires_")
+    private String socialCreditCodeExpires;
+
+    @ApiModelProperty("经营范围")
+    @TableField(value = "business_scope_")
+    private String businessScope;
+
+    @ApiModelProperty("法人")
+    @TableField(value = "legal_person_")
+    private String legalPerson;
+
+
+    @ApiModelProperty("法人证件人像面照片 请上传带有人像面的法人证件照片")
+    @TableField(value = "legal_Licence_FrontUrl_")
+    private String legalLicenceFrontUrl;
+
+    @ApiModelProperty("法人证件非人像面照片")
+    @TableField(value = "legal_Licence_BackUrl_")
+    private String legalLicenceBackUrl;
+
+    @ApiModelProperty("法人证件类型")
+    @TableField(value = "legal_licence_type_")
+    private String legalLicenceType;
+
+    @ApiModelProperty("商户证件照片")
+    @TableField(value = "licence_Url_")
+    private String licenceUrl;
+
+    @ApiModelProperty("开户许可证照片")
+    @TableField(value = "open_Account_LicenceUrl_")
+    private String openAccountLicenceUrl;
+
+    @ApiModelProperty("法人身份证号")
+    @TableField(value = "legal_cert_id_")
+    private String legalCertId;
+
+    @ApiModelProperty("身份证有效期")
+    @TableField(value = "legal_cert_id_expires_")
+    private String legalCertIdExpires;
+
+    @ApiModelProperty("法人手机号")
+    @TableField(value = "legal_mp_")
+    private String legalMp;
+
+    @ApiModelProperty("邮编")
+    @TableField(value = "zip_code_")
+    private String zipCode;
+
+    @ApiModelProperty("企业银行卡号")
+    @TableField(value = "card_no_")
+    private String cardNo;
+
+    @ApiModelProperty("银行编码")
+    @TableField(value = "bank_code_")
+    private String bankCode;
+
+    @ApiModelProperty("结算账户id")
+    @TableField(value = "settle_account_id_")
+    private String settleAccountId;
+
+    @ApiModelProperty("备注")
+    @TableField(value = "memo_")
+    private String memo;
+
+    @ApiModelProperty("状态")
+    @TableField(value = "status_")
+    private AuthStatusEnum status;
+
+    @ApiModelProperty("每月最大收款金额,0不限制")
+    @TableField(value = "month_max_receipt_")
+    private BigDecimal monthMaxReceipt;
+
+    @ApiModelProperty("银行账户类型:1-对公;2-对私,如果需要自动开结算账户,本字段必填")
+    @TableField(value = "bank_acct_type_")
+    private String bankAcctType;
+
+    @ApiModelProperty("银行卡对应的户名,如果需要自动开结算账户,本字段必填;若银行账户类型是对公,必须与企业名称一致")
+    @TableField(value = "card_name_")
+    private String cardName;
+
+    @ApiModelProperty("联系人邮箱")
+    @TableField(value = "contact_email_")
+    private String contactEmail;
+
+    @ApiModelProperty("联系人证件号码")
+    @TableField(value = "contact_licence_no_")
+    private String contactLicenceNo;
+
+    @ApiModelProperty("联系人姓名")
+    @TableField(value = "contact_name_")
+    private String contactName;
+
+    @ApiModelProperty("联系人手机号码")
+    @TableField(value = "contact_mobile_")
+    private String contactMobile;
+
+    @ApiModelProperty("创建时间")
+    @TableField(value = "create_time_")
+    private Date createTime;
+
+    @ApiModelProperty("更新时间")
+    @TableField(value = "update_time_")
+    private Date updateTime;
+
+}

+ 35 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/TenantMemberMapper.java

@@ -0,0 +1,35 @@
+package com.yonge.cooleshow.biz.dal.mapper;
+
+
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+import com.yonge.cooleshow.biz.dal.entity.TenantMember;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantMemberWrapper;
+
+/**
+ * @Author:haonan
+ * @Date:2023/8/10 13:43
+ * @Filename:TenantMemberMapper
+ */
+
+/**
+ * 机构子账户表
+ * 2023-08-10 13:36:39
+ */
+@Repository
+public interface TenantMemberMapper extends BaseMapper<TenantMember> {
+
+    /**
+     * 分页查询
+     * @param page IPage<TenantMemberWrapper.TenantMember>
+     * @param param TenantMemberWrapper.TenantMemberQuery
+     * @return List<TenantMemberWrapper.TenantMember>
+     */
+    List<TenantMemberWrapper.TenantMember> selectPage(@Param("page") IPage<TenantMemberWrapper.TenantMember> page, @Param("param") TenantMemberWrapper.TenantMemberQuery param);
+
+}

+ 0 - 9
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/PaymentMerchantConfigService.java

@@ -40,15 +40,6 @@ public interface PaymentMerchantConfigService extends IService<PaymentMerchantCo
      */
      Boolean update(PaymentMerchantConfigWrapper.PaymentMerchantConfig paymentMerchantConfig);
 
-    /**
-     * 根据机构查询三方汇付主账户
-     *
-     * @param tenantId
-     * @return
-     */
-    PaymentMerchantConfig getByTenantId(Long tenantId);
-
-    PaymentMerchantConfig getDefault();
 
     PaymentMerchantConfig getByPaymentVendor(String paymentVendor);
 }

+ 62 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/TenantMemberService.java

@@ -0,0 +1,62 @@
+package com.yonge.cooleshow.biz.dal.service;
+
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantMemberWrapper;
+import com.yonge.cooleshow.biz.dal.entity.TenantMember;
+import com.yonge.cooleshow.common.enums.EPayerType;
+
+/**
+ * @Author:haonan
+ * @Date:2023/8/10 13:41
+ * @Filename:TenantMemberService
+ */
+
+/**
+ * 机构子账户表
+ * 2023-08-10 13:36:39
+ */
+public interface TenantMemberService extends IService<TenantMember>  {
+
+    /**
+     * 查询详情
+     * @param id 详情ID
+     * @return TenantMember
+     */
+    TenantMember detail(Long id);
+
+    /**
+     * 分页查询
+     * @param page IPage<TenantMember>
+     * @param query TenantMemberWrapper.TenantMemberQuery
+     * @return IPage<TenantMember>
+     */
+    IPage<TenantMemberWrapper.TenantMember> selectPage(IPage<TenantMemberWrapper.TenantMember> page, TenantMemberWrapper.TenantMemberQuery query);
+
+    /**
+     * 添加
+     * @param tenantMember TenantMemberWrapper.TenantMember
+     * @return Boolean
+     */
+    Boolean add(TenantMemberWrapper.InsertOrUpdateTenantMember tenantMember);
+
+    /**
+     * 更新
+     * @param tenantMember TenantMemberWrapper.TenantMember
+     * @return Boolean
+     */
+    Boolean update(TenantMemberWrapper.InsertOrUpdateTenantMember tenantMember);
+
+    /**
+     * 修改结算账户
+     * @param tenantMember
+     * @return
+     */
+    Boolean updateCount(TenantMemberWrapper.UpdateCount tenantMember);
+
+    TenantMember getByMemberId(String memberId, EPayerType payerType);
+
+    TenantMember getByRequestNo(String requestNo);
+}

+ 0 - 18
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/PaymentMerchantConfigServiceImpl.java

@@ -106,24 +106,6 @@ public class PaymentMerchantConfigServiceImpl extends ServiceImpl<PaymentMerchan
         return this.updateById(JSON.parseObject(paymentMerchantConfig.jsonString(), PaymentMerchantConfig.class));       
     }
 
-    /**
-     * 根据机构查询三方汇付主账户
-     *
-     * @param tenantId
-     * @return
-     */
-    @Override
-    public PaymentMerchantConfig getByTenantId(Long tenantId) {
-        return this.lambdaQuery()
-                .eq(PaymentMerchantConfig::getTenantId, tenantId)
-                .last("limit 1")
-                .one();
-    }
-
-    @Override
-    public PaymentMerchantConfig getDefault() {
-        return getByTenantId(-1L);
-    }
 
     @Override
     public PaymentMerchantConfig getByPaymentVendor(String paymentVendor) {

+ 10 - 3
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/StudentServiceImpl.java

@@ -392,6 +392,9 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
         }
         dataList.sort(Comparator.comparingInt(ExcelDataReaderProperty::getRowIndex));
 
+        Map<String, Long> subjectIdNamemap = subjectDao.findAll(new HashMap<>())
+                .stream().collect(Collectors.toMap(next -> next.getName(), next -> next.getId()));
+        Set<String> subjectNames = subjectIdNamemap.keySet();
         // 校验数据的完整性
         List<String> errMsg = new ArrayList<>();
         Map<String, Integer> phoneMap = new HashMap<>();
@@ -408,6 +411,10 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
                 phoneMap.put(student.getPhone().trim(), msgRowNo);
             }
 
+            if (!subjectNames.contains(student.getSubjectName())) {
+                errMsg.add(String.format("第%s行声部不支持", msgRowNo));
+            }
+
             if (errMsg.size() > 100) {
                 break;
             }
@@ -448,8 +455,8 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
             StudentWrapper.Student student = new StudentWrapper.Student();
             student.setTenantId(tenantId);
             student.setName(studentImport.getUserName());
-            student.setGender("1".equals(studentImport.getGender()) ? 1 : 0);
-            student.setSubjectId(studentImport.getSubjectId());
+            student.setGender("".equals(studentImport.getGender()) ? 1 : 0);
+            student.setSubjectId(subjectIdNamemap.get(studentImport.getSubjectName()).toString());
 
             LocalDate birthday = LocalDate.parse(studentImport.getBirthday(), DateTimeFormatter.ISO_LOCAL_DATE);
             student.setBirthdate(birthday);
@@ -493,8 +500,8 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
 //            imUserFriendService.delFriendByTenantId(student.getTenantId(), student.getUserId());
 //        }
         // 手机号码修改
-        com.yonge.cooleshow.biz.dal.entity.SysUser sysUser = getOrCreateAccount(studentInfo);
         if (!student.getPhone().equals(studentInfo.getPhone())) {
+            com.yonge.cooleshow.biz.dal.entity.SysUser sysUser = getOrCreateAccount(studentInfo);
             this.lambdaUpdate().set(Student::getSubjectId, studentInfo.getSubjectId())
                     .set(Student::getTenantId, studentInfo.getTenantId())
                     .set(Student::getUserId, sysUser.getId())

+ 268 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantMemberServiceImpl.java

@@ -0,0 +1,268 @@
+package com.yonge.cooleshow.biz.dal.service.impl;
+
+
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import com.baomidou.mybatisplus.extension.service.additional.update.impl.LambdaUpdateChainWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.microsvc.toolkit.middleware.payment.common.api.BasePaymentService;
+import com.microsvc.toolkit.middleware.payment.common.api.PaymentServiceContext;
+import com.microsvc.toolkit.middleware.payment.common.api.entity.PaymentMerchant;
+import com.yonge.cooleshow.biz.dal.entity.PaymentMerchantConfig;
+import com.yonge.cooleshow.biz.dal.entity.SysArea;
+import com.yonge.cooleshow.biz.dal.mapper.SysAreaMapper;
+import com.yonge.cooleshow.biz.dal.service.PaymentMerchantConfigService;
+import com.yonge.cooleshow.biz.dal.service.SysConfigService;
+import com.yonge.cooleshow.biz.dal.service.TenantInfoService;
+import com.yonge.cooleshow.common.constant.SysConfigConstant;
+import com.yonge.cooleshow.common.enums.EPayerType;
+import com.yonge.toolset.base.exception.BizException;
+import com.yonge.toolset.base.util.StringUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import lombok.extern.slf4j.Slf4j;
+import com.yonge.cooleshow.biz.dal.entity.TenantMember;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantMemberWrapper;
+import com.yonge.cooleshow.biz.dal.mapper.TenantMemberMapper;
+import com.yonge.cooleshow.biz.dal.service.TenantMemberService;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+/**
+ * @Author:haonan
+ * @Date:2023/8/10 13:41
+ * @Filename:TenantMemberServiceImpl
+ */
+
+
+
+/**
+ * 机构子账户表
+ * 2023-08-10 13:36:39
+ */
+@Slf4j
+@Service
+public class TenantMemberServiceImpl extends ServiceImpl<TenantMemberMapper, TenantMember> implements TenantMemberService {
+
+    @Autowired
+    private SysAreaMapper sysAreaMapper;
+
+    @Autowired
+    private PaymentServiceContext paymentServiceContext;
+
+    @Autowired
+    private PaymentMerchantConfigService paymentMerchantConfigService;
+
+    @Autowired
+    private SysConfigService sysConfigService;
+
+    /**
+     * 查询详情
+     * @param id 详情ID
+     * @return TenantMember
+     */
+    @Override
+    public TenantMember detail(Long id) {
+
+        return baseMapper.selectById(id);
+    }
+
+    /**
+     * 分页查询
+     * @param page IPage<TenantMember>
+     * @param query TenantMemberWrapper.TenantMemberQuery
+     * @return IPage<TenantMember>
+     */
+    @Override
+    public IPage<TenantMemberWrapper.TenantMember> selectPage(IPage<TenantMemberWrapper.TenantMember> page, TenantMemberWrapper.TenantMemberQuery query) {
+        List<TenantMemberWrapper.TenantMember> tenantMembers = baseMapper.selectPage(page, query);
+        if (tenantMembers.isEmpty()) {
+            return page.setRecords(tenantMembers);
+        }
+        //设置省市中文名称
+        List<Integer> areaCodeList = tenantMembers.stream().map(next -> {
+            HashSet<Integer> areaCodes = new HashSet<>();
+            areaCodes.add(Integer.valueOf(next.getProvCode()));
+            areaCodes.add(Integer.valueOf(next.getAreaCode()));
+            areaCodes.add(Integer.valueOf(next.getDistrictCode()));
+            return areaCodes;
+        }).flatMap(Collection::stream).filter(Objects::nonNull).distinct().collect(Collectors.toList());
+        if (!areaCodeList.isEmpty()) {
+            QueryWrapper<SysArea> queryWrapper = new QueryWrapper<>();
+            queryWrapper.lambda().in(SysArea::getCode, areaCodeList);
+
+            Map<Integer, String> codeNameMap = sysAreaMapper.selectList(queryWrapper)
+                    .stream().collect(Collectors.toMap(SysArea::getCode, SysArea::getName));
+
+            tenantMembers.forEach(next -> {
+                next.setProvName(codeNameMap.getOrDefault(Integer.valueOf(next.getProvCode()), ""));
+                next.setAreaName(codeNameMap.getOrDefault(Integer.valueOf(next.getAreaCode()), ""));
+                next.setDistrictName(codeNameMap.getOrDefault(Integer.valueOf(next.getDistrictCode()), ""));
+            });
+        }
+        return page.setRecords(tenantMembers);
+    }
+
+    /**
+     * 添加
+     * @param tenantMember TenantMemberWrapper.TenantMember
+     * @return Boolean
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean add(TenantMemberWrapper.InsertOrUpdateTenantMember tenantMember) {
+
+        PaymentMerchant.MerchantConfig merchantConfig = getMerchantConfig(tenantMember.getPayerName());
+        tenantMember.setRequestNo(IdWorker.getIdStr());
+
+        // 创建账户
+        BasePaymentService paymentService = paymentServiceContext.getPaymentService(tenantMember.getPayerName());
+
+        PaymentMerchant.MerchantMember merchantMember = getMerchantMember(tenantMember);
+        paymentService.createPaymentCorpMember(merchantConfig,merchantMember);
+
+        return this.save(JSON.parseObject(tenantMember.jsonString(), TenantMember.class));
+    }
+
+    private PaymentMerchant.MerchantMember getMerchantMember(TenantMemberWrapper.InsertOrUpdateTenantMember tenantMember) {
+        PaymentMerchant.MerchantMember merchantMember = PaymentMerchant.MerchantMember.builder()
+                .memberId(tenantMember.getMemberId())
+                .merchantName(tenantMember.getName())
+                .merchantType(tenantMember.getMerchantType())
+                .provinceCode(tenantMember.getProvCode())
+                .cityCode(tenantMember.getAreaCode())
+                .districtCode(tenantMember.getDistrictCode())
+                .socialCreditCode(tenantMember.getSocialCreditCode())
+                .socialCreditCodeExpires(tenantMember.getSocialCreditCodeExpires())
+                .businessScope(tenantMember.getBusinessScope())
+                .legalName(tenantMember.getLegalPerson())
+                .legalLicenceNo(tenantMember.getLegalCertId())
+                .legalCertIdExpires(tenantMember.getLegalCertIdExpires())
+                .mobile(tenantMember.getLegalMp())
+                .legalLicenceType(tenantMember.getLegalLicenceType())
+                .legalLicenceFrontUrl(tenantMember.getLegalLicenceFrontUrl())
+                .legalLicenceBackUrl(tenantMember.getLegalLicenceBackUrl())
+                .address(tenantMember.getAddress())
+                .attachFile(tenantMember.getFile())
+                .bankCode(tenantMember.getBankCode())
+                .bankAccountType(tenantMember.getBankAcctType())
+                .bankCardNo(tenantMember.getBankCode())
+                .cardName(tenantMember.getCardName())
+                .zipCode(tenantMember.getZipCode())
+                .requestNo(tenantMember.getRequestNo())
+                .licenceNo(tenantMember.getSocialCreditCode())
+                .licenceUrl(tenantMember.getLicenceUrl())
+                .openAccountLicenceUrl(tenantMember.getOpenAccountLicenceUrl())
+                .contactName(tenantMember.getContactName())
+                .contactMobile(tenantMember.getContactMobile())
+                .contactEmail(tenantMember.getContactEmail())
+                .contactLicenceNo(tenantMember.getContactLicenceNo())
+                .primaryIndustryCategory("120")
+                .secondaryIndustryCategory("120004")
+                .settlementDirection("BANKCARD")
+                .build();
+        if (tenantMember.getPayerType().equals(EPayerType.ADAPAY)) {
+            merchantMember.setNotifyUrl(sysConfigService.findConfigValue(SysConfigConstant.SUB_ACCOUNT_CREATE_CALLBACK_URL +
+                    "/" + EPayerType.ADAPAY.getCode()));
+        } else if (tenantMember.getPayerType().equals(EPayerType.YEEPAY)) {
+            merchantMember.setNotifyUrl(sysConfigService.findConfigValue(SysConfigConstant.SUB_ACCOUNT_CREATE_CALLBACK_URL +
+                    "/" + EPayerType.YEEPAY.getCode()+"/"+tenantMember.getRequestNo()));
+        }
+        return merchantMember;
+
+    }
+
+    private PaymentMerchant.MerchantConfig getMerchantConfig(String paymentVerdor) {
+        // 注册对应的子账户
+        PaymentMerchantConfig merchantConfig = paymentMerchantConfigService.getByPaymentVendor(paymentVerdor);
+
+        if (merchantConfig == null) {
+            throw new BizException("支付渠道不存在");
+        }
+
+        return PaymentMerchant.MerchantConfig.builder()
+                .payerName(paymentVerdor)
+                .appId(merchantConfig.getAppId())
+                .merchantKey(merchantConfig.getMerKey())
+                .apiKey(merchantConfig.getApiKey())
+                .rsaPrivateKey(merchantConfig.getRsaPrivateKey())
+                .rsaPublicKey(merchantConfig.getRsaPublicKey())
+                .wxAppId(merchantConfig.getWxAppId())
+                .wxAppSecret(merchantConfig.getWxAppSecret())
+                .alipayAppId(merchantConfig.getAlipayAppId())
+                .alipayPublicKey(merchantConfig.getAlipayPublicKey())
+                .platformPayeeMemberId(merchantConfig.getPlatformPayeeMemberId())
+                .build();
+    }
+
+    /**
+     * 更新
+     * @param tenantMember TenantMemberWrapper.TenantMember
+     * @return Boolean
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean update(TenantMemberWrapper.InsertOrUpdateTenantMember tenantMember){
+
+        TenantMember member = this.getById(tenantMember.getId());
+
+        PaymentMerchant.MerchantConfig merchantConfig = getMerchantConfig(tenantMember.getPayerName());
+
+        // 创建账户
+        BasePaymentService paymentService = paymentServiceContext.getPaymentService(tenantMember.getPayerName());
+
+        PaymentMerchant.MerchantMember merchantMember = getMerchantMember(tenantMember);
+
+        if (member.getPayerName().equals(tenantMember.getPayerName())) {
+            paymentService.updatePaymentCorpMember(merchantConfig, merchantMember);
+        } else {
+            paymentService.createPaymentCorpMember(merchantConfig, merchantMember);
+        }
+
+        return this.updateById(JSON.parseObject(tenantMember.jsonString(), TenantMember.class));
+    }
+
+    /**
+     * 修改结算账户
+     * @param tenantMember
+     * @return
+     */
+    @Override
+    public Boolean updateCount(TenantMemberWrapper.UpdateCount tenantMember) {
+
+        if (!StringUtil.isEmpty(tenantMember)){
+            LambdaUpdateChainWrapper<TenantMember> wrapper = this.lambdaUpdate()
+                    .set(TenantMember::getCardNo, tenantMember.getCardNo())
+                    .set(TenantMember::getBankCode, tenantMember.getBankCode())
+                    .eq(TenantMember::getId, tenantMember.getId());
+
+            wrapper.update();
+            return true;
+        }
+         return false;
+    }
+
+    @Override
+    public TenantMember getByMemberId(String memberId, EPayerType payerType) {
+        return this.lambdaQuery()
+                .eq(TenantMember::getMemberId, memberId)
+                .eq(TenantMember::getPayerName, payerType.name())
+                .last("limit 1")
+                .one();
+    }
+
+    @Override
+    public TenantMember getByRequestNo(String requestNo) {
+        return this.lambdaQuery()
+                .eq(TenantMember::getRequestNo, requestNo)
+                .last("limit 1")
+                .one();
+    }
+
+}

+ 1 - 1
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserPaymentCoreServiceImpl.java

@@ -1008,7 +1008,7 @@ public class UserPaymentCoreServiceImpl implements UserPaymentCoreService {
         }
         
         // 结算给机构的,检测机构的主账户,没有主账户的,查询-1的主账户
-        PaymentMerchantConfig merchantConfig = paymentMerchantConfigService.getByTenantId(-1L);
+        PaymentMerchantConfig merchantConfig = paymentMerchantConfigService.getByPaymentVendor(paymentServiceContext.getProperties().getDefaultService());
         if (Objects.isNull(merchantConfig)) {
             throw new BizException("平台主账户信息不存在");
         }

+ 5 - 4
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/StudentWrapper.java

@@ -137,7 +137,7 @@ public class StudentWrapper {
         private String phone;
 
         @ExcelProperty(value = "声部")
-        private String subjectId;
+        private String subjectName;
 
         @ExcelProperty(value = "出生日期")
         private String birthday;
@@ -145,8 +145,7 @@ public class StudentWrapper {
         @ExcelProperty(value = "性别")
         private String gender;
 
-        private static final String PHONE_REG = "^(13\\d|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18\\d|19[0-35-9])" +
-                "\\d{8}$";
+        private static final String PHONE_REG = "^1\\d{10}$";
 
         private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");
 
@@ -160,7 +159,7 @@ public class StudentWrapper {
             } else if (!Pattern.matches(PHONE_REG, phone)) {
                 errMsg.add("手机号格式错误");
             }
-            if (StringUtils.isEmpty(subjectId)) {
+            if (StringUtils.isEmpty(subjectName)) {
                 errMsg.add("声部为空");
             }
             if (StringUtils.isEmpty(birthday)) {
@@ -177,6 +176,8 @@ public class StudentWrapper {
             }
             if (StringUtils.isEmpty(gender)) {
                 errMsg.add("性别为空");
+            } else if (!"男".equals(gender) && !"女".equals(gender)) {
+                errMsg.add("性别错误");
             }
             return errMsg;
         }

+ 373 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/TenantMemberWrapper.java

@@ -0,0 +1,373 @@
+package com.yonge.cooleshow.biz.dal.wrapper;
+
+
+import com.alibaba.fastjson.JSON;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.biz.dal.enums.AuthStatusEnum;
+import com.yonge.cooleshow.common.enums.EPayerType;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.File;
+import java.math.BigDecimal;
+import java.util.Date;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @Author:haonan
+ * @Date:2023/8/10 13:45
+ * @Filename:TenantMemberWrapper
+ */
+
+/**
+ * 机构子账户表
+ * 2023-08-10 13:36:39
+ */
+@ApiModel(value = "TenantMemberWrapper对象", description = "机构子账户表查询对象")
+public class TenantMemberWrapper {
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel(" TenantMemberQuery-机构子账户表")
+    public static class TenantMemberQuery implements QueryInfo {
+
+        @ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        @ApiModelProperty("商户号")
+        private String memberId;
+
+        @ApiModelProperty("公司名称")
+        private String name;
+
+
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static TenantMemberQuery from(String json) {
+            return JSON.parseObject(json, TenantMemberQuery.class);
+        }
+    }
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel(" TenantMember-机构子账户表")
+    public static class TenantMember {
+
+        private Long id;
+
+        @ApiModelProperty("支付渠道 ADAPAY,YEEPAY")
+        private String payerName;
+
+        @ApiModelProperty("商户ID")
+        private String appId;
+
+        @ApiModelProperty("请求id")
+        private String requestNo;
+
+        @ApiModelProperty("机构ID")
+        private Long tenantId;
+
+        @ApiModelProperty("公司名称")
+        private String name;
+
+        @ApiModelProperty("商户号")
+        private String memberId;
+
+        @ApiModelProperty("商家类型(企业-ENTERPRISE,个体户-INDIVIDUAL)")
+        private String merchantType;
+
+        @ApiModelProperty("省份编号")
+        private String provCode;
+
+        @ApiModelProperty("省份名称")
+        private String provName;
+
+        @ApiModelProperty("城市编号")
+        private String areaCode;
+
+        @ApiModelProperty("城市名称")
+        private String areaName;
+
+        @ApiModelProperty("区编号")
+        private String districtCode;
+
+        @ApiModelProperty("区名称")
+        private String districtName;
+
+        @ApiModelProperty("公司地址")
+        private String address;
+
+        @ApiModelProperty("统一社会信用码")
+        private String socialCreditCode;
+
+        @ApiModelProperty("统一社会信用码有效期")
+        private String socialCreditCodeExpires;
+
+        @ApiModelProperty("经营范围")
+        private String businessScope;
+
+        @ApiModelProperty("法人")
+        private String legalPerson;
+
+
+        @ApiModelProperty("证照文件")
+        private String multipartFile;
+
+
+        @ApiModelProperty("法人证件人像面照片 请上传带有人像面的法人证件照片")
+        private String legalLicenceFrontUrl;
+
+        @ApiModelProperty("法人证件非人像面照片")
+        private String legalLicenceBackUrl;
+
+        @ApiModelProperty("法人证件类型")
+        private String legalLicenceType;
+
+        @ApiModelProperty("商户证件照片")
+        private String licenceUrl;
+
+        @ApiModelProperty("开户许可证照片")
+        private String openAccountLicenceUrl;
+
+        @ApiModelProperty("法人身份证号")
+        private String legalCertId;
+
+        @ApiModelProperty("身份证有效期")
+        private String legalCertIdExpires;
+
+        @ApiModelProperty("法人手机号")
+        private String legalMp;
+
+        @ApiModelProperty("邮编")
+        private String zipCode;
+
+        @ApiModelProperty("企业银行卡号")
+        private String cardNo;
+
+        @ApiModelProperty("银行编码")
+        private String bankCode;
+
+        @ApiModelProperty("结算账户id")
+        private String settleAccountId;
+
+        @ApiModelProperty("备注")
+        private String memo;
+
+        @ApiModelProperty("状态 DOING 审核中 PASS 审核通过 UNPASS 审核拒绝")
+        private AuthStatusEnum status;
+
+        @ApiModelProperty("每月最大收款金额,0不限制")
+        private BigDecimal monthMaxReceipt;
+
+        @ApiModelProperty("银行账户类型:1-对公;2-对私,如果需要自动开结算账户,本字段必填")
+        private String bankAcctType;
+
+        @ApiModelProperty("银行卡对应的户名,如果需要自动开结算账户,本字段必填;若银行账户类型是对公,必须与企业名称一致")
+        private String cardName;
+
+        @ApiModelProperty("联系人邮箱")
+        private String contactEmail;
+
+        @ApiModelProperty("联系人证件号码")
+        private String contactLicenceNo;
+
+        @ApiModelProperty("联系人姓名")
+        private String contactName;
+
+        @ApiModelProperty("联系人手机号码")
+        private String contactMobile;
+
+        @ApiModelProperty("创建时间")
+        private Date createTime;
+
+        @ApiModelProperty("更新时间")
+        private Date updateTime;
+
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static TenantMember from(String json) {
+            return JSON.parseObject(json, TenantMember.class);
+        }
+    }
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel(" TenantMember-机构子账户表新增/修改数据")
+    public static class InsertOrUpdateTenantMember {
+        private Long id;
+
+        @ApiModelProperty("机构ID")
+        @NotNull(message = "机构ID不能为空")
+        private Long tenantId;
+
+
+
+        @ApiModelProperty("支付类型 ADAPAY,YEEPAY")
+        private EPayerType payerType;
+
+        @NotNull(message = "支付渠道不能为空")
+        @ApiModelProperty("支付渠道 ADAPAY,YEEPAY")
+        private String payerName;
+
+        @ApiModelProperty("请求id")
+        private String requestNo;
+
+        @ApiModelProperty("商户号")
+        @NotNull(message = "商户号不能为空")
+        private String memberId;
+
+        @ApiModelProperty("公司名称")
+        @NotNull(message = "公司名称不能为空")
+        private String name;
+
+        @ApiModelProperty("统一社会信用码")
+        private String socialCreditCode;
+
+        @ApiModelProperty("统一社会信用码有效期")
+        private String socialCreditCodeExpires;
+
+        @ApiModelProperty("法人")
+        private String legalPerson;
+
+        @ApiModelProperty("证照文件")
+        private MultipartFile multipartFile;
+
+        @ApiModelProperty(hidden = true)
+        private File file;
+
+        @ApiModelProperty("法人手机号")
+        private String legalMp;
+
+        @ApiModelProperty("法人身份证号")
+        private String legalCertId;
+
+        @ApiModelProperty("身份证有效期")
+        private String legalCertIdExpires;
+
+        @ApiModelProperty("经营范围")
+        private String businessScope;
+
+        @ApiModelProperty("公司地址")
+        private String address;
+
+        @ApiModelProperty("法人证件类型")
+        private String legalLicenceType;
+
+        @ApiModelProperty("邮编")
+        private String zipCode;
+
+        @ApiModelProperty("企业银行卡号")
+        private String cardNo;
+
+        @ApiModelProperty("银行编码")
+        private String bankCode;
+
+        @ApiModelProperty("银行账户类型:1-对公;2-对私,如果需要自动开结算账户,本字段必填")
+        private String bankAcctType;
+
+        @ApiModelProperty("银行卡对应的户名,如果需要自动开结算账户,本字段必填;若银行账户类型是对公,必须与企业名称一致")
+        private String cardName;
+
+        @ApiModelProperty("省份编号")
+        private String provCode;
+
+        @ApiModelProperty("省份名称")
+        private String provName;
+
+        @ApiModelProperty("城市编号")
+        private String areaCode;
+
+        @ApiModelProperty("城市名称")
+        private String areaName;
+
+        @ApiModelProperty("区编号")
+        private String districtCode;
+
+        @ApiModelProperty("商家类型(企业-ENTERPRISE,个体户-INDIVIDUAL)")
+        private String merchantType;
+
+        @ApiModelProperty("商户证件照片")
+        private String licenceUrl;
+
+        @ApiModelProperty("开户许可证照片")
+        private String openAccountLicenceUrl;
+
+
+        @ApiModelProperty("法人证件人像面照片 请上传带有人像面的法人证件照片")
+        private String legalLicenceFrontUrl;
+
+        @ApiModelProperty("法人证件非人像面照片")
+        private String legalLicenceBackUrl;
+
+        @ApiModelProperty("联系人姓名")
+        private String contactName;
+
+        @ApiModelProperty("联系人证件号码")
+        private String contactLicenceNo;
+
+
+        @ApiModelProperty("联系人手机号码")
+        private String contactMobile;
+
+        @ApiModelProperty("联系人邮箱")
+        private String contactEmail;
+
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static TenantMember from(String json) {
+            return JSON.parseObject(json, TenantMember.class);
+        }
+    }
+
+
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel(" TenantMember-机构子账户表修改银行信息")
+    public static class UpdateCount {
+        private Long id;
+
+        @ApiModelProperty("企业银行卡号")
+        private String cardNo;
+
+        @ApiModelProperty("银行编码")
+        private String bankCode;
+
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static TenantMember from(String json) {
+            return JSON.parseObject(json, TenantMember.class);
+        }
+    }
+
+}

+ 3 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/UserPaymentOrderWrapper.java

@@ -575,6 +575,9 @@ public class UserPaymentOrderWrapper {
         @ApiModelProperty("支付用户类型")
         private ClientEnum userType;
 
+        @ApiModelProperty(value = "请求ip", hidden = true)
+        private String ip;
+
         public String jsonString() {
             return JSON.toJSONString(this);
         }

+ 59 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/TenantMemberMapper.xml

@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE  mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.yonge.cooleshow.biz.dal.mapper.TenantMemberMapper">
+
+
+
+    <!-- 表字段 -->
+    <sql id="baseColumns">
+        t.id_ AS id
+        , t.payer_name_ AS payerName
+        , t.app_id_ AS appId
+        , t.request_no_ AS requestNo
+        , t.tenant_id_ AS tenantId
+        , t.name_ AS name
+        , t.member_id_ AS memberId
+        , t.prov_code_ AS provCode
+        , t.area_code_ AS areaCode
+        , t.district_code_ AS districtCode
+        , t.address_ AS address
+        , t.social_credit_code_ AS socialCreditCode
+        , t.social_credit_code_expires_ AS socialCreditCodeExpires
+        , t.business_scope_ AS businessScope
+        , t.legal_person_ AS legalPerson
+        , t.legal_licence_type_ AS legalLicenceType
+        , t.legal_cert_id_ AS legalCertId
+        , t.legal_cert_id_expires_ AS legalCertIdExpires
+        , t.legal_mp_ AS legalMp
+        , t.zip_code_ AS zipCode
+        , t.card_no_ AS cardNo
+        , t.bank_code_ AS bankCode
+        , t.settle_account_id_ AS settleAccountId
+        , t.memo_ AS memo
+        , t.status_ AS status
+        , t.month_max_receipt_ AS monthMaxReceipt
+        , t.bank_acct_type_ AS bankAcctType
+        , t.card_name_ AS cardName
+        , t.contact_email_ AS contactEmail
+        , t.contact_licence_no_ AS contactLicenceNo
+        , t.contact_name_ AS contactName
+        , t.contact_mobile_ AS contactMobile
+        , t.create_time_ AS createTime
+        , t.update_time_ AS updateTime
+    </sql>
+
+    <select id="selectPage" resultType="com.yonge.cooleshow.biz.dal.wrapper.TenantMemberWrapper$TenantMember">
+        SELECT
+        <include refid="baseColumns" />
+        FROM tenant_member t
+        <where>
+            <if test="param.memberId != null and param.memberId != ''">
+                and t.member_id_ = #{param.memberId}
+            </if>
+            <if test="param.name != null and param.name != ''">
+                and t.name_ = #{param.name}
+            </if>
+        </where>
+    </select>
+
+</mapper>

+ 3 - 1
cooleshow-user/user-student/src/main/java/com/yonge/cooleshow/student/controller/UserOrderController.java

@@ -1,5 +1,6 @@
 package com.yonge.cooleshow.student.controller;
 
+import cn.hutool.extra.servlet.ServletUtil;
 import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.microsvc.toolkit.common.response.template.R;
@@ -304,7 +305,7 @@ public class UserOrderController extends BaseController {
 
     @ApiOperation(value = "用户付款", notes = "用户付款")
     @PostMapping("/orderPay/v2")
-    public R<UserPaymentOrderWrapper.PaymentReq> executePaymentV2(@Validated @RequestBody UserPaymentOrderVo.PaymentReqConfig config) {
+    public R<UserPaymentOrderWrapper.PaymentReq> executePaymentV2(@Validated @RequestBody UserPaymentOrderVo.PaymentReqConfig config,HttpServletRequest request) {
         // 设置下单用户信息
         SysUser sysUser = sysUserFeignService.queryUserInfo();
         if (Objects.isNull(sysUser)) {
@@ -315,6 +316,7 @@ public class UserOrderController extends BaseController {
         // 用户下单请求
         UserPaymentOrderWrapper.PaymentOrderReqConfig reqConfig = UserPaymentOrderWrapper.PaymentOrderReqConfig.from(config.jsonString());
 
+        reqConfig.setIp(ServletUtil.getClientIP(request));
         // 创建用户支付数据
         UserPaymentOrderWrapper.PaymentReq paymentConfig = userPaymentCoreService.executePayment(JwtUserInfo.builder()
                 .userId(sysUser.getId().toString()).clientType(ClientEnum.STUDENT.getCode()).build(), reqConfig);

+ 24 - 0
cooleshow-user/user-tenant/src/main/java/com/yonge/cooleshow/tenant/controller/StudentController.java

@@ -116,6 +116,30 @@ public class StudentController extends BaseController {
         StudentWrapper.Student studentInfo = JSON.parseObject(JSON.toJSONString(student), StudentWrapper.Student.class);
         TenantInfo tenantInfo = getTenantInfo();
         studentInfo.setTenantId(tenantInfo.getId());
+
+        Long studentId = student.getId();
+
+        if (studentId == null) {
+            SysUser sysUser = sysUserFeignService.queryUserByMobile(student.getPhone());
+            if (sysUser != null) {
+                studentId = sysUser.getId();
+            }
+        }
+
+        if (studentId != null) {
+            Student one = studentService.lambdaQuery()
+                    .eq(Student::getUserId, studentId)
+                    .eq(Student::getHideFlag, 0)
+                    .last("limit 1").one();
+            if (one != null) {
+                if (one.getTenantId().equals(-1L)) {
+                    throw new BizException("该手机号已经注册为平台学生");
+                } else if (!one.getTenantId().equals(tenantInfo.getId())) {
+                    throw new BizException("该手机号已经注册为其他平台学生");
+                }
+            }
+        }
+
         studentService.save(studentInfo);
         return succeed();
     }

+ 34 - 2
cooleshow-user/user-tenant/src/main/java/com/yonge/cooleshow/tenant/controller/open/OpenStudentController.java

@@ -1,6 +1,9 @@
 package com.yonge.cooleshow.tenant.controller.open;
 
 import com.alibaba.fastjson.JSON;
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.entity.Student;
 import com.yonge.cooleshow.biz.dal.entity.TenantInfo;
 import com.yonge.cooleshow.biz.dal.service.StudentService;
 import com.yonge.cooleshow.biz.dal.service.TenantInfoService;
@@ -18,6 +21,8 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
+
 @RestController
 @RequestMapping("/open/student")
 @Api(value = "学生表", tags = "学生表")
@@ -28,8 +33,11 @@ public class OpenStudentController extends BaseController {
     @Autowired
     private TenantInfoService tenantInfoService;
 
+    @Resource
+    private SysUserFeignService sysUserFeignService;
+
     @PostMapping("/save")
-    @ApiOperation(value = "新增/修改", notes = "传入Student")
+    @ApiOperation(value = "新增/修改", notes = "传入Student,换绑时按照返回错误码5004判断,是否需要换绑,updateTenant=true表示换绑")
     public HttpResponseResult<Boolean> save(@Validated @RequestBody StudentVo.Student student) {
         Long tenantId = student.getTenantId();
         if (tenantId == null) {
@@ -39,7 +47,31 @@ public class OpenStudentController extends BaseController {
         if (tenantInfo == null) {
             throw new BizException("机构不存在");
         }
-        student.setId(null);
+        Long studentId = student.getId();
+
+        if (studentId == null) {
+            SysUser sysUser = sysUserFeignService.queryUserByMobile(student.getPhone());
+            if (sysUser != null) {
+                studentId = sysUser.getId();
+            }
+        }
+
+        if (studentId != null) {
+            Student one = studentService.lambdaQuery()
+                    .eq(Student::getUserId, studentId)
+                    .eq(Student::getHideFlag, 0)
+                    .last("limit 1").one();
+            if (one != null) {
+                if (one.getTenantId().equals(-1L)) {
+                    throw new BizException("该手机号已经注册为平台学生");
+                } else if (!one.getTenantId().equals(tenantId) && !student.getUpdateTenant()) {
+                    throw new BizException(5004, "该手机号已经注册为其他平台学生");
+                }
+            }
+            student.setId(studentId);
+        }
+
+
         StudentWrapper.Student studentInfo = JSON.parseObject(JSON.toJSONString(student), StudentWrapper.Student.class);
         studentInfo.setTenantId(tenantInfo.getId());
         studentService.save(studentInfo);

+ 2 - 2
cooleshow-user/user-tenant/src/main/java/com/yonge/cooleshow/tenant/vo/StudentVo.java

@@ -42,7 +42,7 @@ public class StudentVo {
         @ApiModelProperty("声部,多个用逗号隔开")
         private String subjectId;
 
-        @ApiModelProperty("是否解绑")
-        private Boolean bindTenant;
+        @ApiModelProperty("是否换绑机构,开放接口使用参数")
+        private Boolean updateTenant;
     }
 }