Merge remote-tracking branch 'origin/develop' into develop

# Conflicts:
#	Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-dev.yml
#	Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-prod.yml
#	Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-test.yml
This commit is contained in:
yxz 2024-01-23 09:34:00 +08:00
commit 6ce6022d63
111 changed files with 4529 additions and 472 deletions

View File

@ -14,7 +14,7 @@ public interface CloudDbUrl {
/**
* 课卡相关云函数
*/
String COMMON_CARD_URL = BASE_URL + "/merchant_cloud";
String COMMON_USE_URL = BASE_URL + "/merchant_cloud";
/**
* 查询云数据专用

View File

@ -3,8 +3,6 @@ package com.cpop.api.cloudDb.core.dto;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import java.time.OffsetDateTime;
/**
* @author DB
* @version 1.0.0
@ -101,4 +99,75 @@ public class CloudClassCardDto {
@SerializedName("isDrainage")
private boolean isDrainageCard;
/**
* 实收金额
*/
@SerializedName("money")
private String payAmount;
/**
* 云校区id
*/
@SerializedName("storeId")
private String storeCloudId;
/**
* 客户手机号
*/
@SerializedName("phone")
private String customerPhone;
/**
* 模板id
*/
@SerializedName("templateId")
private String orderCloudId;
/**
* 订单来源
*/
private String orderSource;
/**
* 子商户
*/
private String subMchId;
/**
* 模板路径
*/
private String templateUrl;
/**
* 客户openid
*/
@SerializedName("openid")
private String openId;
/**
* 商户侧签约计划号
*/
private String merchantSignPlanNo;
/**
* 签约计划id
*/
private String signPlanId;
/**
* 计划id
*/
private String planId;
/**
* 每期课次
*/
private String classHour;
/**
* 签约计划详情,json格式
*/
@SerializedName("signedDetailList")
private String signPlanDetails;
}

View File

@ -123,11 +123,11 @@ public class CloudCourseStudentDto {
* 扣除课卡名
*/
@SerializedName("periodName")
private String cardName;
private String deductionCardName;
/**
* 状态操作时间
*/
@SerializedName("_createTime")
private String createTime;
private String entryTime;
}

View File

@ -0,0 +1,51 @@
package com.cpop.api.cloudDb.core.dto;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-15 11:18
*/
@Data
@Accessors(chain = true)
public class CloudStoreDto {
/**
* 云校区id
*/
@SerializedName("storeId")
private String storeCloudId;
/**
* 云品牌id
*/
@SerializedName("brandId")
private String brandCloudId;
/**
* 云校区名
*/
@SerializedName("name")
private String storeName;
/**
* 负责人
*/
@SerializedName("principalName")
private String personCharge;
/**
* 手机号
*/
private String phone;
/**
* 云校区id
*/
@SerializedName("address")
private String storeAddr;
}

View File

@ -4,9 +4,9 @@ import com.alibaba.fastjson.JSONObject;
import com.cpop.api.cloudDb.core.constant.CloudDbUrl;
import com.cpop.api.cloudDb.core.dto.CloudClassCardDto;
import com.cpop.api.cloudDb.core.dto.CloudClassCardRecordDto;
import com.cpop.api.cloudDb.core.dto.CloudClassStudentDto;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.entity.ExtendPage;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.exception.UtilException;
import com.mybatisflex.core.paginate.Page;
import org.springframework.beans.factory.annotation.Autowired;
@ -139,4 +139,46 @@ public class CloudClassCardHandler {
return page;
}
}
/**
* 添加课卡
* @author DB
* @since 2024/1/20
* @param dto 课卡中间表
* @return String
*/
public String insertCloudClassCard(CloudClassCardDto dto){
JSONObject jsonBody = JSONObject.parseObject(JSONObject.toJSONString(dto));
jsonBody.put("_type", "addPeriod");
JSONObject result = restTemplate.postForObject(CloudDbUrl.COMMON_USE_URL, jsonBody, JSONObject.class);
if (result != null) {
if (result.getBoolean("success")) {
return result.getString("data");
} else {
throw new UtilException(result.getString("error"));
}
} else {
throw new ServiceException("办卡失败!");
}
}
/**
* 通知退款退卡
* @author DB
* @since 2024/1/22
* @param dto 请求参数
*/
public void refundCloudClassCard(CloudClassCardDto dto){
JSONObject jsonBody = JSONObject.parseObject(JSONObject.toJSONString(dto));
jsonBody.put("_type", "periodRefund");
JSONObject result = restTemplate.postForObject(CloudDbUrl.COMMON_USE_URL, jsonBody, JSONObject.class);
if (result != null) {
if (!result.getBoolean("success")) {
throw new UtilException(result.getString("error"));
}
} else {
throw new ServiceException("操作失败!");
}
}
}

View File

@ -0,0 +1,18 @@
package com.cpop.api.cloudDb.handler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
/**
* 数据导入
* @author DB
* @version 1.0.0
* @since 2024-01-14 11:38
*/
@Component
public class CloudDataImportHandler {
@Autowired
private RestTemplate restTemplate;
}

View File

@ -0,0 +1,57 @@
package com.cpop.api.cloudDb.handler;
import com.alibaba.fastjson.JSONObject;
import com.cpop.api.cloudDb.core.constant.CloudDbUrl;
import com.cpop.api.cloudDb.core.dto.CloudStoreDto;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.exception.UtilException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
/**
* 云校区工具类
* @author DB
* @version 1.0.0
* @since 2024-01-15 11:16
*/
@Component
public class CloudStoreHandler {
@Autowired
private RestTemplate restTemplate;
/**
* 更新校区
* @author DB
* @since 2024/1/15
* @param dto 入参
*/
public void updateStore(CloudStoreDto dto) {
JSONObject jsonBody = new JSONObject();
jsonBody.put("_type", "storeEdit");
//云校区id
jsonBody.put("storeId", dto.getStoreCloudId());
if (StringUtils.isNotBlank(dto.getBrandCloudId())) {
jsonBody.put("brandId", dto.getBrandCloudId());
}
if (StringUtils.isNotBlank(dto.getStoreName())) {
jsonBody.put("name", dto.getStoreName());
}
if (StringUtils.isNotBlank(dto.getPersonCharge())) {
jsonBody.put("principalName", dto.getPersonCharge());
}
if (StringUtils.isNotBlank(dto.getPhone())) {
jsonBody.put("phone", dto.getPhone());
}
if (StringUtils.isNotBlank(dto.getStoreAddr())) {
jsonBody.put("address", dto.getStoreAddr());
}
JSONObject jsonObject = restTemplate.postForObject(CloudDbUrl.COMMON_USE_URL, jsonBody, JSONObject.class);
if (jsonObject != null) {
if (!jsonObject.getBoolean("success")) {
throw new UtilException(jsonObject.getString("error"));
}
}
}
}

View File

@ -0,0 +1,15 @@
package com.cpop.core.annontation;
import java.lang.annotation.*;
/**
* @author: DB
* @Date: 2023/08/08/9:49
* @Description: 自定义签名校验
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SignatureCheck {
}

View File

@ -0,0 +1,15 @@
package com.cpop.core.annontation;
import java.lang.annotation.*;
/**
* 简易校验签名
* @author DB
* @version 1.0.0
* @since 2024-01-16 10:31
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SimpleSignatureCheck {
}

View File

@ -0,0 +1,148 @@
package com.cpop.core.aspect;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.R;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.exception.UtilException;
import com.cpop.core.utils.RsaUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Key;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 自定义前面校验
* @author DB
* @version 1.0.0
* @since 2024-01-16 10:01
*/
@Aspect
@Component
@Slf4j
public class SignatureCheckAspect {
@Autowired
private RsaUtils rsaUtils;
private static final Map<String, String[]> APP_IDS = new HashMap<String, String[]>() {{
//数币
put("1688842965582499840", new String[]{"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmsFHkB4iIdVSgaz8u8QG66wiZupgSbu2T/ml/kdPm2vemsKgvEqUqp1gR6ulfHcPF8otjVbjiE8q8oR70XfxFIREbomTUmpsOzurLFrAmVhyvu6/tY23/txjQoeeH/tlCy7Lq/TL1AqPKyBcGzsQ4yInpIgRWpXz7fmJCTRw07tyE+4lpXBqiaLdWrkkGG00LnHQAOfcUoXf0TdxFPSfRHiBikfbkmgeVoU66RGlUEXU2esTY2nYGvFn+FqWsNkGEnn2YxIqgbQQ1zNX33+FWBlba1WdQtc8mTJAleaPGXmFnQiEMb55b7xVPjyyCWt6aRwl97KQgtCmfsoPZUWwQQIDAQAB", "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCawUeQHiIh1VKBrPy7xAbrrCJm6mBJu7ZP+aX+R0+ba96awqC8SpSqnWBHq6V8dw8Xyi2NVuOITyryhHvRd/EUhERuiZNSamw7O6ssWsCZWHK+7r+1jbf+3GNCh54f+2ULLsur9MvUCo8rIFwbOxDjIiekiBFalfPt+YkJNHDTu3IT7iWlcGqJot1auSQYbTQucdAA59xShd/RN3EU9J9EeIGKR9uSaB5WhTrpEaVQRdTZ6xNjadga8Wf4Wpaw2QYSefZjEiqBtBDXM1fff4VYGVtrVZ1C1zyZMkCV5o8ZeYWdCIQxvnlvvFU+PLIJa3ppHCX3spCC0KZ+yg9lRbBBAgMBAAECggEAdstPp+25vccHYsvr5icAOQEWF3JrH66csJ+vMJaFIYWYh6xHvsJxhNbyBZJZokWyrExi01CTsRs0mJ3iflVYFqvB7ChnkqhnFMElERNJLW2cB702JKP5TgbXm0aHt30/f2oYppNvtAG3DR/2FGEvAWxCiiZ5S9Q4P8GB1DMROTZBpYQgVlN9vOxqgcy8SsJyruy0xsEP3RIKko9UQ7Y9y/b6TbNOJDx/ZpC9KcOUmI8Or73IMdG1ZucumzHNO3dS2XKL7qeTQ8AWMwwAk2ZsCRx9g05QLiW3+7ZrpmOMwI3wCeJOoxhUQKijCXI3B8Rh1cU++CMk4LdyPOe78PYEEQKBgQDnyOL69Ck6+xe1EJ2HAEDPla5ujCexv6ctYvSernhI6OsMVCWa1D5rCqzC4L0IvRW7/m5lUSWlSzpfIGhSGc+PNyIaYsyYMbaIV5e8LKRp8SxUDrTA4IfYmxoXdYyq2l0PSkBPKMJ2ZyWlRoGGEC432IsiY+GBaznvHwIYFvkYHwKBgQCq7DkJYT6du/bQ2uoZv6hYYIGTY4A9TzjJ0Kp5O00BUz5zNpgBUfb1SmuISHwGyN1hOWFntR0uwfj/BUDvtG0b07k1Xz+4UWXsDqtS6eEnvUR6q/i2yWWGjCMS74t61FZopV6AxHneJV2S6Tt26MFK0VbrCwXaiYg/3tMYgC2rnwKBgF0kfRIby/XHsV8xrhvyHhlNLSt/ZvQm8Cds/KBHvE6QSuRJbFMrt2mMgKBPb6dzVKiXNgXA9j/WWz6e500W0jHbFflEerMuRwvDJ1aXGfr4z7d3sWtQz0ZcDcAfnMeLuJnMXMtytbKfAKHKE4KsPeZzPnYzbQt063MMIutLUA5BAoGBAIduFONxwgOJY8+pJcSxL9qW3RTDymDJ3N1MEUdtzV43b0wq/dZN87f396xMgrl9fqwCo0NhJnZeC8VFjGZiN/HMmPvJNNv+4xtfpDBWUKkENrZcfP2YJnGtqDzgwUvZ432XSoINK+LxCGvXkd5uHnoB1TT3zvOR9ftluy22onlRAoGBAKkIZmwW/2H/86ILrCDyARK4obULB4op8IyrunZ+lH14DksxbL7fmTsSbLyRX7oD/QvGJIuc0EDkgONztsAn5vrETv8Z6RqyKdoZZI3sAQWIBc0om6nH2zqJDIs+mep96DOg/jJAcgiVhyIoFP91IvHY7pvKwy5MTttdZLvvS2XB"});
}};
@Pointcut("@annotation(com.cpop.core.annontation.SignatureCheck)")
public void signatureCheck() {}
/**
* 前置通知
* @author DB
* @since 2024/1/16
* @param joinPoint 切入点
*/
@Before(value = "signatureCheck()")
public void beforePointcut(JoinPoint joinPoint) throws IllegalAccessException {
//获取RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
//从获取RequestAttributes中获取HttpServletRequest的信息
assert requestAttributes != null;
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
assert request != null;
Object object = joinPoint.getArgs()[0];
//验签拼接字段
List<String> signString = new ArrayList<String>();
//获取父类公共类必传属性
Field[] fatherFields = object.getClass().getSuperclass().getDeclaredFields();
String signature = null;
String appId = null;
for (Field field : fatherFields) {
field.setAccessible(true);
if (StringUtils.equals("signature", field.getName())) {
signature = (String) field.get(object);
continue;
}
if (StringUtils.equals("appId", field.getName())) {
String[] strings = APP_IDS.get((String) field.get(object));
if (null == strings){
throw new ServiceException("appId匹配失败,请核实appId");
}
appId = strings[0];
}
signString.add(field.getName() + "=" + field.get(object));
}
if (null == signature){
throw new ServiceException("签名不存在,请核实签名");
//return ResultDTO.fail("签名不存在,请核实签名");
}
//可能为空参
Field[] fields = object.getClass().getDeclaredFields();
if (fields.length > 0) {
for (Field field : fields) {
field.setAccessible(true);
if(null == field.get(object)){
signString.add(field.getName() + "=");
} else {
signString.add(field.getName() + "=" + field.get(object));
}
}
}
//按照字母排序
String sign = signString.stream().sorted().collect(Collectors.joining("&")) + appId;
String md5DigestAsHex = DigestUtils.md5DigestAsHex(sign.getBytes());
if (!StringUtils.equals(md5DigestAsHex,signature)){
throw new ServiceException("签名匹配失败,请核实签名");
}
}
/**
* 环绕通知,不做处理
* @author DB
* @since 2024/1/16
* @param joinPoint 请求
* @return Object
*/
@Around("signatureCheck()")
public Object aroundPointcut(ProceedingJoinPoint joinPoint) throws Throwable {
return joinPoint.proceed(joinPoint.getArgs());
}
/**
* 异常通知目标方法发生异常的时候执行以下代码此时返回通知不会再触发
* value 属性绑定通知的切入点表达式可以关联切入点声明也可以直接设置切入点表达式
* pointcut 属性绑定通知的切入点表达式优先级高于 value默认为 ""
* throwing 属性与方法中的异常参数名称一致
*
* @param ex捕获的异常对象名称与 throwing 属性值一致
*/
@AfterThrowing(pointcut = "signatureCheck()", throwing = "ex")
public Object aspectAfterThrowing(JoinPoint jp, Exception ex) {
String methodName = jp.getSignature().getName();
if (ex instanceof ServiceException) {
log.error("【异常通知】" + methodName + "方法算术异常ArithmeticException" + ex.getMessage());
return R.fail(ex.getMessage());
} else {
log.error("【异常通知】" + methodName + "方法异常:" + ex.getMessage());
return R.fail("签名不合法");
}
}
}

View File

@ -0,0 +1,138 @@
package com.cpop.core.aspect;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.R;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.exception.UtilException;
import com.cpop.core.utils.RsaUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.HashMap;
import java.util.Map;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-16 10:31
*/
@Aspect
@Component
@Slf4j
public class SimpleSignatureCheckAspect {
@Autowired
private RsaUtils rsaUtils;
private static final Map<String, String[]> APP_IDS = new HashMap<String, String[]>() {{
//果酱内部
put("1747095325571944448", new String[]{"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkPn6JRxgY3/cxyeEQ3xETlI6tcsq4d2GGrgD2pnQ8Db2vaSCEu3k4cV92/HjmoggA09A7cepurO6xeFwya9C8c1YD4UHJQ13MPlKIskDmoc/ZUyklVQKVp60pvi/BpuhECt6LksHu9Yz2ECUBiFXDd2Pgju41Oiu6joIJylWdbUkhTesOs/XnPCUjWw2kQzhpcmoMZwlgneuvGXO72OhI2FD5QTHA00UbnbtzM3hk9cQNRxak+sNzKkv4AOZy5uTjHXVdYcUUwDc7XbuWN/E40tzbyWmoZSuXPt80vOk+KgCEOK+sfPy6YPgxAYh4NOk59qA4x1ZaYSJsLRNo1c/OwIDAQAB",
"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCQ+folHGBjf9zHJ4RDfEROUjq1yyrh3YYauAPamdDwNva9pIIS7eThxX3b8eOaiCADT0Dtx6m6s7rF4XDJr0LxzVgPhQclDXcw+UoiyQOahz9lTKSVVApWnrSm+L8Gm6EQK3ouSwe71jPYQJQGIVcN3Y+CO7jU6K7qOggnKVZ1tSSFN6w6z9ec8JSNbDaRDOGlyagxnCWCd668Zc7vY6EjYUPlBMcDTRRudu3MzeGT1xA1HFqT6w3MqS/gA5nLm5OMddV1hxRTANztdu5Y38TjS3NvJaahlK5c+3zS86T4qAIQ4r6x8/Lpg+DEBiHg06Tn2oDjHVlphImwtE2jVz87AgMBAAECggEABg36jWw29lDTtpmG446gB6lVfFwkyVQIEruWpZ2A5VdWTKs/J205/tfRnsrmV4DR3XGE46lQBFUXOsZkgHfKUvDheZxzpO+AB9KRbwx4Ew8M7b0aroXY/K8aGlMPH0aGnndCXgaSJx0WAzUHOY5Q5WpYYPb/jBy/mVadGo2WZ8n9cMQQSVwdVFxsGOHckPQePyK41fsjQ6A7pNiW3ErK5TCQ18gimLAbjBeUDj5NKfe8P6o65uETkRBPE+ZL6O95hueqj7FU/8LtBFVXCFmpYLDa0BBRxZCgJP94lnS/GIo2qYkVMJh4fThWh6ZxvscggaWmVPGqhP2zzSDQup+A+QKBgQDtKD5ZdG5KeDC9jMn3HQGYAf8aiNVx0KNxpCn19uRrclNgaEFPPLj/6yWeclqPOAqzk4AGQ+MaMEQzTmHOP7O411jIgX2Ki2D9OilZjr+kObdGoekWGzZKPm38EqP+Z9oAJxNGDBkUe1iH/DUoLGgp1mt19cZn1pPgdR9vsmZwxQKBgQCcfskmHrt3NltXrOzwV3PWwelsA+E+DVn3N9N9+V8ETs0pIxFAg6LuDVxVQziLe2wApp3dy8b/efxnRUYmiFDBUxKf9CQJcZTDncHO/wASObEHlUqcIkBM9Vcy8EMovKSNrNnJHcvNV7zQaRHZshft2rPKnUaIMb0M3H6GokHv/wKBgBc4lopJxTbTd+pHa8sfcvWAVIszlLq1NBu/eEBWMV1370QEUUjB6FdenetaxRU65olYyvNSGF2LFlJzvU3lnOJfa5kOXM2BAjkpRb04JfmdkR2AYwNAHNu+KyTAaoBRiN309YUpUBdaUHvYLRhG6NgX36PIMeoe75HNxgs4y6EFAoGAcvyNm97U68Ea2I8NAYOgb9nHQ0COjeONiSKR2WwTrryf7mv/zyFp4/QZNeTQdVxYfRnvwPpr22esV80EwGdEvuflNXZTzESShDE0KH4hdULCmsnNKm/YQzO5wIndLt99IUQyOZ4VE2o2KAQrw4MiJfieRm/NVWEGgZ65sP8j580CgYEA2iNWW8jkLQhyPwOG4EztXmoTlCJUcwCmgjnL4dlRzAhsCooY+saXG0Q4GlRTJtpgXNM7kFGgAPjBSk57u6xh5I0/Tet8SWagNC2zLTcP2Bk1y2HtjWG+mSHAGEcth6etgnZgrU5daIVRJyTfslYX0i7x6o5EnCzJV0ftIBYstZ4="});
//数币
put("1688842965582499840", new String[]{"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmsFHkB4iIdVSgaz8u8QG66wiZupgSbu2T/ml/kdPm2vemsKgvEqUqp1gR6ulfHcPF8otjVbjiE8q8oR70XfxFIREbomTUmpsOzurLFrAmVhyvu6/tY23/txjQoeeH/tlCy7Lq/TL1AqPKyBcGzsQ4yInpIgRWpXz7fmJCTRw07tyE+4lpXBqiaLdWrkkGG00LnHQAOfcUoXf0TdxFPSfRHiBikfbkmgeVoU66RGlUEXU2esTY2nYGvFn+FqWsNkGEnn2YxIqgbQQ1zNX33+FWBlba1WdQtc8mTJAleaPGXmFnQiEMb55b7xVPjyyCWt6aRwl97KQgtCmfsoPZUWwQQIDAQAB", "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCawUeQHiIh1VKBrPy7xAbrrCJm6mBJu7ZP+aX+R0+ba96awqC8SpSqnWBHq6V8dw8Xyi2NVuOITyryhHvRd/EUhERuiZNSamw7O6ssWsCZWHK+7r+1jbf+3GNCh54f+2ULLsur9MvUCo8rIFwbOxDjIiekiBFalfPt+YkJNHDTu3IT7iWlcGqJot1auSQYbTQucdAA59xShd/RN3EU9J9EeIGKR9uSaB5WhTrpEaVQRdTZ6xNjadga8Wf4Wpaw2QYSefZjEiqBtBDXM1fff4VYGVtrVZ1C1zyZMkCV5o8ZeYWdCIQxvnlvvFU+PLIJa3ppHCX3spCC0KZ+yg9lRbBBAgMBAAECggEAdstPp+25vccHYsvr5icAOQEWF3JrH66csJ+vMJaFIYWYh6xHvsJxhNbyBZJZokWyrExi01CTsRs0mJ3iflVYFqvB7ChnkqhnFMElERNJLW2cB702JKP5TgbXm0aHt30/f2oYppNvtAG3DR/2FGEvAWxCiiZ5S9Q4P8GB1DMROTZBpYQgVlN9vOxqgcy8SsJyruy0xsEP3RIKko9UQ7Y9y/b6TbNOJDx/ZpC9KcOUmI8Or73IMdG1ZucumzHNO3dS2XKL7qeTQ8AWMwwAk2ZsCRx9g05QLiW3+7ZrpmOMwI3wCeJOoxhUQKijCXI3B8Rh1cU++CMk4LdyPOe78PYEEQKBgQDnyOL69Ck6+xe1EJ2HAEDPla5ujCexv6ctYvSernhI6OsMVCWa1D5rCqzC4L0IvRW7/m5lUSWlSzpfIGhSGc+PNyIaYsyYMbaIV5e8LKRp8SxUDrTA4IfYmxoXdYyq2l0PSkBPKMJ2ZyWlRoGGEC432IsiY+GBaznvHwIYFvkYHwKBgQCq7DkJYT6du/bQ2uoZv6hYYIGTY4A9TzjJ0Kp5O00BUz5zNpgBUfb1SmuISHwGyN1hOWFntR0uwfj/BUDvtG0b07k1Xz+4UWXsDqtS6eEnvUR6q/i2yWWGjCMS74t61FZopV6AxHneJV2S6Tt26MFK0VbrCwXaiYg/3tMYgC2rnwKBgF0kfRIby/XHsV8xrhvyHhlNLSt/ZvQm8Cds/KBHvE6QSuRJbFMrt2mMgKBPb6dzVKiXNgXA9j/WWz6e500W0jHbFflEerMuRwvDJ1aXGfr4z7d3sWtQz0ZcDcAfnMeLuJnMXMtytbKfAKHKE4KsPeZzPnYzbQt063MMIutLUA5BAoGBAIduFONxwgOJY8+pJcSxL9qW3RTDymDJ3N1MEUdtzV43b0wq/dZN87f396xMgrl9fqwCo0NhJnZeC8VFjGZiN/HMmPvJNNv+4xtfpDBWUKkENrZcfP2YJnGtqDzgwUvZ432XSoINK+LxCGvXkd5uHnoB1TT3zvOR9ftluy22onlRAoGBAKkIZmwW/2H/86ILrCDyARK4obULB4op8IyrunZ+lH14DksxbL7fmTsSbLyRX7oD/QvGJIuc0EDkgONztsAn5vrETv8Z6RqyKdoZZI3sAQWIBc0om6nH2zqJDIs+mep96DOg/jJAcgiVhyIoFP91IvHY7pvKwy5MTttdZLvvS2XB"});
}};
@Pointcut("@annotation(com.cpop.core.annontation.SimpleSignatureCheck)")
public void simpleSignatureCheck() {}
/**
* 前置通知
* @author DB
* @since 2024/1/16
*/
@Before(value = "simpleSignatureCheck()")
public void beforePointcut() {
//获取RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
//从获取RequestAttributes中获取HttpServletRequest的信息
assert requestAttributes != null;
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
assert request != null;
String signature = request.getHeader("signature");
if (StringUtils.isBlank(signature)){
throw new ServiceException("签名为空,请核实签名");
}
String appId = request.getHeader("appId");
if (StringUtils.isBlank(appId)){
throw new ServiceException("appId为空,请核实签名");
}
String dateTime = request.getHeader("dateTime");
if (StringUtils.isBlank(dateTime)){
throw new ServiceException("时间为空,请核实签名");
}
String decrypt = rsaUtils.decrypt(signature, stringToKey(APP_IDS.get(appId)[1]));
String sign = appId + dateTime;
String md5DigestAsHex = DigestUtils.md5DigestAsHex(sign.getBytes());
if (!StringUtils.equals(md5DigestAsHex, decrypt)) {
throw new ServiceException("签名匹配失败,请核实签名");
}
}
/**
* 环绕通知,不做处理
* @author DB
* @since 2024/1/16
* @param joinPoint 请求
* @return Object
*/
@Around("simpleSignatureCheck()")
public Object aroundPointcut(ProceedingJoinPoint joinPoint) throws Throwable {
return joinPoint.proceed(joinPoint.getArgs());
}
/**
* 异常通知目标方法发生异常的时候执行以下代码此时返回通知不会再触发
* value 属性绑定通知的切入点表达式可以关联切入点声明也可以直接设置切入点表达式
* pointcut 属性绑定通知的切入点表达式优先级高于 value默认为 ""
* throwing 属性与方法中的异常参数名称一致
*
* @param ex捕获的异常对象名称与 throwing 属性值一致
*/
@AfterThrowing(pointcut = "simpleSignatureCheck()", throwing = "ex")
public Object aspectAfterThrowing(JoinPoint jp, Exception ex) {
String methodName = jp.getSignature().getName();
if (ex instanceof ServiceException) {
log.error("【异常通知】" + methodName + "方法算术异常ArithmeticException" + ex.getMessage());
return R.fail(ex.getMessage());
} else {
log.error("【异常通知】" + methodName + "方法异常:" + ex.getMessage());
return R.fail("签名不合法");
}
}
private Key stringToKey(String stringKey) {
byte[] bytes = stringKey.getBytes(StandardCharsets.UTF_8);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
Key key = null;
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(bais);
key = (Key) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new UtilException(e.getMessage());
} finally {
try {
assert ois != null;
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return key;
}
}

View File

@ -0,0 +1,33 @@
package com.cpop.core.base.entity;
import lombok.Data;
/**
* 普普签名基础类
* @author DB
* @version 1.0.0
* @since 2024-01-16 10:09
*/
@Data
public class CpopSignBase {
/**
* 签名
*/
private String signature;
/**
* appId
*/
private String appId;
/**
* 时间yyyyMMddHHmmss
*/
private String dateTime;
/**
* 签名类型
*/
private String signType;
}

View File

@ -14,9 +14,15 @@ public enum OrderSource {
MALL("Mall",0.002),
/**
* 微信支付
* 一次性支付
*/
EASY_LEARN("EasyLearn",0.002);
EASY_LEARN("EasyLearn",0.002),
/**
* 先学后付
*/
LEARN_NOW_PAY_LATER("LearnNowPayLater",0.06)
;
OrderSource(String name, Double rate) {
this.rate = rate;

View File

@ -86,14 +86,18 @@ public class RsaUtils {
* 将密钥对生成到文件中
*/
private void generateKeyPairToFiles() {
generateKeyPairToFiles(keyPairConfig.getPublicKeyFile(),keyPairConfig.getPrivateKeyFile());
}
private void generateKeyPairToFiles(String publicKeyFile, String privateKeyFile) {
ObjectOutputStream oosPublicKey = null;
ObjectOutputStream oosPrivateKey = null;
try {
Map<String, Key> keyPairMap = generateKeyPair();
Key publicKey = keyPairMap.get("publicKey");
Key privateKey = keyPairMap.get("privateKey");
oosPublicKey = new ObjectOutputStream(Files.newOutputStream(Paths.get(keyPairConfig.getPublicKeyFile())));
oosPrivateKey = new ObjectOutputStream(Files.newOutputStream(Paths.get(keyPairConfig.getPrivateKeyFile())));
oosPublicKey = new ObjectOutputStream(Files.newOutputStream(Paths.get(publicKeyFile)));
oosPrivateKey = new ObjectOutputStream(Files.newOutputStream(Paths.get(privateKeyFile)));
oosPublicKey.writeObject(publicKey);
oosPrivateKey.writeObject(privateKey);
} catch (NoSuchAlgorithmException | IOException e) {
@ -111,25 +115,31 @@ public class RsaUtils {
}
}
/**
* 初始化密钥对文件
* @return 返回密钥对信息publicKey公钥字符串privateKey私钥字符串
*/
public Map<String, String> initKeyPair() {
return initKeyPair(keyPairConfig.getPublicKeyFile(),keyPairConfig.getPrivateKeyFile());
}
public Map<String, String> initKeyPair(String publicKeyFile, String privateKeyFile){
Map<String, String> keyPairMap = new HashMap<>();
File publicFile = new File(keyPairConfig.getPublicKeyFile());
File privateFile = new File(keyPairConfig.getPrivateKeyFile());
File publicFile = new File(publicKeyFile);
File privateFile = new File(privateKeyFile);
//判断是否存在公钥和私钥文件
if (!publicFile.exists() || !privateFile.exists()) {
generateKeyPairToFiles();
generateKeyPairToFiles(publicKeyFile, privateKeyFile);
}
ObjectInputStream oisPublic = null;
ObjectInputStream oisPrivate = null;
Key publicKey = null;
Key privateKey = null;
try {
oisPublic = new ObjectInputStream(Files.newInputStream(Paths.get(keyPairConfig.getPublicKeyFile())));
oisPrivate = new ObjectInputStream(Files.newInputStream(Paths.get(keyPairConfig.getPrivateKeyFile())));
oisPublic = new ObjectInputStream(Files.newInputStream(Paths.get(publicKeyFile)));
oisPrivate = new ObjectInputStream(Files.newInputStream(Paths.get(privateKeyFile)));
publicKey = (Key) oisPublic.readObject();
privateKey = (Key) oisPrivate.readObject();
byte[] publicKeyBytes = publicKey.getEncoded();
@ -183,7 +193,28 @@ public class RsaUtils {
* @return 解密后的字符串
*/
public String decrypt(String source) {
Key privateKey = getKeyFromFile(keyPairConfig.getPrivateKeyFile());
return decrypt(source,keyPairConfig.getPrivateKeyFile());
}
public String decrypt(String source, String privateKeyFile) {
Key privateKey = getKeyFromFile(privateKeyFile);
Base64.Decoder decoder = Base64.getDecoder();
String decryptSource = null;
try {
//得到Cipher对象对已用公钥加密的数据进行RSA解密
Cipher cipher = Cipher.getInstance(keyPairConfig.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
//执行解密操作
byte[] bytes = decoder.decode(source);
decryptSource = new String(cipher.doFinal(bytes), StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException |
IllegalBlockSizeException | BadPaddingException e) {
throw new UtilException(e.getMessage());
}
return decryptSource;
}
public String decrypt(String source, Key privateKey) {
Base64.Decoder decoder = Base64.getDecoder();
String decryptSource = null;
try {

View File

@ -295,6 +295,9 @@
<if test="password != null and password != ''">
password = #{password},
</if>
<if test="rsaPassword != null and rsaPassword != ''">
rsa_password = #{rsaPassword},
</if>
<if test="nickName != null and nickName != ''">
nick_name = #{nickName},
</if>

View File

@ -40,17 +40,17 @@ public class CpopGenerator {
/**
* 输出路径
*/
private static final String EXPORT_URL = "/Cpop-Oam";
private static final String EXPORT_URL = "/Cpop-Jambox";
/**
* 模块
*/
private static final String EXPORT_ITEM = "oam";
private static final String EXPORT_ITEM = "jambox";
/**
* 表前缀
*/
private static final String TABLE_PREFIX = "cp_oam_";
private static final String TABLE_PREFIX = "cp_j_";
/**
* 主入口

View File

@ -28,6 +28,11 @@
<groupId>com.cpop</groupId>
<artifactId>Cpop-Pay</artifactId>
</dependency>
<!--微信小程序-->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-miniapp</artifactId>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,154 @@
package com.cpop.jambox.business.bo;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-16 16:29
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "CardTemplateUnionBo对象", description = "课卡模板统一入口")
public class CardTemplateUnionBo {
/**
* 主键
*/
@ApiModelProperty(value = "主键")
private String id;
/**
* 旧课卡模板id
*/
@ApiModelProperty(value = "旧课卡模板id")
private String oldTemplateId;
/**
* 云品牌id
*/
@ApiModelProperty(value = "云品牌id")
private String brandCloudId;
/**
* 云校区id
*/
@ApiModelProperty(value = "云校区id")
private String storeCloudId;
/**
* 模板名
*/
@NotBlank(message = "模板名不能为空")
@ApiModelProperty(value = "模板名",required = true)
private String name;
/**
* 有效日期数
*/
@ApiModelProperty(value = "有效日期数")
private Integer validDay;
/**
* 结束日期
*/
@ApiModelProperty(value = "结束日期")
private LocalDate endDate;
/**
* 价格
*/
@NotNull(message = "价格不能为空")
@ApiModelProperty(value = "价格")
private BigDecimal price;
/**
* 课时
*/
@ApiModelProperty("课时")
private Integer classNumber;
/**
* 周预约数
*/
@ApiModelProperty(value = "周预约数")
private Integer weekAppointment;
/**
* 日预约数
*/
@ApiModelProperty(value = "日预约数")
private Integer dayAppointment;
/**
* 缓冲天数
*/
@ApiModelProperty(value = "缓冲天数")
private Integer bufferDay;
/**
* 模板类型(0:课时卡,1:时限卡,2:储值卡)
*/
@ApiModelProperty(value = "模板类型(0:课时卡,1:时限卡,2:储值卡)")
private Integer templateType;
/**
* 使用范围
*/
@ApiModelProperty(value = "使用范围(旧Type字段)")
private String scopeUse;
/**
* 支付类型(0:微信支付;1:先学后付次付;2:旧放心学合约支付;3:数字人民币支付;4:线下支付;5:先学后付月付;)
*/
@NotEmpty(message = "支付类型不能为空")
@ApiModelProperty(value = "支付类型(0:微信支付;1:先学后付次付;2:旧放心学合约支付;3:数字人民币支付;4:线下支付;5:先学后付月付;)")
private List<Integer> payType;
/**
* 是否是会员(0否1是)
*/
@ApiModelProperty(value = "是否是会员(0否1是)")
private Boolean isMember;
/**
* 是否是引流卡
*/
@ApiModelProperty(value = "是否是引流卡(0否1是)")
private Boolean isDrainage;
/**
* 先学后付支付
*/
@ApiModelProperty("先学后付支付(次付)")
private LearnNowPayLaterPlanBo learnNowPayLaterPay;
/**
* 先学后付支付
*/
@ApiModelProperty("先学后付(月付)")
private LearnNowPayLaterPlanBo learnNowPayLaterMonthPay;
/**
* 放心学旧合同
*/
@ApiModelProperty("放心学旧合同")
private EasyLearnOldContractBo easyLearnOldContract;
/**
* 放心学数币
*/
@ApiModelProperty("放心学数币")
private EasyLearnDigitalCurrencyBo easyLearnDigitalCurrency;
}

View File

@ -0,0 +1,31 @@
package com.cpop.jambox.business.bo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-19 9:44
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "EasyLearnDigitalCurrencyBo对象", description = "放心学数币参数")
public class EasyLearnDigitalCurrencyBo {
/**
* 是否是数币活动
*/
private Boolean isActivity;
/**
* 活动码
*/
private String activityCode;
/**
* 活动描述
*/
private String activityDesc;
}

View File

@ -0,0 +1,37 @@
package com.cpop.jambox.business.bo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-19 9:36
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "EasyLearnOldContractBo对象", description = "放心学旧合同参数")
public class EasyLearnOldContractBo {
/**
* 期数
*/
@ApiModelProperty("期数")
private Integer stageNum;
/**
* 押金
*/
@ApiModelProperty("押金")
private BigDecimal deposit;
/**
* 首期缓冲天数
*/
@ApiModelProperty("首期缓冲天数")
private Integer firstBufferDay;
}

View File

@ -41,8 +41,8 @@ public class LearnNowPayLaterPlanBo {
@ApiModelProperty("支付分计划原总金额")
private Integer totalOriginalPrice;
public void setDeductionQuantity(BigDecimal deductionQuantity) {
this.deductionQuantity = deductionQuantity.scaleByPowerOfTen(2).intValue();
public void setTotalOriginalPrice(BigDecimal totalOriginalPrice) {
this.totalOriginalPrice = totalOriginalPrice.scaleByPowerOfTen(2).intValue();
}
/**
@ -51,8 +51,8 @@ public class LearnNowPayLaterPlanBo {
@ApiModelProperty("支付分计划实际扣费总金额(单位分)")
private Integer totalActualPrice;
public void setTotalOriginalPrice(BigDecimal totalOriginalPrice) {
this.totalOriginalPrice = totalOriginalPrice.scaleByPowerOfTen(2).intValue();
public void setTotalActualPrice(BigDecimal totalActualPrice) {
this.totalActualPrice = totalActualPrice.scaleByPowerOfTen(2).intValue();
}
/**
@ -61,4 +61,10 @@ public class LearnNowPayLaterPlanBo {
@ApiModelProperty("支付分计划明细列表")
private List<LearnNowPayLaterPlanDetailBo> planDetailList;
/**
* 课次
*/
@ApiModelProperty("支付分计划原总金额")
private String classHour;
}

View File

@ -0,0 +1,61 @@
package com.cpop.jambox.business.bo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-20 12:33
*/
@Data
@ApiModel(value = "先学后付用户核销")
public class LearnNowPayLaterServiceOrderBo {
/**
* 支付分订单在商户侧的订单号必须和创建签约计划时传入的该笔订单对应的商户侧计划明细使用订单号(merchant\_plan\_detail\_no)一致
*/
@NotBlank(message = "待创建服务订单对应的用户的签约计划不能为空")
@ApiModelProperty(value = "待创建服务订单对应的用户的签约计划",required = true)
private String signPlanId;
/**
* 待创建服务订单对应的用户的签约计划详情序号
*/
@NotNull(message = "planDetailNo不能为空")
@ApiModelProperty(value = "待创建服务订单对应的用户的签约计划详情序号",required = true)
private Integer planDetailNo;
/**
* 服务商公众号下的用户标识
*/
@NotBlank(message = "openid不能为空")
@ApiModelProperty(value = "服务商公众号下的用户标识",required = true)
private String openid;
/**
* 卡号
*/
@NotBlank(message = "cardNo不能为空")
@ApiModelProperty(value = "卡号",required = true)
private String cardNo;
/**
* 课程信息
*/
@NotBlank(message = "课程信息不能为空")
@ApiModelProperty(value = "课程信息",required = true)
private String serviceIntroduction;
/**
* 核销金额
*/
@NotNull(message = "核销金额不能为空")
@ApiModelProperty(value = "核销金额",required = true)
private Integer price;
}

View File

@ -0,0 +1,31 @@
package com.cpop.jambox.business.bo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-20 15:01
*/
@Data
@ApiModel(value = "停止用户签约计划")
public class LearnNowPayLaterStopUserSignPlansBo {
/**
* 签约计划id
*/
@NotBlank(message = "签约计划id不能为空")
@ApiModelProperty(value = "签约计划id",required = true)
private String signPlanId;
/**
* 取消理由
*/
@NotBlank(message = "取消理由不能为空")
@ApiModelProperty(value = "取消理由",required = true)
private String stopReason;
}

View File

@ -0,0 +1,71 @@
package com.cpop.jambox.business.bo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-19 22:40
*/
@Data
@ApiModel(value = "先学后付用户签约计划")
public class LearnNowPayLaterUserSignPlansBo {
/**
* 支付分id
*/
@NotBlank(message = "支付分id不能为空")
@ApiModelProperty(value = "支付分id",required = true)
private String id;
/**
* 云校区id
*/
@NotBlank(message = "云校区id不能为空")
@ApiModelProperty(value = "云校区id",required = true)
private String storeCloudId;
/**
* 子商户下用户openid
*/
@NotBlank(message = "子商户下用户openid不能为空")
@ApiModelProperty(value = "子商户下用户openid",required = true)
private String subOpenId;
/**
* 支付分计划名称
*/
@NotBlank(message = "支付分计划名称不能为空")
@ApiModelProperty(value = "支付分计划名称",required = true)
private String planName;
/**
* 客户名
*/
@NotBlank(message = "客户名不能为空")
@ApiModelProperty(value = "客户名",required = true)
private String customerName;
/**
* 客户手机号
*/
@NotBlank(message = "客户手机号不能为空")
@ApiModelProperty(value = "客户手机号", required = true)
private String customerPhone;
/**
* 模板id
*/
@ApiModelProperty(value = "模板id")
private String templateId;
/**
* 旧模板id
*/
@ApiModelProperty(value = "旧模板id")
private String oldTemplateId;
}

View File

@ -1,31 +0,0 @@
package com.cpop.jambox.business.controller.backstage;
import com.mybatisflex.core.paginate.Page;
import com.cpop.core.base.R;
import com.cpop.jambox.business.entity.CardTemplate;
import com.cpop.jambox.business.service.CardTemplateService;
import com.cpop.jambox.business.vo.CardTemplateListVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.io.Serializable;
import java.util.List;
/**
* 果酱-课卡模板 控制层
*
* @author DB
* @since 2023-09-27
*/
@RestController
@Api(tags = "果酱-课卡模板接口")
@RequestMapping("/cardTemplate")
public class CardTemplateController {
@Autowired
private CardTemplateService cardTemplateService;
}

View File

@ -2,10 +2,7 @@ package com.cpop.jambox.business.controller.backstage;
import com.alibaba.excel.EasyExcel;
import com.cpop.core.base.R;
import com.cpop.jambox.business.bo.EasyLearnPageBo;
import com.cpop.jambox.business.bo.EasyLearnUnifiedPayBo;
import com.cpop.jambox.business.bo.EasyLearnUnionPayBo;
import com.cpop.jambox.business.bo.OncePlaceOrderBo;
import com.cpop.jambox.business.bo.*;
import com.cpop.jambox.business.dto.EasyLearnPageDto;
import com.cpop.jambox.business.service.EasyLearnOrderService;
import com.cpop.jambox.business.vo.EasyLearnPageVo;

View File

@ -0,0 +1,51 @@
package com.cpop.jambox.business.controller.callback;
import com.cpop.jambox.business.service.EasyLearnOrderService;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
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.RestController;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-20 0:22
*/
@RestController
@Api(tags = "果酱-放心学回调接口")
@RequestMapping("/callback/easyLearn")
public class CallBackEasyLearnController {
@Autowired
private EasyLearnOrderService easyLearnOrderService;
/**
* 用户签约成功回调
* @author DB
* @since 2024/1/20
* @param notifyData 返回参数
*/
@ApiOperation("放心学先学后付支付分回调通知")
@PostMapping("/learnNowPayLaterUserSignPlanNotify")
public String learnNowPayLaterUserSignPlanNotifyUrl(@RequestBody String notifyData) {
easyLearnOrderService.learnNowPayLaterUserSignPlanNotify(notifyData);
return WxPayNotifyResponse.success("成功");
}
/**
* 支付分用户核销成功回调
* @author DB
* @since 2024/1/20
* @param notifyData 返回参数
*/
@ApiOperation("支付分用户核销成功回调")
@PostMapping("/userServiceOrderSuccess")
public String userServiceOrderSuccess(@RequestBody String notifyData) {
easyLearnOrderService.userServiceOrderSuccess(notifyData);
return WxPayNotifyResponse.success("成功");
}
}

View File

@ -46,4 +46,6 @@ public class EasyLearnCallBackController {
return WxPayNotifyResponse.success("成功");
}
}

View File

@ -0,0 +1,97 @@
package com.cpop.jambox.business.controller.mini;
import com.cpop.core.base.R;
import com.cpop.core.utils.SpringUtils;
import com.cpop.jambox.business.bo.CardTemplateUnionBo;
import com.cpop.jambox.business.entity.CardTemplate;
import com.cpop.jambox.business.service.CardTemplateExtendService;
import com.cpop.jambox.business.service.CardTemplateService;
import com.cpop.jambox.business.vo.CardTemplateInfoVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import static com.cpop.jambox.business.entity.table.CardTemplateExtendTableDef.CARD_TEMPLATE_EXTEND;
import static com.cpop.jambox.business.entity.table.CardTemplateTableDef.CARD_TEMPLATE;
/**
* 果酱-课卡模板 控制层
*
* @author DB
* @since 2023-09-27
*/
@RestController
@Api(tags = "果酱-课卡模板接口")
@RequestMapping("/mini/cardTemplate")
public class MiniCardTemplateController {
@Autowired
private CardTemplateService cardTemplateService;
/**
* 添加课卡模板(整合)
* @author DB
* @since 2023/10/07 9:59
* @param bo 请求参数
*/
//@SimpleSignatureCheck
@ApiOperation(value = "添加课卡模板(整合)")
@PostMapping("/insertCardTemplateUnion")
public R<Void> insertCardTemplateUnion(@RequestBody @Validated CardTemplateUnionBo bo) {
cardTemplateService.insertCardTemplateUnion(bo);
return R.ok();
}
/**
* 修改课卡模板(整合)
* @author DB
* @since 2023/10/07 9:59
* @param bo 请求参数
*/
//@SimpleSignatureCheck
@ApiOperation(value = "修改课卡模板(整合)")
@PutMapping("/updateCardTemplateUnion")
public R<Void> updateCardTemplateUnion(@RequestBody @Validated CardTemplateUnionBo bo) {
cardTemplateService.updateCardTemplateUnion(bo);
return R.ok();
}
/**
* 删除课卡模板
* @author DB
* @since 2024/1/19
* @param oldId 旧主键id
* @return R<Void>
*/
@Deprecated
@ApiOperation(value = "删除课卡模板")
@DeleteMapping("/removeCardTemplateById/{oldId}")
public R<Void> removeCardTemplateById(@PathVariable String oldId) {
CardTemplate cardTemplate = cardTemplateService.queryChain().where(CARD_TEMPLATE.OLD_TEMPLATE_ID.eq(oldId)).one();
cardTemplateService.updateChain()
.where(CARD_TEMPLATE.OLD_TEMPLATE_ID.eq(oldId))
.remove();
SpringUtils.getBean(CardTemplateExtendService.class).updateChain()
.where(CARD_TEMPLATE_EXTEND.TEMPLATE_ID.eq(cardTemplate.getId()))
.remove();
return R.ok();
}
/**
* 获取模板信息
* @author DB
* @since 2024/1/22
* @param id 主键
* @return R<Void>
*/
@ApiOperation(value = "获取模板信息")
@GetMapping("/getCardTemplateInfo")
public R<CardTemplateInfoVo> getCardTemplateInfo(@ApiParam("id") @RequestParam(value = "id", required = false) String id,
@ApiParam("旧模板id") @RequestParam(value = "oldTemplateId", required = false) String oldTemplateId) {
CardTemplateInfoVo vo = cardTemplateService.getCardTemplateInfo(id, oldTemplateId);
return R.ok(vo);
}
}

View File

@ -0,0 +1,93 @@
package com.cpop.jambox.business.controller.mini;
import com.cpop.core.base.R;
import com.cpop.jambox.business.bo.LearnNowPayLaterServiceOrderBo;
import com.cpop.jambox.business.bo.LearnNowPayLaterStopUserSignPlansBo;
import com.cpop.jambox.business.bo.LearnNowPayLaterUserSignPlansBo;
import com.cpop.jambox.business.service.CardTemplateService;
import com.cpop.jambox.business.service.EasyLearnOrderService;
import com.cpop.jambox.business.vo.LearnNowPayLaterPlanVo;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreSignPlanResult;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreUserSignPlanResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-18 22:58
*/
@RestController
@Api(tags = "果酱小程序-放心学接口")
@RequestMapping("/mini/easyLearn")
public class MiniEasyLearnController {
@Autowired
private CardTemplateService cardTemplateService;
@Autowired
private EasyLearnOrderService easyLearnOrderService;
/**
* 获取支付分计划
* @author DB
* @since 2024/1/18
* @param oldTemplateId 旧模板id
* @param isMonth 是否月付
* @return R<LearnNowPayLaterPlanDetailVo>
*/
@ApiOperation("获取支付分计划")
@GetMapping("/getWxPayScorePlan")
public R<LearnNowPayLaterPlanVo> getWxPayScorePlan(@ApiParam(value = "旧模板id") @RequestParam(value = "oldTemplateId", required = false) String oldTemplateId,
@ApiParam(value = "模板id") @RequestParam(value = "templateId", required = false) String templateId,
@ApiParam(value = "是否月付(0否1是)", required = true) @RequestParam("isMonth") Boolean isMonth) {
LearnNowPayLaterPlanVo vo = cardTemplateService.getWxPayScorePlan(oldTemplateId, templateId, isMonth);
return R.ok(vo);
}
/**
* 获取支付分计划
*
* @param bo 请求参数
* @return R<LearnNowPayLaterPlanDetailVo>
* @author DB
* @since 2024/1/18
*/
@ApiOperation("创建用户签约计划")
@PostMapping("/createUserSignPlans")
public R<WxPartnerPayScoreUserSignPlanResult> createUserSignPlans(@RequestBody @Validated LearnNowPayLaterUserSignPlansBo bo) {
WxPartnerPayScoreUserSignPlanResult result = easyLearnOrderService.createUserSignPlans(bo);
return R.ok(result);
}
/**
* 创建用户服务订单(核销)
* @author DB
* @since 2024/1/20
* @param bo 请求参数
*/
@ApiOperation("创建用户服务订单(核销)")
@PostMapping("/createServiceOrder")
public R<WxPartnerPayScoreSignPlanResult> createServiceOrder(@RequestBody @Validated LearnNowPayLaterServiceOrderBo bo) {
WxPartnerPayScoreSignPlanResult result = easyLearnOrderService.createServiceOrder(bo);
return R.ok(result);
}
/**
* 取消用户签约计划
* @author DB
* @since 2024/1/20
* @param bo 请求参数
* @return R<Void>
*/
@ApiOperation("取消用户签约计划")
@PostMapping("/stopUserSignPlans")
public R<Void> stopUserSignPlans(@RequestBody @Validated LearnNowPayLaterStopUserSignPlansBo bo){
easyLearnOrderService.stopUserSignPlans(bo);
return R.ok();
}
}

View File

@ -41,14 +41,14 @@ public class CardTemplate extends BaseEntity implements Serializable {
private String oldTemplateId;
/**
* 品牌id
* 品牌id
*/
private String cloudBrandId;
private String brandId;
/**
* 校区id
* 校区id
*/
private String cloudStoreId;
private String storeId;
/**
* 是否使用(0否1是)
@ -65,11 +65,6 @@ public class CardTemplate extends BaseEntity implements Serializable {
*/
private Integer validDay;
/**
* 开始日期
*/
private LocalDate startDate;
/**
* 结束日期
*/
@ -110,11 +105,6 @@ public class CardTemplate extends BaseEntity implements Serializable {
*/
private String scopeUse;
/**
* 支付类型(0:微信支付;1:微信先学后付;2:放心学合约支付;3:数字人民币支付;4:线下支付)
*/
private String payType;
/**
* 太阳码
*/
@ -126,10 +116,9 @@ public class CardTemplate extends BaseEntity implements Serializable {
private Boolean isMember;
/**
* 模板类型(0:课时卡,1:时限卡,2:储值卡)
* 是否是引流卡
*/
@Column(ignore = true)
private String oldTemplateType;
private Boolean isDrainage;
/**
* 逻辑删除(0否1是)

View File

@ -0,0 +1,62 @@
package com.cpop.jambox.business.entity;
import com.cpop.core.base.entity.BaseEntity;
import com.cpop.core.base.entity.BaseInsertListener;
import com.cpop.core.base.entity.BaseUpdateListener;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.Accessors;
/**
* 果酱模板拓展表 实体类
*
* @author DB
* @since 2024-01-17
*/
@Data
@EqualsAndHashCode(callSuper=false)
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@Table(value = "cp_j_card_template_extend", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false)
public class CardTemplateExtend extends BaseEntity implements Serializable {
/**
* 模板id
*/
@Id
private String templateId;
/**
* 支付类型(0:微信支付;1:先学后付次付;2:旧放心学合约支付;3:数字人民币支付;4:线下支付;5:先学后付月付
*/
@Id
private Integer payType;
/**
* 拓展id
*/
private String extendId;
/**
* 拓展参数1
*/
private String extendParamOne;
/**
* 拓展参数2
*/
private String extendParamTwo;
/**
* 拓展参数3
*/
private String extendParamThree;
}

View File

@ -104,6 +104,11 @@ public class EasyLearnOrder extends BaseEntity implements Serializable {
*/
private Double rate;
/**
* 模板id
*/
private String templateId;
/**
* 逻辑删除0否1是
*/

View File

@ -0,0 +1,14 @@
package com.cpop.jambox.business.mapper;
import com.mybatisflex.core.BaseMapper;
import com.cpop.jambox.business.entity.CardTemplateExtend;
/**
* 果酱模板拓展表 映射层
*
* @author DB
* @since 2024-01-17
*/
public interface CardTemplateExtendMapper extends BaseMapper<CardTemplateExtend> {
}

View File

@ -0,0 +1,14 @@
package com.cpop.jambox.business.service;
import com.mybatisflex.core.service.IService;
import com.cpop.jambox.business.entity.CardTemplateExtend;
/**
* 果酱模板拓展表 服务层
*
* @author DB
* @since 2024-01-17
*/
public interface CardTemplateExtendService extends IService<CardTemplateExtend> {
}

View File

@ -1,10 +1,12 @@
package com.cpop.jambox.business.service;
import com.mybatisflex.core.service.IService;
import com.cpop.jambox.business.bo.CardTemplateUnionBo;
import com.cpop.jambox.business.entity.CardTemplate;
import com.cpop.jambox.business.vo.CardTemplateListVo;
import java.util.List;
import com.cpop.jambox.business.vo.CardTemplateInfoVo;
import com.cpop.jambox.business.vo.LearnNowPayLaterPlanDetailVo;
import com.cpop.jambox.business.vo.LearnNowPayLaterPlanVo;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.service.IService;
/**
* 果酱-课卡模板 服务层
@ -22,5 +24,40 @@ public interface CardTemplateService extends IService<CardTemplate> {
* @param brandId 品牌id
* @return: com.cpop.jambox.business.entity.CardTemplate
*/
CardTemplate getOldTemplateInfo(String oldTemplateId, String brandId);
Row getOldTemplateInfo(String oldTemplateId, String brandId);
/**
* 添加课卡模板(整合)
* @author DB
* @since 2024/1/16
* @param bo 请求参数
* @return String 旧模板id
*/
void insertCardTemplateUnion(CardTemplateUnionBo bo);
/**
* 修改课卡模板(整合)
* @author DB
* @since 2024/1/18
* @param bo 请求参数
*/
void updateCardTemplateUnion(CardTemplateUnionBo bo);
/**
* 获取支付分计划
* @author DB
* @since 2024/1/18
* @param oldTemplateId 旧模板id
* @param isMonth 是否月付
* @return LearnNowPayLaterPlanDetailVo
*/
LearnNowPayLaterPlanVo getWxPayScorePlan(String oldTemplateId,String templateId, Boolean isMonth);
/**
* 获取模板信息
* @author DB
* @since 2024/1/22
* @param id 主键
*/
CardTemplateInfoVo getCardTemplateInfo(String id,String oldTemplateId);
}

View File

@ -1,12 +1,11 @@
package com.cpop.jambox.business.service;
import com.cpop.jambox.business.bo.EasyLearnPageBo;
import com.cpop.jambox.business.bo.EasyLearnUnifiedPayBo;
import com.cpop.jambox.business.bo.EasyLearnUnionPayBo;
import com.cpop.jambox.business.bo.OncePlaceOrderBo;
import com.cpop.jambox.business.bo.*;
import com.cpop.jambox.business.dto.EasyLearnPageDto;
import com.cpop.jambox.business.entity.EasyLearnOrder;
import com.cpop.jambox.business.vo.EasyLearnPageVo;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreSignPlanResult;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreUserSignPlanResult;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
@ -77,4 +76,45 @@ public interface EasyLearnOrderService extends IService<EasyLearnOrder> {
* @return Object
*/
Object unifiedPay(EasyLearnUnifiedPayBo bo);
/**
* 创建用户签约计划
* @author DB
* @since 2024/1/19
* @param bo 请求参数
*/
WxPartnerPayScoreUserSignPlanResult createUserSignPlans(LearnNowPayLaterUserSignPlansBo bo);
/**
* 用户签约成功回调
* @author DB
* @since 2024/1/20
* @param notifyData 返回参数
*/
void learnNowPayLaterUserSignPlanNotify(String notifyData);
/**
* 创建用户服务订单(核销)
* @author DB
* @since 2024/1/20
* @param bo 请求参数
* @return WxPartnerPayScoreSignPlanResult
*/
WxPartnerPayScoreSignPlanResult createServiceOrder(LearnNowPayLaterServiceOrderBo bo);
/**
* 支付分用户核销成功回调
* @author DB
* @since 2024/1/20
* @param notifyData 返回数据
*/
void userServiceOrderSuccess(String notifyData);
/**
* 取消用户签约计划
* @author DB
* @since 2024/1/20
* @param bo 请求参数
*/
void stopUserSignPlans(LearnNowPayLaterStopUserSignPlansBo bo);
}

View File

@ -0,0 +1,18 @@
package com.cpop.jambox.business.service.impl;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.cpop.jambox.business.entity.CardTemplateExtend;
import com.cpop.jambox.business.mapper.CardTemplateExtendMapper;
import com.cpop.jambox.business.service.CardTemplateExtendService;
import org.springframework.stereotype.Service;
/**
* 果酱模板拓展表 服务层实现
*
* @author DB
* @since 2024-01-17
*/
@Service("cardTemplateExtendService")
public class CardTemplateExtendServiceImpl extends ServiceImpl<CardTemplateExtendMapper, CardTemplateExtend> implements CardTemplateExtendService {
}

View File

@ -1,24 +1,59 @@
package com.cpop.jambox.business.service.impl;
import cn.binarywang.wx.miniapp.api.WxMaQrcodeService;
import cn.binarywang.wx.miniapp.api.WxMaService;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.handler.TencentCosHandler;
import com.cpop.core.utils.SpringUtils;
import com.cpop.core.utils.file.FileUtils;
import com.cpop.jambox.business.bo.CardTemplateUnionBo;
import com.cpop.jambox.business.bo.EasyLearnDigitalCurrencyBo;
import com.cpop.jambox.business.bo.EasyLearnOldContractBo;
import com.cpop.jambox.business.entity.BrandExtend;
import com.cpop.jambox.business.entity.CardTemplate;
import com.cpop.jambox.business.entity.CardTemplateExtend;
import com.cpop.jambox.business.entity.StoreExtend;
import com.cpop.jambox.business.mapper.CardTemplateMapper;
import com.cpop.jambox.business.service.BrandExtendService;
import com.cpop.jambox.business.service.CardTemplateExtendService;
import com.cpop.jambox.business.service.CardTemplateService;
import com.cpop.jambox.business.service.StoreExtendService;
import com.cpop.jambox.business.vo.CardTemplateInfoVo;
import com.cpop.jambox.business.vo.LearnNowPayLaterPlanDetailVo;
import com.cpop.jambox.business.vo.LearnNowPayLaterPlanVo;
import com.cpop.jambox.framework.tasks.LearnNowPayLaterTask;
import com.cpop.system.business.entity.Store;
import com.cpop.system.business.entity.WxPayScore;
import com.cpop.system.business.entity.WxPayScoreDetail;
import com.cpop.system.business.service.StoreService;
import com.cpop.system.business.service.WxPayScoreDetailService;
import com.cpop.system.business.service.WxPayScoreService;
import com.mybatisflex.core.datasource.DataSourceKey;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.row.RowUtil;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.qcloud.cos.model.UploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.cpop.jambox.business.entity.table.BrandExtendTableDef.BRAND_EXTEND;
import static com.cpop.jambox.business.entity.table.CardTemplateExtendTableDef.CARD_TEMPLATE_EXTEND;
import static com.cpop.jambox.business.entity.table.CardTemplateTableDef.CARD_TEMPLATE;
import static com.cpop.jambox.business.entity.table.StoreExtendTableDef.STORE_EXTEND;
import static com.cpop.system.business.entity.table.WxPayScoreDetailTableDef.WX_PAY_SCORE_DETAIL;
import static com.cpop.system.business.entity.table.WxPayScoreTableDef.WX_PAY_SCORE;
/**
* 果酱-课卡模板 服务层实现
@ -38,24 +73,288 @@ public class CardTemplateServiceImpl extends ServiceImpl<CardTemplateMapper, Car
* @return: com.cpop.jambox.business.entity.CardTemplate
*/
@Override
public CardTemplate getOldTemplateInfo(String oldTemplateId, String brandId) {
//查询模板信息
CardTemplate cardTemplate;
public Row getOldTemplateInfo(String oldTemplateId, String brandId) {
try {
DataSourceKey.use("jambox");
Row row = Db.selectOneByQuery("t_card_template", QueryWrapper.create()
return Db.selectOneByQuery("t_card_template", QueryWrapper.create()
.select("template_id AS oldTemplateId", "store_id AS cloudStoreId", "open_status AS status", "name", "day AS validDay",
"start AS startDate", "end AS endDate", "price", "number AS classNumber", "week_appointment", "day_appointment",
"time_limit AS oldTemplateType", "type AS scopeUse", "pay_type", "template_qr_code AS qrCode", "is_member")
.from("t_card_template")
.where("template_id = ?", oldTemplateId));
cardTemplate = RowUtil.toEntity(row, CardTemplate.class);
} finally {
DataSourceKey.clear();
}
//获取云品牌信息
BrandExtend brandExtend = SpringUtils.getBean(BrandExtendService.class).getOne(QueryWrapper.create().where(BRAND_EXTEND.BRAND_ID.eq(brandId)));
cardTemplate.setCloudBrandId(brandExtend.getBrandCloudId());
return cardTemplate;
}
/**
* 添加课卡模板(整合)
* @author DB
* @since 2024/1/16
* @param bo 请求参数
* @return String 旧模板id
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void insertCardTemplateUnion(CardTemplateUnionBo bo) {
CardTemplate cardTemplate = BeanUtils.mapToClass(bo, CardTemplate.class);
//品牌
if (StringUtils.isNotBlank(bo.getBrandCloudId())){
BrandExtendService brandExtendService = SpringUtils.getBean(BrandExtendService.class);
BrandExtend brandExtend = brandExtendService.getOne(QueryWrapper.create().where(BRAND_EXTEND.BRAND_CLOUD_ID.eq(bo.getBrandCloudId())));
cardTemplate.setBrandId(brandExtend.getBrandId());
} else {
//校区
StoreExtend storeExtend = SpringUtils.getBean(StoreExtendService.class).getOne(QueryWrapper.create().where(STORE_EXTEND.STORE_CLOUD_ID.eq(bo.getStoreCloudId())));
Store store = SpringUtils.getBean(StoreService.class).getById(storeExtend.getStoreId());
cardTemplate.setStoreId(store.getId()).setBrandId(store.getBrandId());
}
this.save(cardTemplate);
saveTemplateExtend(cardTemplate,bo);
//次付
if (bo.getPayType().contains(1)) {
SpringUtils.getBean(LearnNowPayLaterTask.class).asyncCreateLearnNowPayLaterPlan(cardTemplate, bo.getLearnNowPayLaterPay(), 1);
}
//月付
if (bo.getPayType().contains(5)) {
SpringUtils.getBean(LearnNowPayLaterTask.class).asyncCreateLearnNowPayLaterPlan(cardTemplate, bo.getLearnNowPayLaterMonthPay(), 5);
}
if (bo.getPayType().contains(0) || bo.getPayType().contains(1) || bo.getPayType().contains(2) || bo.getPayType().contains(3) || bo.getPayType().contains(5)) {
WxMaQrcodeService qrcodeService = SpringUtils.getBean(WxMaService.class).getQrcodeService();
try {
// 获取当前执行环境
String active = SpringUtils.getActiveProfile();
File qrCode = qrcodeService.createWxaCodeUnlimit(cardTemplate.getId(), "pages/pay/pay", false, StringUtils.equals(active, "prod") ? "release" : "trial", 430,
true, null, false);
MultipartFile multipartFile = FileUtils.getInstance().getMultipartFile(qrCode);
TencentCosHandler tencentCosHandler = SpringUtils.getBean(TencentCosHandler.class);
UploadResult uploadResult = tencentCosHandler.cdnUpload(multipartFile);
cardTemplate.setQrCode("https://" + uploadResult.getBucketName() + tencentCosHandler.getCdnUrl() + uploadResult.getKey());
this.updateById(cardTemplate);
} catch (WxErrorException | IOException e) {
throw new ServiceException("生成支付码失败");
}
}
}
/**
* 插入模板拓展
* @author DB
* @since 2024/1/19
* @param cardTemplate 模板
* @param bo 请求
*/
private void saveTemplateExtend(CardTemplate cardTemplate, CardTemplateUnionBo bo) {
List<CardTemplateExtend> cardTemplateExtends = new ArrayList<>();
List<Integer> payTypeList = bo.getPayType();
//普通微信支付
if (payTypeList.contains(0)){
CardTemplateExtend cardTemplateExtend = new CardTemplateExtend();
cardTemplateExtend.setTemplateId(cardTemplate.getId()).setPayType(0);
cardTemplateExtends.add(cardTemplateExtend);
}
//放心学合约支付
if (payTypeList.contains(2)){
CardTemplateExtend cardTemplateExtend = new CardTemplateExtend();
EasyLearnOldContractBo easyLearnOldContract = bo.getEasyLearnOldContract();
cardTemplateExtend.setTemplateId(cardTemplate.getId()).setPayType(2)
.setExtendParamOne(easyLearnOldContract.getStageNum().toString())
.setExtendParamTwo(easyLearnOldContract.getDeposit().toString())
.setExtendParamThree(easyLearnOldContract.getFirstBufferDay().toString());
cardTemplateExtends.add(cardTemplateExtend);
}
//数字人民币支付
if (payTypeList.contains(3)){
CardTemplateExtend cardTemplateExtend = new CardTemplateExtend();
EasyLearnDigitalCurrencyBo easyLearnDigitalCurrency = bo.getEasyLearnDigitalCurrency();
cardTemplateExtend.setTemplateId(cardTemplate.getId()).setPayType(3)
.setExtendParamOne(easyLearnDigitalCurrency.getIsActivity().toString())
.setExtendParamTwo(easyLearnDigitalCurrency.getActivityCode())
.setExtendParamThree(easyLearnDigitalCurrency.getActivityDesc());
cardTemplateExtends.add(cardTemplateExtend);
}
//线下支付
if (payTypeList.contains(4)){
CardTemplateExtend cardTemplateExtend = new CardTemplateExtend();
cardTemplateExtend.setTemplateId(cardTemplate.getId()).setPayType(4);
cardTemplateExtends.add(cardTemplateExtend);
}
SpringUtils.getBean(CardTemplateExtendService.class).saveBatch(cardTemplateExtends);
}
/**
* 修改课卡模板(整合)
* @author DB
* @since 2024/1/18
* @param bo 请求参数
*/
@Override
public void updateCardTemplateUnion(CardTemplateUnionBo bo) {
CardTemplate cardTemplate = BeanUtils.mapToClass(bo, CardTemplate.class);
this.update(cardTemplate, QueryWrapper.create().where(CARD_TEMPLATE.OLD_TEMPLATE_ID.eq(bo.getOldTemplateId())));
CardTemplateExtendService cardTemplateExtendService = SpringUtils.getBean(CardTemplateExtendService.class);
List<CardTemplateExtend> cardTemplateExtends = cardTemplateExtendService.list(QueryWrapper.create()
.where(CARD_TEMPLATE_EXTEND.TEMPLATE_ID.eq(bo.getOldTemplateId())));
updateTemplateExtend(cardTemplate, bo, cardTemplateExtends);
//次付
List<Integer> payTypeList = cardTemplateExtends.stream().map(CardTemplateExtend::getPayType).collect(Collectors.toList());
if (bo.getPayType().contains(1) && !payTypeList.contains(1)) {
SpringUtils.getBean(LearnNowPayLaterTask.class).asyncCreateLearnNowPayLaterPlan(cardTemplate, bo.getLearnNowPayLaterPay(), 1);
}
if (!bo.getPayType().contains(1) && payTypeList.contains(1)){
//停用先学后付
SpringUtils.getBean(CardTemplateExtendService.class).updateChain()
.set(CARD_TEMPLATE_EXTEND.EXTEND_PARAM_ONE, false)
.where(CARD_TEMPLATE_EXTEND.PAY_TYPE.eq(1))
.and(CARD_TEMPLATE_EXTEND.TEMPLATE_ID.eq(cardTemplate.getId()))
.update();
}
//月付
if (bo.getPayType().contains(5) && !payTypeList.contains(5)) {
SpringUtils.getBean(LearnNowPayLaterTask.class).asyncCreateLearnNowPayLaterPlan(cardTemplate, bo.getLearnNowPayLaterMonthPay(), 5);
}
if (!bo.getPayType().contains(1) && payTypeList.contains(1)){
//停用先学后付
SpringUtils.getBean(CardTemplateExtendService.class).updateChain()
.set(CARD_TEMPLATE_EXTEND.EXTEND_PARAM_ONE, false)
.where(CARD_TEMPLATE_EXTEND.PAY_TYPE.eq(5))
.and(CARD_TEMPLATE_EXTEND.TEMPLATE_ID.eq(cardTemplate.getId()))
.update();
}
}
/**
* 更新模板拓展
* @author DB
* @since 2024/1/19
* @param cardTemplate 模板
* @param bo 请求
*/
private void updateTemplateExtend(CardTemplate cardTemplate, CardTemplateUnionBo bo, List<CardTemplateExtend> cardTemplateExtends) {
List<Integer> payTypeList = bo.getPayType();
Map<Integer, CardTemplateExtend> existExtends = cardTemplateExtends.stream().collect(Collectors.toMap(CardTemplateExtend::getPayType, item -> item));
List<Integer> removePayTypes = new ArrayList<>();
//普通微信支付
if (payTypeList.contains(0)) {
if (existExtends.get(0) == null) {
CardTemplateExtend cardTemplateExtend = new CardTemplateExtend();
cardTemplateExtend.setTemplateId(cardTemplate.getId()).setPayType(0);
cardTemplateExtends.add(cardTemplateExtend);
}
} else {
removePayTypes.add(0);
}
//放心学旧合约支付
if (payTypeList.contains(2)) {
CardTemplateExtend cardTemplateExtend;
EasyLearnOldContractBo easyLearnOldContract = bo.getEasyLearnOldContract();
if (existExtends.get(2) == null) {
cardTemplateExtend = new CardTemplateExtend();
cardTemplateExtend.setTemplateId(cardTemplate.getId()).setPayType(2)
.setExtendParamOne(easyLearnOldContract.getStageNum().toString())
.setExtendParamTwo(easyLearnOldContract.getDeposit().toString())
.setExtendParamThree(easyLearnOldContract.getFirstBufferDay().toString());
} else {
cardTemplateExtend = existExtends.get(2);
cardTemplateExtend.setExtendParamOne(easyLearnOldContract.getStageNum().toString())
.setExtendParamTwo(easyLearnOldContract.getDeposit().toString())
.setExtendParamThree(easyLearnOldContract.getFirstBufferDay().toString());
}
cardTemplateExtends.add(cardTemplateExtend);
} else {
removePayTypes.add(2);
}
//数字人民币支付
if (payTypeList.contains(3)){
CardTemplateExtend cardTemplateExtend;
EasyLearnDigitalCurrencyBo easyLearnDigitalCurrency = bo.getEasyLearnDigitalCurrency();
if (existExtends.get(3) == null) {
cardTemplateExtend = new CardTemplateExtend();
cardTemplateExtend.setTemplateId(cardTemplate.getId()).setPayType(3)
.setExtendParamOne(easyLearnDigitalCurrency.getIsActivity().toString())
.setExtendParamTwo(easyLearnDigitalCurrency.getActivityCode())
.setExtendParamThree(easyLearnDigitalCurrency.getActivityDesc());
} else {
cardTemplateExtend = existExtends.get(3);
cardTemplateExtend.setExtendParamOne(easyLearnDigitalCurrency.getIsActivity().toString())
.setExtendParamTwo(easyLearnDigitalCurrency.getActivityCode())
.setExtendParamThree(easyLearnDigitalCurrency.getActivityDesc());
}
cardTemplateExtends.add(cardTemplateExtend);
} else {
removePayTypes.add(3);
}
//线下支付
if (payTypeList.contains(4)) {
CardTemplateExtend cardTemplateExtend = new CardTemplateExtend();
cardTemplateExtend.setTemplateId(cardTemplate.getId()).setPayType(4);
cardTemplateExtends.add(cardTemplateExtend);
} else {
removePayTypes.add(4);
}
CardTemplateExtendService cardTemplateExtendService = SpringUtils.getBean(CardTemplateExtendService.class);
cardTemplateExtendService.saveBatch(cardTemplateExtends);
cardTemplateExtendService.updateChain()
.where(CARD_TEMPLATE_EXTEND.TEMPLATE_ID.eq(cardTemplate.getId()))
.and(CARD_TEMPLATE_EXTEND.PAY_TYPE.in(removePayTypes))
.remove();
}
/**
* 获取支付分计划
* @author DB
* @since 2024/1/18
* @param oldTemplateId 旧模板id
* @param isMonth 是否月付
* @return LearnNowPayLaterPlanDetailVo
*/
@Override
public LearnNowPayLaterPlanVo getWxPayScorePlan(String oldTemplateId,String templateId, Boolean isMonth) {
CardTemplate cardTemplate;
if (StringUtils.isNotBlank(templateId)) {
cardTemplate = this.queryChain().where(CARD_TEMPLATE.OLD_TEMPLATE_ID.eq(oldTemplateId)).one();
} else {
cardTemplate = this.queryChain().where(CARD_TEMPLATE.ID.eq(templateId)).one();
}
CardTemplateExtendService cardTemplateExtendService = SpringUtils.getBean(CardTemplateExtendService.class);
CardTemplateExtend cardTemplateExtend = cardTemplateExtendService.getOne(QueryWrapper.create()
.where(CARD_TEMPLATE_EXTEND.TEMPLATE_ID.eq(cardTemplate.getId()))
.and(CARD_TEMPLATE_EXTEND.PAY_TYPE.eq(isMonth ? 5 : 1)));
WxPayScore wxPayScore = SpringUtils.getBean(WxPayScoreService.class).getOne(QueryWrapper.create()
.where(WX_PAY_SCORE.ID.eq(cardTemplateExtend.getExtendId())));
LearnNowPayLaterPlanVo vo = BeanUtils.mapToClass(wxPayScore, LearnNowPayLaterPlanVo.class);
List<WxPayScoreDetail> wxPayScoreDetails = SpringUtils.getBean(WxPayScoreDetailService.class).list(QueryWrapper.create()
.where(WX_PAY_SCORE_DETAIL.SYS_WX_PAY_SCORE_ID.eq(vo.getId())));
List<LearnNowPayLaterPlanDetailVo> detailVos = BeanUtils.mapToList(wxPayScoreDetails, LearnNowPayLaterPlanDetailVo.class);
vo.setPlanDetailList(detailVos);
return vo;
}
/**
* 获取模板信息
* @author DB
* @since 2024/1/22
* @param id 主键
*/
@Override
public CardTemplateInfoVo getCardTemplateInfo(String id, String oldTemplateId) {
//TODO: 模板详情信息调整
CardTemplateInfoVo vo;
if (StringUtils.isNotBlank(id)) {
vo = this.getOneAs(QueryWrapper.create().where(CARD_TEMPLATE.ID.eq(id))
, CardTemplateInfoVo.class);
} else {
vo = this.getOneAs(QueryWrapper.create().where(CARD_TEMPLATE.OLD_TEMPLATE_ID.eq(oldTemplateId))
, CardTemplateInfoVo.class);
}
//获取模板拓展
List<Integer> payTypeList = SpringUtils.getBean(CardTemplateExtendService.class).queryChain()
.where(CARD_TEMPLATE_EXTEND.TEMPLATE_ID.eq(vo.getId()))
.list().stream().map(CardTemplateExtend::getPayType)
.collect(Collectors.toList());
vo.setPayType(payTypeList);
return vo;
}
}

View File

@ -1,6 +1,9 @@
package com.cpop.jambox.business.service.impl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cpop.api.cloudDb.core.dto.CloudClassCardDto;
import com.cpop.api.cloudDb.handler.CloudClassCardHandler;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.common.utils.http.HttpUtils;
@ -12,18 +15,11 @@ import com.cpop.core.service.RedisService;
import com.cpop.core.utils.SecurityUtils;
import com.cpop.core.utils.SpringUtils;
import com.cpop.core.utils.sql.SqlUtils;
import com.cpop.jambox.business.bo.EasyLearnPageBo;
import com.cpop.jambox.business.bo.EasyLearnUnifiedPayBo;
import com.cpop.jambox.business.bo.EasyLearnUnionPayBo;
import com.cpop.jambox.business.bo.OncePlaceOrderBo;
import com.cpop.jambox.business.bo.*;
import com.cpop.jambox.business.dto.EasyLearnPageDto;
import com.cpop.jambox.business.entity.BrandExtend;
import com.cpop.jambox.business.entity.EasyLearnOrder;
import com.cpop.jambox.business.entity.StoreExtend;
import com.cpop.jambox.business.entity.*;
import com.cpop.jambox.business.mapper.EasyLearnOrderMapper;
import com.cpop.jambox.business.service.BrandExtendService;
import com.cpop.jambox.business.service.EasyLearnOrderService;
import com.cpop.jambox.business.service.StoreExtendService;
import com.cpop.jambox.business.service.*;
import com.cpop.jambox.business.vo.EasyLearnPageVo;
import com.cpop.jambox.framework.constant.JamboxCloudUrl;
import com.cpop.jambox.framework.constant.JamboxRedisConstant;
@ -32,11 +28,18 @@ import com.cpop.pay.framewok.config.wxPay.WxPayConfiguration;
import com.cpop.pay.framewok.handler.wxPay.WxPayHandler;
import com.cpop.pay.framewok.task.WxPayAsyncTask;
import com.cpop.system.business.entity.Store;
import com.cpop.system.business.entity.WxPayScore;
import com.cpop.system.business.entity.WxPayScoreDetail;
import com.cpop.system.business.service.StoreService;
import com.cpop.system.business.service.WxPayScoreDetailService;
import com.cpop.system.business.service.WxPayScoreService;
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.payscore.*;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.PartnerPayScoreSignPlanService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.mybatisflex.core.FlexGlobalConfig;
import com.mybatisflex.core.datasource.DataSourceKey;
@ -44,6 +47,7 @@ import com.mybatisflex.core.datasource.FlexDataSource;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.DbChain;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.row.RowUtil;
import com.mybatisflex.spring.service.impl.ServiceImpl;
@ -55,13 +59,21 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import static com.cpop.jambox.business.entity.table.BrandExtendTableDef.BRAND_EXTEND;
import static com.cpop.jambox.business.entity.table.EasyLearnOrderDetailTableDef.EASY_LEARN_ORDER_DETAIL;
import static com.cpop.jambox.business.entity.table.EasyLearnOrderExtendTableDef.EASY_LEARN_ORDER_EXTEND;
import static com.cpop.jambox.business.entity.table.EasyLearnOrderTableDef.EASY_LEARN_ORDER;
import static com.cpop.jambox.business.entity.table.StoreExtendTableDef.STORE_EXTEND;
import static com.cpop.system.business.entity.table.StoreTableDef.STORE;
import static com.cpop.system.business.entity.table.WxPayScoreDetailTableDef.WX_PAY_SCORE_DETAIL;
import static com.cpop.system.business.entity.table.WxPayScoreTableDef.WX_PAY_SCORE;
/**
* 果酱-放心学订单表 服务层实现
@ -79,6 +91,9 @@ public class EasyLearnOrderServiceImpl extends ServiceImpl<EasyLearnOrderMapper,
@Autowired
private WxPayAsyncTask wxPayAsyncTask;
@Autowired
private WxPayConfiguration wxPayConfiguration;
/**
* 一次性支付回调地址本地内网穿透
*/
@ -390,6 +405,7 @@ public class EasyLearnOrderServiceImpl extends ServiceImpl<EasyLearnOrderMapper,
}
//课卡信息
JSONObject jsonBody = new JSONObject();
jsonBody.put("_type", "addPeriod");
//办卡实收金额
jsonBody.put("money", easyLearnOrder.getTotalPayAmount());
@ -655,4 +671,318 @@ public class EasyLearnOrderServiceImpl extends ServiceImpl<EasyLearnOrderMapper,
public Object unifiedPay(EasyLearnUnifiedPayBo bo) {
return null;
}
/**
* 创建用户签约计划
* @author DB
* @since 2024/1/19
* @param bo 请求参数
*/
@Override
@Transactional(rollbackFor = Exception.class)
public WxPartnerPayScoreUserSignPlanResult createUserSignPlans(LearnNowPayLaterUserSignPlansBo bo) {
//分布式锁进行幂等处理
RedisService redisService = SpringUtils.getBean(RedisService.class);
//分布式锁进行幂等处理
Lock userIdLock = redisService.distributedLock(JamboxRedisConstant.LEARN_NOW_PAY_LATER_CREATE_USER_PLANS_LOCK_USER_PAY + bo.getId());
if (userIdLock.tryLock()) {
try {
// 获取计划
WxPayScore wxPayScore = SpringUtils.getBean(WxPayScoreService.class).getById(bo.getId());
//获取计划详情
List<WxPayScoreDetail> wxPayScoreDetails = SpringUtils.getBean(WxPayScoreDetailService.class).queryChain()
.where(WX_PAY_SCORE_DETAIL.SYS_WX_PAY_SCORE_ID.eq(bo.getId()))
.list();
Row brandAndStore = Db.selectOneByQuery(QueryWrapper.create()
.select(STORE.ID, STORE.BRAND_ID)
.leftJoin(STORE_EXTEND).on(STORE_EXTEND.STORE_ID.eq(STORE.ID))
.where(STORE_EXTEND.STORE_CLOUD_ID.eq(bo.getStoreCloudId())));
//创建用户签约计划
String orderId = createEasyLearnUserSignPlans(bo, brandAndStore, wxPayScore);
String subMchId = wxPayHandler.getSubMchId(brandAndStore.getString("brandId"), brandAndStore.getString("id"));
WxPayService wxPayService = wxPayHandler.getWxPayService(null, subMchId);
PartnerPayScoreSignPlanService partnerPayScoreSignPlanService = wxPayService.getPartnerPayScoreSignPlanService();
List<PayScorePlanDetailRequest> payScorePlanDetailRequests = BeanUtils.mapToList(wxPayScoreDetails, PayScorePlanDetailRequest.class);
WxPartnerPayScoreSignPlanRequest signPlanRequest = new WxPartnerPayScoreSignPlanRequest();
signPlanRequest.setPlanId(wxPayScore.getOutPlanId()).setSubAppid(subMchId)
.setSubOpenid(bo.getSubOpenId())
.setMerchantSignPlanNo(orderId)
.setPlanDetailList(payScorePlanDetailRequests)
.setNotifyUrl(wxPayConfiguration.getProperties().getLearnNowPayLaterUserSignPlanNotifyUrl());
try {
return partnerPayScoreSignPlanService.createUserSignPlans(signPlanRequest);
} catch (WxPayException e) {
throw new ServiceException(e.getMessage());
}
} finally {
//释放锁
userIdLock.unlock();
}
} else {
//获取锁失败直接返回空
throw new ServiceException("请勿重复提交");
}
}
/**
* 创建用户支付计划
* @author DB
* @since 2024/1/19
* @param wxPayScore 支付分
* @return String
*/
private String createEasyLearnUserSignPlans(LearnNowPayLaterUserSignPlansBo bo, Row brandAndStore, WxPayScore wxPayScore) {
EasyLearnOrder easyLearnOrder = new EasyLearnOrder();
easyLearnOrder.setBrandId(brandAndStore.getString("brandId"))
.setStoreId(brandAndStore.getString("id"))
.setOrderContent(bo.getPlanName())
.setOrderStatus(0)
.setCustomerName(bo.getCustomerName())
.setCustomerPhone(bo.getCustomerPhone())
.setTotalAmount(new BigDecimal(wxPayScore.getTotalOriginalPrice()).divide(BigDecimal.valueOf(100)))
.setTotalPayAmount(BigDecimal.ZERO)
.setOrderType(0)
.setRate(OrderSource.LEARN_NOW_PAY_LATER.getRate())
.setTemplateId(bo.getTemplateId() == null ? bo.getOldTemplateId() : bo.getTemplateId());
this.save(easyLearnOrder);
return easyLearnOrder.getId();
}
private final String LOCAL_TEMPLATE_URL = "http://localhost:9420/Cpop-Oam/";
private final String TEST_TEMPLATE_URL = "https://test.cpopsz.com/oam/Cpop-Oam/";
private final String PROD_TEMPLATE_URL = "https://oam.jamboxsys.com/Cpop-Oam/";
/**
* 用户签约成功回调
* @author DB
* @since 2024/1/20
* @param notifyData 响应数据
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void learnNowPayLaterUserSignPlanNotify(String notifyData) {
try {
PayScoreNotifyData payScoreNotifyData = JSONObject.parseObject(notifyData, PayScoreNotifyData.class);
PartnerPayScoreSignPlanService partnerPayScoreSignPlanService = wxPayHandler.getWxPayService().getPartnerPayScoreSignPlanService();
SignatureHeader signatureHeader = wxPayHandler.getSignatureHeader();
PartnerUserSignPlanEntity result = partnerPayScoreSignPlanService.parseSignPlanNotifyResult(notifyData, signatureHeader);
String orderId = result.getMerchantSignPlanNo();
EasyLearnOrder easyLearnOrder = this.getById(orderId);
//支付成功
if (StringUtils.equals("PAYSCORE.USER_SIGN_PLAN", payScoreNotifyData.getEventType())) {
//订单已支付
if (easyLearnOrder.getOrderStatus() == 1){
return;
}
easyLearnOrder.setOrderStatus(1).setOutOrderNo(result.getSignPlanId());
//添加支付分详情
List<EasyLearnOrderDetail> easyLearnOrderDetails = new ArrayList<>();
result.getSignedDetailList().forEach(item->{
EasyLearnOrderDetail easyLearnOrderDetail = new EasyLearnOrderDetail();
easyLearnOrderDetail.setOrderId(easyLearnOrder.getId())
.setPeriodNo(item.getPlanDetailNo())
.setAmount(new BigDecimal(item.getOriginalPrice()).divide(BigDecimal.valueOf(100)))
.setDetailDesc(item.getPlanDiscountDescription())
.setActualPrice(new BigDecimal(item.getActualPrice()).divide(BigDecimal.valueOf(100)))
.setDetailStatus(0)
.setOutOrderNo(item.getOrderId())
.setDetailName(item.getPlanDetailName());
easyLearnOrderDetails.add(easyLearnOrderDetail);
});
SpringUtils.getBean(EasyLearnOrderDetailService.class).saveBatch(easyLearnOrderDetails);
//支付分拓展
EasyLearnOrderExtend orderExtend = new EasyLearnOrderExtend();
orderExtend.setOrderId(orderId)
.setPlanId(result.getPlanId())
.setSignPlanId(result.getSignPlanId())
.setSubMchId(result.getSubMchid())
.setExtendStatus(0)
.setGoingDetailNo(0);
SpringUtils.getBean(EasyLearnOrderExtendService.class).save(orderExtend);
//云办卡
CloudClassCardDto dto = new CloudClassCardDto();
if (StringUtils.equals("prod", SpringUtils.getActiveProfile())) {
dto.setTemplateUrl(PROD_TEMPLATE_URL);
} else if (StringUtils.equals("test", SpringUtils.getActiveProfile())){
dto.setTemplateUrl(TEST_TEMPLATE_URL);
} else {
dto.setTemplateUrl(LOCAL_TEMPLATE_URL);
}
// 办卡
dto.setOpenId(result.getSubOpenid());
dto.setMerchantSignPlanNo(result.getMerchantSignPlanNo());
dto.setSignPlanId(result.getSignPlanId());
dto.setOrderCloudId(easyLearnOrder.getTemplateId());
StoreExtend storeExtend = SpringUtils.getBean(StoreExtendService.class).queryChain()
.where(STORE_EXTEND.STORE_ID.eq(easyLearnOrder.getStoreId()))
.one();
dto.setStoreCloudId(storeExtend.getStoreCloudId());
dto.setCustomerPhone(easyLearnOrder.getCustomerPhone());
dto.setCustomerName(easyLearnOrder.getCustomerName());
dto.setPlanId(result.getPlanId());
dto.setSignPlanDetails(JSONArray.toJSONString(result.getSignedDetailList()));
//获取计划
Row payScorePlan = DbChain.table(WX_PAY_SCORE.getTableName()).select(WX_PAY_SCORE.CLASS_HOUR).where(WX_PAY_SCORE.OUT_PLAN_ID.eq(result.getPlanId())).one();
//获取支付分
if (payScorePlan != null && StringUtils.isNotBlank(payScorePlan.getString("classHour"))) {
dto.setClassHour(payScorePlan.getString("classHour"));
}
String cloudCardId = SpringUtils.getBean(CloudClassCardHandler.class).insertCloudClassCard(dto);
easyLearnOrder.setProductId(cloudCardId);
this.updateById(easyLearnOrder);
} else if (StringUtils.equals("PAYSCORE.USER_CANCEL_SIGN_PLAN", payScoreNotifyData.getEventType())){
//取消合约
easyLearnOrder.setOrderStatus(2);
this.updateById(easyLearnOrder);
//批量修改订单详情状态
SpringUtils.getBean(EasyLearnOrderDetailService.class).updateChain()
.set(EASY_LEARN_ORDER_DETAIL.DETAIL_STATUS, 3)
.where(EASY_LEARN_ORDER_DETAIL.ORDER_ID.eq(easyLearnOrder.getId()))
.and(EASY_LEARN_ORDER_DETAIL.DETAIL_STATUS.eq(0))
.update();
//通知波哥取消课卡
CloudClassCardDto cloudClassCardDto = new CloudClassCardDto();
cloudClassCardDto.setSignPlanId(result.getSignPlanId());
cloudClassCardDto.setMerchantSignPlanNo(result.getMerchantSignPlanNo());
SpringUtils.getBean(CloudClassCardHandler.class).refundCloudClassCard(cloudClassCardDto);
}
} catch (WxPayException e) {
throw new ServiceException(e.getMessage());
}
}
/**
* 创建用户服务订单(核销)
* @author DB
* @since 2024/1/20
* @param bo 请求参数
* @return WxPartnerPayScoreSignPlanResult
*/
@Override
@Transactional(rollbackFor = Exception.class)
public WxPartnerPayScoreSignPlanResult createServiceOrder(LearnNowPayLaterServiceOrderBo bo) {
//分布式锁进行幂等处理
RedisService redisService = SpringUtils.getBean(RedisService.class);
//分布式锁进行幂等处理
Lock userIdLock = redisService.distributedLock(JamboxRedisConstant.LEARN_NOW_PAY_LATER_SERVICE_ORDER_LOCK_USER_PAY + bo.getSignPlanId());
if (userIdLock.tryLock()) {
try {
EasyLearnOrder easyLearnOrder = this.queryChain().where(EASY_LEARN_ORDER.OUT_ORDER_NO.eq(bo.getSignPlanId())).one();
EasyLearnOrderDetailService easyLearnOrderDetailService = SpringUtils.getBean(EasyLearnOrderDetailService.class);
EasyLearnOrderDetail easyLearnOrderDetail = easyLearnOrderDetailService.queryChain()
.where(EASY_LEARN_ORDER_DETAIL.ORDER_ID.eq(easyLearnOrder.getId()))
.and(EASY_LEARN_ORDER_DETAIL.PERIOD_NO.eq(bo.getPlanDetailNo()))
.one();
//获取计划拓展
EasyLearnOrderExtend orderExtend = SpringUtils.getBean(EasyLearnOrderExtendService.class).queryChain()
.where(EASY_LEARN_ORDER_EXTEND.ORDER_ID.eq(easyLearnOrder.getId()))
.one();
WxPayService wxPayService = wxPayHandler.getWxPayService(null, orderExtend.getSubMchId());
PartnerPayScoreSignPlanService partnerPayScoreSignPlanService = wxPayService.getPartnerPayScoreSignPlanService();
WxPartnerPayScoreSignPlanRequest signPlanRequest = new WxPartnerPayScoreSignPlanRequest();
signPlanRequest.setSignPlanId(easyLearnOrder.getOutOrderNo())
.setPlanDetailNo(easyLearnOrderDetail.getPeriodNo())
.setSubMchid(orderExtend.getSubMchId())
.setSubOpenid(bo.getOpenid())
.setNotifyUrl(wxPayConfiguration.getProperties().getLearnNowPayLaterServiceOrderNotifyUrl())
.setServiceIntroduction(easyLearnOrderDetail.getDetailDesc());
TimeRange timeRange = new TimeRange();
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter yyyyMMddHHmmss = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
String startTime = now.plusSeconds(10).format(yyyyMMddHHmmss);
timeRange.setStartTime(startTime);
String endTime = now.plusSeconds(60).format(yyyyMMddHHmmss);
timeRange.setEndTime(endTime);
signPlanRequest.setTimeRange(timeRange).setOutOrderNo(easyLearnOrderDetail.getId());
easyLearnOrderDetail.setDetailStatus(1);
easyLearnOrderDetailService.updateById(easyLearnOrderDetail);
try {
return partnerPayScoreSignPlanService.signPlanServiceOrder(signPlanRequest);
} catch (WxPayException e) {
throw new ServiceException(e.getMessage());
}
} finally {
//释放锁
userIdLock.unlock();
}
} else {
//获取锁失败直接返回空
throw new ServiceException("请勿重复提交");
}
}
/**
* 支付分用户核销成功回调
* @author DB
* @since 2024/1/20
* @param notifyData 返回数据
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void userServiceOrderSuccess(String notifyData) {
try {
WxPayOrderNotifyResult notifyResult = wxPayHandler.getWxPayService().parseOrderNotifyResult(notifyData);
EasyLearnOrderDetailService easyLearnOrderDetailService = SpringUtils.getBean(EasyLearnOrderDetailService.class);
EasyLearnOrderDetail easyLearnOrderDetail = easyLearnOrderDetailService.queryChain()
.where(EASY_LEARN_ORDER_DETAIL.ORDER_ID.eq(notifyResult.getOutTradeNo()))
.and(EASY_LEARN_ORDER_DETAIL.OUT_ORDER_NO.eq(notifyResult.getTransactionId()))
.one();
EasyLearnOrder easyLearnOrder = this.getById(easyLearnOrderDetail.getOrderId());
//需要分账
String subMchId = notifyResult.getSubMchId();
if (notifyResult.getTotalFee() >= Math.ceil(1 / OrderSource.EASY_LEARN.getRate())) {
//设置子商户
WxPayService wxPayService = wxPayHandler.getWxPayService(null, subMchId);
wxPayAsyncTask.asyncWxPayProfitSharing(notifyResult.getOutTradeNo(), notifyResult, wxPayService, OrderSource.LEARN_NOW_PAY_LATER);
}
BigDecimal payAmount = new BigDecimal(notifyResult.getTotalFee()).divide(BigDecimal.valueOf(100));
easyLearnOrderDetail.setDetailStatus(2)
.setActualPrice(payAmount);
easyLearnOrderDetailService.updateById(easyLearnOrderDetail);
//修改订单实际支付金额
easyLearnOrder.setTotalPayAmount(easyLearnOrder.getTotalPayAmount() == null ? payAmount : easyLearnOrder.getTotalPayAmount().add(payAmount));
this.updateById(easyLearnOrder);
} catch (WxPayException e) {
throw new ServiceException(e.getMessage());
}
}
/**
* 取消用户签约计划
* @author DB
* @since 2024/1/20
* @param bo 请求参数
*/
@Override
public void stopUserSignPlans(LearnNowPayLaterStopUserSignPlansBo bo) {
EasyLearnOrder easyLearnOrder = this.queryChain().where(EASY_LEARN_ORDER.OUT_ORDER_NO.eq(bo.getSignPlanId())).one();
String subMchId = wxPayHandler.getSubMchId(easyLearnOrder.getBrandId(), easyLearnOrder.getStoreId());
WxPayService wxPayService = wxPayHandler.getWxPayService(null, subMchId);
try {
wxPayService.getPartnerPayScoreSignPlanService().stopUserSignPlans(easyLearnOrder.getId(), subMchId, bo.getStopReason());
//取消合约
easyLearnOrder.setOrderStatus(2);
this.updateById(easyLearnOrder);
//批量修改订单详情状态
SpringUtils.getBean(EasyLearnOrderDetailService.class).updateChain()
.set(EASY_LEARN_ORDER_DETAIL.DETAIL_STATUS, 3)
.where(EASY_LEARN_ORDER_DETAIL.ORDER_ID.eq(easyLearnOrder.getId()))
.and(EASY_LEARN_ORDER_DETAIL.DETAIL_STATUS.eq(0))
.update();
//获取拓展信息
EasyLearnOrderExtend easyLearnOrderExtend = SpringUtils.getBean(EasyLearnOrderExtendService.class).queryChain()
.where(EASY_LEARN_ORDER_EXTEND.ORDER_ID.eq(easyLearnOrder.getId()))
.one();
//通知波哥取消课卡
CloudClassCardDto cloudClassCardDto = new CloudClassCardDto();
cloudClassCardDto.setSignPlanId(easyLearnOrderExtend.getSignPlanId());
cloudClassCardDto.setMerchantSignPlanNo(easyLearnOrder.getId());
SpringUtils.getBean(CloudClassCardHandler.class).refundCloudClassCard(cloudClassCardDto);
} catch (WxPayException e) {
throw new ServiceException(e.getMessage());
}
}
}

View File

@ -0,0 +1,135 @@
package com.cpop.jambox.business.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-22 10:40
*/
@Data
@Accessors(chain = true)
@ApiModel("课卡模板信息")
public class CardTemplateInfoVo {
/**
* 主键
*/
@ApiModelProperty(value = "主键")
private String id;
/**
* 旧课卡模板id
*/
@ApiModelProperty(value = "旧课卡模板id")
private String oldTemplateId;
/**
* 云品牌id
*/
@ApiModelProperty(value = "云品牌id")
private String brandCloudId;
/**
* 云校区id
*/
@ApiModelProperty(value = "云校区id")
private String storeCloudId;
/**
* 模板名
*/
@NotBlank(message = "模板名不能为空")
@ApiModelProperty(value = "模板名",required = true)
private String name;
/**
* 有效日期数
*/
@ApiModelProperty(value = "有效日期数")
private Integer validDay;
/**
* 结束日期
*/
@ApiModelProperty(value = "结束日期")
private LocalDate endDate;
/**
* 价格
*/
@NotNull(message = "价格不能为空")
@ApiModelProperty(value = "价格")
private BigDecimal price;
/**
* 课时
*/
@ApiModelProperty("课时")
private Integer classNumber;
/**
* 周预约数
*/
@ApiModelProperty(value = "周预约数")
private Integer weekAppointment;
/**
* 日预约数
*/
@ApiModelProperty(value = "日预约数")
private Integer dayAppointment;
/**
* 缓冲天数
*/
@ApiModelProperty(value = "缓冲天数")
private Integer bufferDay;
/**
* 模板类型(0:课时卡,1:时限卡,2:储值卡)
*/
@ApiModelProperty(value = "模板类型(0:课时卡,1:时限卡,2:储值卡)")
private Integer templateType;
/**
* 使用范围
*/
@ApiModelProperty(value = "使用范围(旧Type字段)")
private String scopeUse;
/**
* 支付类型(0:微信支付;1:先学后付次付;2:旧放心学合约支付;3:数字人民币支付;4:线下支付;5:先学后付月付;)
*/
@NotEmpty(message = "支付类型不能为空")
@ApiModelProperty(value = "支付类型(0:微信支付;1:先学后付次付;2:旧放心学合约支付;3:数字人民币支付;4:线下支付;5:先学后付月付;)")
private List<Integer> payType;
/**
* 是否是会员(0否1是)
*/
@ApiModelProperty(value = "是否是会员(0否1是)")
private Boolean isMember;
/**
* 是否是引流卡
*/
@ApiModelProperty(value = "是否是引流卡(0否1是)")
private Boolean isDrainage;
/**
* 二维码
*/
@ApiModelProperty(value = "二维码")
private String qrCode;
}

View File

@ -0,0 +1,55 @@
package com.cpop.jambox.business.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-08 9:54
*/
@Data
@ApiModel(value = "先学后付计划详情")
public class LearnNowPayLaterPlanDetailVo {
/**
* 计划明细优惠说明
*/
@ApiModelProperty("计划明细优惠说明")
private String planDiscountDescription;
/**
* 计划明细原支付金额(单位分)
*/
@ApiModelProperty("计划明细原支付金额(单位分)")
private BigDecimal originalPrice;
public void setOriginalPrice(Integer originalPrice) {
this.originalPrice = new BigDecimal(originalPrice).divide(BigDecimal.valueOf(100));
}
/**
* 计划明细实际支付金额(单位分)
*/
@ApiModelProperty("计划明细实际支付金额(单位分)")
private BigDecimal actualPrice;
public void setActualPrice(Long actualPrice) {
this.actualPrice = new BigDecimal(actualPrice).divide(BigDecimal.valueOf(100));
}
/**
* 计划明细名称
*/
@ApiModelProperty("计划明细名称")
private String planDetailName;
/**
* 签约计划编号
*/
@ApiModelProperty("签约计划编号")
private Integer planDetailNo;
}

View File

@ -0,0 +1,70 @@
package com.cpop.jambox.business.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-05 16:13
*/
@Data
@ApiModel("先学后付计划")
public class LearnNowPayLaterPlanVo {
/**
* 主键
*/
@ApiModelProperty("计划分主键")
private String id;
/**
* 支付分计划名称
*/
@ApiModelProperty("支付分计划名称")
private String planName;
/**
* 支付分计划有效期(单位天)
*/
@ApiModelProperty("支付分计划有效期(单位天)")
private Integer planDuration;
/**
* 支付分计划扣费次数
*/
@ApiModelProperty("支付分计划扣费次数")
private Integer deductionQuantity;
/**
* 支付分计划原总金额(单位分)
*/
@ApiModelProperty("支付分计划原总金额")
private BigDecimal totalOriginalPrice;
public void setTotalOriginalPrice(Integer totalOriginalPrice) {
this.totalOriginalPrice = new BigDecimal(totalOriginalPrice).divide(BigDecimal.valueOf(100));
}
/**
* 支付分计划实际扣费总金额(单位分)
*/
@ApiModelProperty("支付分计划实际扣费总金额(单位分)")
private BigDecimal totalActualPrice;
public void setTotalActualPrice(Integer totalActualPrice) {
this.totalActualPrice = new BigDecimal(totalActualPrice).divide(BigDecimal.valueOf(100));
}
/**
* 支付分计划明细列表
*/
@ApiModelProperty("支付分计划明细列表")
private List<LearnNowPayLaterPlanDetailVo> planDetailList;
}

View File

@ -11,4 +11,15 @@ public interface JamboxRedisConstant {
* 一次性支付
*/
String ONCE_PAY_LOCK_USER_PAY = "jambox:oncePayLock:userPay:";
/**
* 先学后付创建计划
*/
String LEARN_NOW_PAY_LATER_CREATE_USER_PLANS_LOCK_USER_PAY = "jambox:learnNowPayLaterCreateUserPlansLock:userPay:";
/**
* 先学后付用户核销
*/
String LEARN_NOW_PAY_LATER_SERVICE_ORDER_LOCK_USER_PAY = "jambox:learnNowPayLaterServiceOrderLock:userPay:";
}

View File

@ -0,0 +1,124 @@
package com.cpop.jambox.framework.tasks;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.utils.SpringUtils;
import com.cpop.jambox.business.bo.LearnNowPayLaterPlanBo;
import com.cpop.jambox.business.entity.CardTemplate;
import com.cpop.jambox.business.entity.CardTemplateExtend;
import com.cpop.jambox.business.service.CardTemplateExtendService;
import com.cpop.pay.framewok.config.wxPay.WxPayConfiguration;
import com.cpop.pay.framewok.handler.wxPay.WxPayHandler;
import com.cpop.system.business.entity.WxPayScore;
import com.cpop.system.business.entity.WxPayScoreDetail;
import com.cpop.system.business.service.WxPayScoreDetailService;
import com.cpop.system.business.service.WxPayScoreService;
import com.github.binarywang.wxpay.bean.payscore.PayScorePlanDetailRequest;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreSignPlanRequest;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreSignPlanResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.PartnerPayScoreSignPlanService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.mybatisflex.core.datasource.DataSourceKey;
import com.mybatisflex.core.row.DbChain;
import com.mybatisflex.core.row.Row;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
import static com.cpop.system.business.entity.table.WxPayScoreTableDef.WX_PAY_SCORE;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-17 18:18
*/
@Component
@Slf4j
public class LearnNowPayLaterTask {
@Autowired
private WxPayHandler wxPayHandler;
@Autowired
private WxPayConfiguration wxPayConfiguration;
/**
* 异步创建先学后付计划
* @author DB
* @since 2024/1/17
* @param cardTemplate 课卡模板
* @param payType 支付类型
*/
@Async("customAsyncThreadPool")
@Transactional(rollbackFor = Exception.class)
public void asyncCreateLearnNowPayLaterPlan(CardTemplate cardTemplate, LearnNowPayLaterPlanBo bo, Integer payType) {
String subMchId = wxPayHandler.getSubMchId(cardTemplate.getBrandId(), cardTemplate.getStoreId());
//录入计划与详情
WxPayScore wxPayScore = BeanUtils.mapToClass(bo, WxPayScore.class);
wxPayScore.setSignAccount(subMchId).setClassHour(bo.getClassHour());
WxPayScoreService wxPayScoreService = SpringUtils.getBean(WxPayScoreService.class);
wxPayScoreService.save(wxPayScore);
//创建计划
WxPayService wxPayService = wxPayHandler.getWxPayService(null, subMchId);
PartnerPayScoreSignPlanService partnerPayScoreSignPlanService = wxPayService.getPartnerPayScoreSignPlanService();
WxPartnerPayScoreSignPlanRequest planRequest = BeanUtils.mapToClass(bo,WxPartnerPayScoreSignPlanRequest.class);
List<PayScorePlanDetailRequest> payScorePlanDetailRequests = BeanUtils.mapToList(bo.getPlanDetailList(), PayScorePlanDetailRequest.class);
planRequest.setAppid(wxPayConfiguration.getProperties().getServiceAppId());
planRequest.setSubMchid(subMchId);
planRequest.setPlanDetailList(payScorePlanDetailRequests);
planRequest.setMerchantPlanNo(wxPayScore.getId());
WxPartnerPayScoreSignPlanResult result;
CardTemplateExtendService cardTemplateExtendService = SpringUtils.getBean(CardTemplateExtendService.class);
//设置商户侧计划
try {
result = partnerPayScoreSignPlanService.createPlans(planRequest);
} catch (WxPayException e) {
//删除计划开通
try {
//查询旧表
DataSourceKey.use("jambox");
Row oldTemplate = DbChain.table("t_card_template")
.select("template_id as oldTemplateId")
.select("pay_type as payTypes")
.from("t_card_template")
.where("template_id = ?", cardTemplate.getOldTemplateId())
.one();
//移除
List<String> payTypes = Arrays.asList(oldTemplate.getString("payTypes").split(","));
payTypes.remove(payType.toString());
DbChain.table("t_card_template")
.set("pay_type", StringUtils.join(payTypes, ","))
.where("template_id = ?", cardTemplate.getOldTemplateId())
.update();
} finally {
DataSourceKey.clear();
}
throw new ServiceException(e.getMessage());
}
List<WxPayScoreDetail> wxPayScoreDetails = BeanUtils.mapToList(result.getPlanDetailList(), WxPayScoreDetail.class);
wxPayScoreDetails.forEach(item -> {
item.setSysWxPayScoreId(wxPayScore.getId());
});
//批量保存计划详情
SpringUtils.getBean(WxPayScoreDetailService.class).saveBatch(wxPayScoreDetails);
//更新外部计划id
wxPayScoreService.updateChain()
.set(WX_PAY_SCORE.OUT_PLAN_ID,result.getPlanId())
.where(WX_PAY_SCORE.ID.eq(wxPayScore.getId()))
.update();
//模板拓展
CardTemplateExtend cardTemplateExtend = new CardTemplateExtend();
cardTemplateExtend.setTemplateId(cardTemplate.getId())
.setExtendId(wxPayScore.getId())
.setExtendParamOne("1")
.setPayType(payType);
cardTemplateExtendService.save(cardTemplateExtend);
}
}

View File

@ -0,0 +1,7 @@
<?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.cpop.jambox.business.mapper.CardTemplateExtendMapper">
</mapper>

View File

@ -8,9 +8,9 @@ cpop:
gateway:
rsa-keypair:
# 公钥文件
publicKeyFile: E:\Cpop\Cpop-Union\Cpop-Core\src\main\resources\static\keyPair\publicKey
publicKeyFile: E:\Cpop\Cpop-Union\Cpop-Mall\Cpop-Mall-Web\src\main\resources\static\keyPair\publicKey
# 公钥文件
privateKeyFile: E:\Cpop\Cpop-Union\Cpop-Core\src\main\resources\static\keyPair\privateKey
privateKeyFile: E:\Cpop\Cpop-Union\Cpop-Mall\Cpop-Mall-Web\src\main\resources\static\keyPair\privateKey
# DataSource Config
spring:
@ -38,6 +38,7 @@ spring:
max-active: 8
#
max-wait: -1ms
client-type: jedis
data:
mongodb:
host: localhost
@ -55,10 +56,9 @@ mybatis-flex:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
datasource:
mall:
#url: jdbc:mysql://sh-cynosdbmysql-grp-fggo83js.sql.tencentcdb.com:20965/cpop_test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
url: jdbc:mysql://sh-cynosdbmysql-grp-fggo83js.sql.tencentcdb.com:20965/cpop_union?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
url: jdbc:mysql://localhost:3306/cpop_dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: Customer0401
password: Admin@123
jambox:
url: jdbc:mysql://sh-cynosdbmysql-grp-fggo83js.sql.tencentcdb.com:20965/jambox_test?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
username: root

View File

@ -38,6 +38,7 @@ spring:
max-active: 8
#
max-wait: -1ms
client-type: jedis
data:
mongodb:
host: localhost

View File

@ -39,6 +39,7 @@ spring:
max-active: 8
#
max-wait: -1ms
client-type: jedis
data:
mongodb:
host: localhost

View File

@ -39,6 +39,7 @@ spring:
max-active: 8
#
max-wait: -1ms
client-type: jedis
data:
mongodb:
host: localhost

View File

@ -31,7 +31,7 @@ spring:
max-file-size: 1024MB
max-request-size: 300MB
profiles:
active: dev,core,mall,system
active: dev,mall,core,jambox,system,pay
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver

View File

@ -26,7 +26,9 @@ class CpopMallWebApplicationTests {
*/
@Test
public void initKeyPair() {
Map<String, String> keyPairMap = rsaUtils.initKeyPair();
String publicFileUrl = "E:\\Cpop\\Cpop-Union\\Cpop-Mall\\Cpop-Mall-Web\\src\\main\\resources\\static\\keyPair\\publicKey";
String privateFileUrl = "E:\\Cpop\\Cpop-Union\\Cpop-Mall\\Cpop-Mall-Web\\src\\main\\resources\\static\\keyPair\\privateKey";
Map<String, String> keyPairMap = rsaUtils.initKeyPair(publicFileUrl,privateFileUrl);
String publicKey = keyPairMap.get("publicKey");
String privateKey = keyPairMap.get("privateKey");
System.out.println("公钥:");

View File

@ -51,19 +51,18 @@ public class CpopWxPayTests {
WxPayRefundV3Request.Amount amount = new WxPayRefundV3Request.Amount();
//退款金额(单位分)
//int refund = order.getTotalAmount().scaleByPowerOfTen(2).intValue();
int refund = 101;
int refund = 1;
amount.setRefund(refund)
.setTotal(refund)
.setCurrency("CNY");
request.setSubMchid(wxPayService.getConfig().getSubMchId())
.setTransactionId("4200002126202312283733408828")
.setOutTradeNo("97945790336548864")
request.setTransactionId("4200002122202401129346519359")
//.setOutTradeNo("1000000000202401121937112562856")
//.setTransactionId(order.getOutOrderNo())
//.setOutTradeNo(order.getId())
.setNotifyUrl(wxPayProperties.getNotifyRefund())
.setOutRefundNo(IdUtils.fastSimpleUUID())
.setSubMchid("1661323640")
.setReason("一次性支付退款")
.setReason("测试退款")
.setAmount(amount);
WxPayRefundV3Result result = wxPayService.refundV3(request);
System.out.println(result);
@ -163,7 +162,7 @@ public class CpopWxPayTests {
*/
@Test
public void getProfitSharingResult() throws WxPayException {
ProfitSharingV3Result profitSharingV3Result = wxPayService.getProfitSharingService().profitSharingQueryV3("1714609621691420672", "4200002015202310186547802213", "1650816616");
ProfitSharingV3Result profitSharingV3Result = wxPayService.getProfitSharingService().profitSharingQueryV3("1745800085756895232", "4200002127202401122097980590", "1661323640");
System.out.println(profitSharingV3Result);
}
@ -174,8 +173,8 @@ public class CpopWxPayTests {
@Test
public void profitSharingFinish() throws WxPayException {
ProfitSharingUnfreezeRequest profitSharingFinishRequest = new ProfitSharingUnfreezeRequest();
profitSharingFinishRequest.setTransactionId("4200002093202312282215936862");
profitSharingFinishRequest.setOutOrderNo("97973671418667008");
profitSharingFinishRequest.setTransactionId("4200002122202401129346519359");
profitSharingFinishRequest.setOutOrderNo("1745820005743910912");
profitSharingFinishRequest.setDescription("结束分账");
profitSharingFinishRequest.setSubMchId("1661323640");
wxPayService.getProfitSharingService().profitSharingFinish(profitSharingFinishRequest);

View File

@ -27,6 +27,10 @@
<groupId>com.cpop</groupId>
<artifactId>Cpop-Jambox</artifactId>
</dependency>
<dependency>
<groupId>com.cpop</groupId>
<artifactId>Cpop-Pay</artifactId>
</dependency>
</dependencies>

View File

@ -0,0 +1,55 @@
package com.cpop.mall.business.bo;
import com.mybatisflex.annotation.Id;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-15 13:44
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "商城轮播图对象")
public class CarouselBo {
/**
* 主键
*/
@ApiModelProperty(value = "主键")
private String id;
/**
* 产品id
*/
@NotBlank(message = "产品id不能为空")
@ApiModelProperty(value = "产品id",required = true)
private String productId;
/**
* 图片地址
*/
@ApiModelProperty(value = "图片地址",required = true)
@NotBlank(message = "图片地址不能为空")
private String picUrl;
/**
* 排序
*/
@NotNull(message = "排序不能为空")
@ApiModelProperty(value = "排序",required = true)
private Integer orderNo;
/**
* 上架状态(0下架;1上架)
*/
@NotNull(message = "上架状态不能为空")
@ApiModelProperty(value = "上架状态(0下架;1上架)",required = true)
private Boolean upStatus;
}

View File

@ -0,0 +1,135 @@
package com.cpop.mall.business.controller.backstage;
import com.alibaba.fastjson.JSONObject;
import com.cpop.core.base.R;
import com.cpop.core.utils.SecurityUtils;
import com.cpop.core.utils.SpringUtils;
import com.cpop.mall.business.bo.CarouselBo;
import com.cpop.mall.business.service.ProductService;
import com.cpop.mall.business.vo.CarouselPageVo;
import com.cpop.mall.business.vo.ProductInfoVo;
import com.cpop.mall.business.vo.ProductSimpleVo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import com.cpop.mall.business.entity.Carousel;
import com.cpop.mall.business.service.CarouselService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import java.io.Serializable;
import java.util.List;
import static com.cpop.mall.business.entity.table.CarouselTableDef.CAROUSEL;
import static com.cpop.mall.business.entity.table.ProductTableDef.PRODUCT;
/**
* 商城轮播图 控制层
*
* @author DB
* @since 2024-01-15
*/
@RestController
@Api(tags = "商城轮播图接口")
@RequestMapping("/carousel")
public class BackstageCarouselController {
@Autowired
private CarouselService carouselService;
/**
* 分页查询商城轮播图
* @author DB
* @since 2024/1/15
* @param upStatus 上架状态
* @return R<Page<CarouselPageVo>>
*/
@GetMapping("/getCarouselPage")
@ApiOperation("分页查询商城轮播图")
public R<Page<CarouselPageVo>> getCarouselPage(@ApiParam("上架状态") @RequestParam(value = "upStatus", required = false) Boolean upStatus) {
Page<CarouselPageVo> page = carouselService.getCarouselPage(upStatus);
return R.ok(page);
}
/**
* 新增轮播图
* @author DB
* @since 2024/1/15
* @param bo 请求参数
* @return R<Void>
*/
@PostMapping("/insertCarousel")
@ApiOperation("新增商城轮播图")
public R<Void> insertCarousel(@RequestBody CarouselBo bo) {
carouselService.insertCarousel(bo);
return R.ok();
}
/**
* 更新轮播图
*
* @param bo 请求参数
* @return R<Void>
* @author DB
* @since 2024/1/15
*/
@PutMapping("/updateCarousel")
@ApiOperation("修改商城轮播图")
public R<Void> updateCarousel(@RequestBody CarouselBo bo) {
carouselService.updateCarousel(bo);
return R.ok();
}
/**
* 轮播图上下架
* @param id 主键
* @return R<Void>
* @author DB
* @since 2024/1/15
*/
@PutMapping("/carouselUnmount/{id}")
@ApiOperation("轮播图上下架")
public R<Void> carouselUnmount(@PathVariable String id) {
carouselService.updateChain()
.setRaw(CAROUSEL.UP_STATUS, "if(up_status = 0, 1, 0)")
.where(CAROUSEL.ID.eq(id))
.update();
return R.ok();
}
/**
* 删除轮播图
*
* @param id 主键
* @return R<Void>
* @author DB
* @since 2024/1/15
*/
@DeleteMapping("/removeCarouselById/{id}")
@ApiOperation("删除轮播图")
public R<Void> removeCarouselById(@PathVariable String id) {
carouselService.updateChain().where(CAROUSEL.ID.eq(id)).remove();
return R.ok();
}
/**
* 获取上架商品
* @author DB
* @since 2024/1/15
* @param brandId 品牌id
* @return R<List<ProductSimpleVo>>
*/
@GetMapping("/getUpProductList")
@ApiOperation("获取上架商品")
public R<List<ProductSimpleVo>> getUpProductList() {
JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
List<ProductSimpleVo> productSimpleVos = SpringUtils.getBean(ProductService.class).listAs(QueryWrapper.create()
.select(PRODUCT.ID, PRODUCT.PRODUCT_NAME)
.where(PRODUCT.BRAND_ID.eq(loginUserInfo.getString("brandId")))
.and(PRODUCT.IS_UP.eq(true))
, ProductSimpleVo.class);
return R.ok(productSimpleVos);
}
}

View File

@ -1,9 +1,12 @@
package com.cpop.mall.business.controller.mini;
import com.alibaba.fastjson.JSONObject;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.core.base.R;
import com.cpop.core.utils.SecurityUtils;
import com.cpop.core.utils.SpringUtils;
import com.cpop.mall.business.bo.ProductPageBo;
import com.cpop.mall.business.service.CarouselService;
import com.cpop.mall.business.service.ProductService;
import com.cpop.mall.business.vo.*;
import com.cpop.system.business.entity.Store;
@ -12,12 +15,15 @@ import com.mybatisflex.core.paginate.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
import static com.cpop.mall.business.entity.table.CarouselTableDef.CAROUSEL;
/**
* 商城-商品表 控制层
*
@ -32,6 +38,9 @@ public class MiniProductController {
@Autowired
private ProductService productService;
@Autowired
private CarouselService carouselService;
/**
* @descriptions 分页查询商城-商品
* @author DB
@ -117,4 +126,18 @@ public class MiniProductController {
return R.ok(info);
}
/**
* 获取商城轮播图
* @author DB
* @since 2024/1/15
* @return R<List<CarouselListVo>>
*/
@GetMapping("/getCarouselList")
@ApiOperation("获取商城轮播图")
public R<List<CarouselListVo>> getCarouselList() {
JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
List<CarouselListVo> vos = carouselService.queryChain().where(CAROUSEL.BRAND_ID.eq(loginUserInfo.getString("brandId"))
.and(CAROUSEL.UP_STATUS.eq(true))).orderBy(CAROUSEL.ORDER_NO.asc()).listAs(CarouselListVo.class);
return R.ok(vos);
}
}

View File

@ -0,0 +1,74 @@
package com.cpop.mall.business.entity;
import com.cpop.core.base.entity.BaseEntity;
import com.cpop.core.base.entity.BaseInsertListener;
import com.cpop.core.base.entity.BaseUpdateListener;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.Accessors;
/**
* 商城轮播图 实体类
*
* @author DB
* @since 2024-01-15
*/
@Data
@EqualsAndHashCode(callSuper=false)
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@Table(value = "cp_mall_carousel", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false)
public class Carousel extends BaseEntity implements Serializable {
/**
* 主键
*/
@Id
private String id;
/**
* 产品id
*/
@Id
private String productId;
/**
* 品牌id
*/
@Id
private String brandId;
/**
* 图片地址
*/
private String picUrl;
/**
* 排序
*/
private Integer orderNo;
/**
* 上架状态(0下架;1上架)
*/
private Boolean upStatus;
/**
* 逻辑删除0否1是
*/
@Column(isLogicDelete = true)
private Boolean isDelete;
}

View File

@ -0,0 +1,14 @@
package com.cpop.mall.business.mapper;
import com.mybatisflex.core.BaseMapper;
import com.cpop.mall.business.entity.Carousel;
/**
* 商城轮播图 映射层
*
* @author DB
* @since 2024-01-15
*/
public interface CarouselMapper extends BaseMapper<Carousel> {
}

View File

@ -0,0 +1,41 @@
package com.cpop.mall.business.service;
import com.cpop.mall.business.bo.CarouselBo;
import com.cpop.mall.business.vo.CarouselPageVo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
import com.cpop.mall.business.entity.Carousel;
/**
* 商城轮播图 服务层
*
* @author DB
* @since 2024-01-15
*/
public interface CarouselService extends IService<Carousel> {
/**
* 分页查询商城轮播图
* @author DB
* @since 2024/1/15
* @param upStatus 上架状态
* @return Page<CarouselPageVo>
*/
Page<CarouselPageVo> getCarouselPage(Boolean upStatus);
/**
* 新增轮播图
* @author DB
* @since 2024/1/15
* @param bo 请求参数
*/
void insertCarousel(CarouselBo bo);
/**
* 修改轮播图
* @author DB
* @since 2024/1/15
* @param bo 请求参数
*/
void updateCarousel(CarouselBo bo);
}

View File

@ -0,0 +1,79 @@
package com.cpop.mall.business.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.core.base.entity.PageDomain;
import com.cpop.core.utils.SecurityUtils;
import com.cpop.core.utils.sql.SqlUtils;
import com.cpop.mall.business.bo.CarouselBo;
import com.cpop.mall.business.vo.CarouselPageVo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.cpop.mall.business.entity.Carousel;
import com.cpop.mall.business.mapper.CarouselMapper;
import com.cpop.mall.business.service.CarouselService;
import org.springframework.stereotype.Service;
import static com.cpop.mall.business.entity.table.CarouselTableDef.CAROUSEL;
import static com.cpop.mall.business.entity.table.ProductTableDef.PRODUCT;
/**
* 商城轮播图 服务层实现
*
* @author DB
* @since 2024-01-15
*/
@Service("carouselService")
public class CarouselServiceImpl extends ServiceImpl<CarouselMapper, Carousel> implements CarouselService {
/**
* 分页查询商城轮播图
* @author DB
* @since 2024/1/15
* @param upStatus 上架状态
* @return Page<CarouselPageVo>
*/
@Override
public Page<CarouselPageVo> getCarouselPage(Boolean upStatus) {
JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
return this.pageAs(Page.of(pageDomain.getPageNum(), pageDomain.getPageSize()),
QueryWrapper.create()
.select(CAROUSEL.ID,CAROUSEL.PRODUCT_ID,CAROUSEL.PIC_URL,CAROUSEL.ORDER_NO,CAROUSEL.UP_STATUS)
.select(PRODUCT.PRODUCT_NAME)
.leftJoin(PRODUCT).on(PRODUCT.ID.eq(CAROUSEL.PRODUCT_ID))
.where(CAROUSEL.BRAND_ID.eq(loginUserInfo.getString("brandId")))
.and(CAROUSEL.UP_STATUS.eq(upStatus))
.orderBy(CAROUSEL.ORDER_NO.asc()),
CarouselPageVo.class);
}
/**
* 新增轮播图
* @author DB
* @since 2024/1/15
* @param bo 请求参数
*/
@Override
public void insertCarousel(CarouselBo bo) {
JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
Carousel carousel = BeanUtils.mapToClass(bo, Carousel.class);
carousel.setBrandId(loginUserInfo.getString("brandId"));
this.save(carousel);
}
/**
* 修改轮播图
* @author DB
* @since 2024/1/15
* @param bo 请求参数
*/
@Override
public void updateCarousel(CarouselBo bo) {
JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
Carousel carousel = BeanUtils.mapToClass(bo, Carousel.class);
carousel.setBrandId(loginUserInfo.getString("brandId"));
this.updateById(carousel);
}
}

View File

@ -87,6 +87,7 @@ public class OrderRefundServiceImpl extends ServiceImpl<OrderRefundMapper, Order
profitSharingReturnRequest.setDescription("分账退款");
profitSharingReturnRequest.setSubMchId(profitSharing.getPayAccount());
profitSharingReturnRequest.setReturnAccount(wxPayProperties.getSharingAccount());
profitSharingReturnRequest.setReturnAccountType("MERCHANT_ID");
profitSharingReturnRequest.setReturnAmount(profitSharing.getAmount().intValue());
wxPayService.getProfitSharingService().profitSharingReturn(profitSharingReturnRequest);
//分账退款记录设置退款

View File

@ -217,18 +217,18 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
//判断当前传入的是否是课卡
if (bo.getProductType() == 0) {
//获取模板相关信息
CardTemplate oldTemplateInfo = SpringUtils.getBean(CardTemplateService.class).getOldTemplateInfo(bo.getCardTemplateId(), product.getBrandId());
product.setMaxConsume(oldTemplateInfo.getPrice()).setMinConsume(oldTemplateInfo.getPrice());
Row oldTemplateInfo = SpringUtils.getBean(CardTemplateService.class).getOldTemplateInfo(bo.getCardTemplateId(), product.getBrandId());
product.setMaxConsume(oldTemplateInfo.getBigDecimal("price")).setMinConsume(oldTemplateInfo.getBigDecimal("price"));
this.save(product);
//课卡模板获取固定规格
ProductSpecification productSpecification = new ProductSpecification();
productSpecification.setSpecificationNames(oldTemplateInfo.getName());
productSpecification.setSpecificationNames(oldTemplateInfo.getString("name"));
productSpecifications = new ArrayList<ProductSpecification>();
productSpecifications.add(productSpecification);
//记录
recordList = new ArrayList<ProductRecord>();
ProductRecord productRecord = new ProductRecord();
productRecord.setRecordNum(2147483647).setRecordNames(productSpecification.getSpecificationNames()).setRecordPrice(oldTemplateInfo.getPrice()).setRecordPoints(0);
productRecord.setRecordNum(2147483647).setRecordNames(productSpecification.getSpecificationNames()).setRecordPrice(oldTemplateInfo.getBigDecimal("price")).setRecordPoints(0);
recordList.add(productRecord);
} else {
//积分支付
@ -449,8 +449,8 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
if (productInfoVo.getProductType() == 0){
try {
DataSourceKey.use("jambox");
CardTemplate cardTemplate = SpringUtils.getBean(CardTemplateService.class).getOldTemplateInfo(productInfoVo.getCardTemplateId(), loginUserInfo.getString("brandId"));
productInfoVo.setCardTemplateName(cardTemplate.getName());
Row cardTemplate = SpringUtils.getBean(CardTemplateService.class).getOldTemplateInfo(productInfoVo.getCardTemplateId(), loginUserInfo.getString("brandId"));
productInfoVo.setCardTemplateName(cardTemplate.getString("name"));
} finally {
DataSourceKey.clear();
}

View File

@ -0,0 +1,41 @@
package com.cpop.mall.business.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-15 14:51
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "Brand对象", description = "品牌表")
public class CarouselListVo {
/**
* 主键
*/
@ApiModelProperty(value = "主键")
private String id;
/**
* 产品id
*/
@ApiModelProperty(value = "产品id")
private String productId;
/**
* 图片地址
*/
@ApiModelProperty(value = "图片地址")
private String picUrl;
/**
* 排序
*/
@ApiModelProperty(value = "排序")
private Integer orderNo;
}

View File

@ -0,0 +1,54 @@
package com.cpop.mall.business.vo;
import com.mybatisflex.annotation.Id;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-15 12:54
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "Brand对象", description = "品牌表")
public class CarouselPageVo {
/**
* 主键
*/
@ApiModelProperty(value = "主键")
private String id;
/**
* 产品id
*/
@ApiModelProperty(value = "产品id")
private String productId;
/**
* 产品名称
*/
@ApiModelProperty(value = "产品名称")
private String productName;
/**
* 图片地址
*/
@ApiModelProperty(value = "图片地址")
private String picUrl;
/**
* 排序
*/
@ApiModelProperty(value = "排序")
private Integer orderNo;
/**
* 上架状态(0下架;1上架)
*/
@ApiModelProperty(value = "上架状态(0下架;1上架)")
private Boolean upStatus;
}

View File

@ -0,0 +1,25 @@
package com.cpop.mall.business.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-15 14:06
*/
@Data
public class ProductSimpleVo {
/**
* 主键
*/
@ApiModelProperty(value = "主键")
private String id;
/**
* 商品名称
*/
@ApiModelProperty(value = "商品名称")
private String productName;
}

View File

@ -0,0 +1,7 @@
<?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.cpop.mall.business.mapper.CarouselMapper">
</mapper>

View File

@ -4,7 +4,7 @@ cpop:
profile: E:/Cpop/uploadPath
jwt:
#白名单
whiteList: /websocket/*,/login,/getCaptcha,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources,/wxCp/*,/wxCp/portal/*/registerCode,/sysCommon/miniSyncBrandAndStore,/easyLearn/callback/*/*,/easyLearn/*,/website/**
whiteList: /websocket/*,/login,/getCaptcha,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources,/wxCp/*,/wxCp/portal/*/registerCode,/sysCommon/miniSyncBrandAndStore,/easyLearn/callback/*/*,/easyLearn/*,/mini/cardTemplate/*,/website/**
gateway:
rsa-keypair:
# 公钥文件
@ -43,7 +43,9 @@ spring:
mongodb:
host: localhost
port: 27017
database: cpop-union
database: cpop-dev
username: Cpop
password: Admin@123
server:
port: 9420
@ -106,3 +108,7 @@ wx:
privateKeyPath: E:/Cpop/Cpop-Union/Cpop-Core/src/main/resources/static/keyPair/wxPay_key.pem
# 私钥文件
privateCertPath: E:/Cpop/Cpop-Union/Cpop-Core/src/main/resources/static/keyPair/wxPay_cert.pem
# 先学后付用户签约通知地址
learn-now-pay-later-user-sign-plan-notify-url:
# 先学后付用户核销通知地址
learn-now-pay-later-service-order-notify-url:

View File

@ -4,7 +4,7 @@ cpop:
profile: /root/cpop-union/cpop-oam/upload
jwt:
#白名单
whiteList: /websocket/*,/login,/getCaptcha,/profile/**,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*,/wxCp/portal/*,/wxCp/*,/wxCp/portal/*/registerCode,/sysCommon/miniSyncBrandAndStore,/easyLearn/callback/*/*,/easyLearn/*,/website/**
whiteList: /websocket/*,/login,/getCaptcha,/profile/**,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*,/wxCp/portal/*,/wxCp/*,/wxCp/portal/*/registerCode,/sysCommon/miniSyncBrandAndStore,/easyLearn/callback/*/*,/easyLearn/*,/mini/cardTemplate/*,/website/**
#拦截
gateway:
rsa-keypair:
@ -56,7 +56,7 @@ mybatis-flex:
configuration:
log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
datasource:
mall:
oam:
url: jdbc:mysql://sh-cynosdbmysql-grp-fggo83js.sql.tencentcdb.com:20965/cpop_union?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: Customer0401
@ -73,4 +73,4 @@ wx:
# 私钥证书
privateKeyPath: /root/cpop-union/cpop-oam/script/secretKey/wxPay_key.pem
# 私钥文件
privateCertPath: /root/cpop-union/cpop-oam/script/secretKey/wxPay_cert.pem
privateCertPath: /root/cpop-union/cpop-oam/script/secretKey/wxPay_cert.pem

View File

@ -4,7 +4,7 @@ cpop:
profile: /root/cpop-union/cpop-mall/upload
jwt:
#白名单
whiteList: /websocket/*,/login,/getCaptcha,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*,/wxCp/portal/*,/wxCp/portal/*/registerCode,/wxCp/*,/sysCommon/miniSyncBrandAndStore,/easyLearn/callback/*/*,/easyLearn/*,/website/**
whiteList: /websocket/*,/login,/getCaptcha,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*,/wxCp/portal/*,/wxCp/portal/*/registerCode,/wxCp/*,/sysCommon/miniSyncBrandAndStore,/easyLearn/callback/*/*,/easyLearn/*,/mini/cardTemplate/*,/website/**
#拦截
gateway:
rsa-keypair:
@ -12,10 +12,6 @@ cpop:
publicKeyFile: /root/jambox-union/jambox-oam/script/secretKey/publicKey
# 公钥文件
privateKeyFile: /root/jambox-union/jambox-oam/script/secretKey/privateKey
# 公钥文件
#publicKeyFile: E:\Cpop\Cpop-Union\Cpop-Core\src\main\resources\static\keyPair\publicKey
# 公钥文件
#privateKeyFile: E:\Cpop\Cpop-Union\Cpop-Core\src\main\resources\static\keyPair\privateKey
# DataSource Config
spring:
@ -60,7 +56,7 @@ mybatis-flex:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
datasource:
mall:
oam:
url: jdbc:mysql://sh-cynosdbmysql-grp-fggo83js.sql.tencentcdb.com:20965/cpop_test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: Customer0401
@ -98,10 +94,4 @@ wx:
# 私钥证书
privateKeyPath: /root/cpop-union/cpop-oam/script/secretKey/wxPay_key.pem
# 私钥文件
privateCertPath: /root/cpop-union/cpop-oam/script/secretKey/wxPay_cert.pem
# p12证书的位置可以指定绝对路径也可以指定类路径以classpath:开头)
#keyPath: E:/Cpop/Cpop-Union/Cpop-Core/src/main/resources/static/keyPair/wxPay_cert.p12
# 私钥证书
#privateKeyPath: E:/Cpop/Cpop-Union/Cpop-Core/src/main/resources/static/keyPair/wxPay_key.pem
# 私钥文件
#privateCertPath: E:/Cpop/Cpop-Union/Cpop-Core/src/main/resources/static/keyPair/wxPay_cert.pem
privateCertPath: /root/cpop-union/cpop-oam/script/secretKey/wxPay_cert.pem

View File

@ -31,7 +31,7 @@ spring:
max-file-size: 1024MB
max-request-size: 300MB
profiles:
active: dev,core,jambox
active: dev,oam,core,jambox,system,pay
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
@ -158,18 +158,7 @@ wx:
componentToken: jambox
componentAesKey: 1a3NBxmCFwkCJvfoQ7WhJHB6iX3qHPsc9JbaDznE1i0
redirectUri: https://empower.oamapi.cpopsz.com/test/openPlatform/thirdPartyPlatform/redirectUrl
#微信支付
pay:
#微信公众号或者小程序等的appid
appId: wx20853d18c455e874
#微信支付商户号
mchId: 1618884922
#微信支付商户密钥
mchKey: JamBox20230919174000000000000002
apiV3Key: JamBox20230919174000000000000002
#分账服务商账号
sharingAccount: 1618884922
sharingAccountName: 果酱盒子
#小程序
miniapp:
configs:
#微信小程序的appid

View File

@ -1,6 +1,8 @@
package com.cpop.oam.web;
import com.cpop.api.tencent.wxWork.handler.WebHookSendHandler;
import com.cpop.core.utils.RsaUtils;
import com.cpop.core.utils.SpringUtils;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@ -14,7 +16,7 @@ import java.util.List;
* @createTime 2023/09/15 17:44
* @description
*/
@SpringBootTest
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class CpopApiTests {
@Autowired
@ -36,4 +38,12 @@ public class CpopApiTests {
throw new RuntimeException(e);
}
}
@Test
public void rsaDecrypt(){
RsaUtils rsaUtils = SpringUtils.getBean(RsaUtils.class);
String jambox0831 = rsaUtils.encrypt("jambox0831");
String decrypt = rsaUtils.decrypt(jambox0831);
System.out.println(decrypt);
}
}

View File

@ -1,5 +1,6 @@
package com.cpop.oam.web;
import cn.hutool.core.util.IdUtil;
import com.cpop.core.base.entity.LoginUser;
import com.cpop.core.base.enums.OperationLogEnum;
import com.cpop.core.base.enums.UserType;
@ -7,6 +8,7 @@ import com.cpop.core.service.CoreService;
import com.cpop.core.utils.PasswordEncoder;
import com.cpop.core.utils.RsaUtils;
import com.cpop.core.utils.SpringUtils;
import com.cpop.core.utils.uuid.IdUtils;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@ -84,5 +86,36 @@ public class CpopCoreTests {
System.out.println("encode加密"+encode);
}
/**
* 初始化密钥对
*/
@Test
public void initPublicOrPrivateKey() {
String snowflakeNextIdStr = IdUtil.getSnowflakeNextIdStr();
String baseKeyRepository = "E:\\KeyRepository\\";
String publicKeyFile = baseKeyRepository + "publicKey" + snowflakeNextIdStr;
String privateKeyFile = baseKeyRepository + "privateKey" + snowflakeNextIdStr;
Map<String, String> keyPairMap = rsaUtils.initKeyPair(publicKeyFile, privateKeyFile);
String publicKey = keyPairMap.get("publicKey");
String privateKey = keyPairMap.get("privateKey");
System.out.println("公钥:");
System.out.println(publicKey);
System.out.println();
System.out.println("私钥:");
System.out.println(privateKey);
System.out.println();
String source = "Admin@123";
System.out.println("待加密字符串:" + source);
System.out.println();
String strEncrypt = rsaUtils.encrypt(source);
System.out.println("加密后的字符串:");
System.out.println(strEncrypt);
System.out.println();
String strDecrypt = rsaUtils.decrypt(strEncrypt);
System.out.println("解密后的字符串:");
System.out.println(strDecrypt);
//加密
String encode = SpringUtils.getBean(PasswordEncoder.class).encode("Admin@123");
System.out.println("encode加密" + encode);
}
}

View File

@ -0,0 +1,289 @@
package com.cpop.oam.web;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.utils.SpringUtils;
import com.cpop.jambox.business.entity.BrandExtend;
import com.cpop.jambox.business.entity.CardTemplate;
import com.cpop.jambox.business.entity.CardTemplateExtend;
import com.cpop.jambox.business.entity.StoreExtend;
import com.cpop.jambox.business.service.BrandExtendService;
import com.cpop.jambox.business.service.CardTemplateExtendService;
import com.cpop.jambox.business.service.CardTemplateService;
import com.cpop.jambox.business.service.StoreExtendService;
import com.cpop.system.business.entity.Store;
import com.cpop.system.business.entity.StoreSign;
import com.cpop.system.business.entity.WxPayScore;
import com.cpop.system.business.mapper.StoreMapper;
import com.cpop.system.business.mapper.StoreSignMapper;
import com.cpop.system.business.service.StoreService;
import com.cpop.system.business.service.StoreSignService;
import com.cpop.system.business.service.WxPayScoreService;
import com.mybatisflex.core.datasource.DataSourceKey;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.DbChain;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.row.RowUtil;
import com.mybatisflex.core.update.UpdateChain;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.cpop.core.base.table.table.SysUserTableDef.SYS_USER;
import static com.cpop.oam.business.entity.table.StaffTableDef.STAFF;
import static com.cpop.system.business.entity.table.StoreSignTableDef.STORE_SIGN;
import static com.mybatisflex.core.query.QueryMethods.count;
import static com.mybatisflex.core.query.QueryMethods.max;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-16 17:17
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles(profiles = {"prod", "core", "pay"})
public class CpopDataSyncTests {
/**
* 同步校区缺失数据
* @author DB
* @since 2024/1/16
*/
@Test
public void syncStoreInfo(){
List<Row> rowList;
try {
DataSourceKey.use("jambox");
rowList = DbChain.table("t_mechanism_info")
.select("tmi.store_id as storeCloudId")
.from("t_mechanism_info").as("tmi")
.leftJoin("t_signContract_mechanism").as("tsm").on("tsm.store_id = tmi.store_id")
.where("tmi.deleted = 1")
.and("DATEDIFF(\n" +
"\tDATE_FORMAT( tsm.end_time, '%Y-%m-%d' ),\n" +
"\tDATE_FORMAT( tmi.creation_time, '%Y-%m-%d' ))>= 300")
.list();
} finally {
DataSourceKey.clear();
}
//获取所有校区
Map<String, String> storeMap = SpringUtils.getBean(StoreExtendService.class).list().stream().collect(Collectors.toMap(StoreExtend::getStoreCloudId, StoreExtend::getStoreId));
rowList.forEach(item -> {
item.set("id", storeMap.get(item.getString("storeCloudId")));
item.set("have_active", true);
});
List<Store> storeList = RowUtil.toEntityList(rowList, Store.class).stream().filter(item -> StringUtils.isNotBlank(item.getId())).collect(Collectors.toList());
SpringUtils.getBean(StoreService.class).updateBatch(storeList);
}
/**
* 同步课卡模板
* @author DB
* @since 2024/1/17
*/
@Test
public void syncCardTemplate(){
List<Row> rowList;
try {
DataSourceKey.use("jambox");
rowList = DbChain.table("t_card_template")
.select("tct.template_id as oldTemplateId", "tct.brand_id as brandCloudId", "tct.store_id as storeCloudId", "tct.open_status as status", "tct.name", "tct.day as validDay",
"tct.end as endDate", "tct.price", "tct.week_appointment", "tct.day_appointment", "tct.free_day as bufferDay", "tct.number as classNumber",
"tct.type as scopeUse", "tct.time_limit", "tct.is_suda", "tct.pay_type", "tct.template_qr_code as qrCode", "tct.is_member", "tct.stage_num", "tct.deposit", "tct.buffer_days",
"tct.is_drainage", "tct.is_ecpp_activity", "tct.ecpp_activity_code", "tct.ecpp_activity_desc")
.select("(SELECT jwpp.plan_id from j_wechat_pay_plan as jwpp WHERE jwpp.template_id = tct.template_id AND jwpp.is_month = 0 AND jwpp.deleted = 1 LIMIT 1 ) as oncePlanId")
.select("(SELECT jwpp.plan_id from j_wechat_pay_plan as jwpp WHERE jwpp.template_id = tct.template_id AND jwpp.is_month = 1 AND jwpp.deleted = 1 LIMIT 1 ) as monthPlanId")
.select("creation_time as createTime", "last_modification_date as updateTime")
.from("t_card_template").as("tct")
.where("tct.deleted = 1")
.list();
} finally {
DataSourceKey.clear();
}
//获取所有计划
Map<String, WxPayScore> wxPayScoreMap = SpringUtils.getBean(WxPayScoreService.class).list().stream().collect(Collectors.toMap(WxPayScore::getOutPlanId, item -> item));
Map<String, String> brandMap = SpringUtils.getBean(BrandExtendService.class).list().stream().collect(Collectors.toMap(BrandExtend::getBrandCloudId, BrandExtend::getBrandId));
Map<String, String> storeMap = SpringUtils.getBean(StoreExtendService.class).list().stream().collect(Collectors.toMap(StoreExtend::getStoreCloudId, StoreExtend::getStoreId));
List<CardTemplateExtend> cardTemplateExtends = new ArrayList<>();
rowList.forEach(item -> {
//模板类型
item.set("templateType", changeTimeLimitToTemplateType(item.getString("timeLimit")));
if (item.getBoolean("isSuda")){
CardTemplateExtend cardTemplateExtend = new CardTemplateExtend();
cardTemplateExtend.setTemplateId(item.getString("oldTemplateId"))
.setPayType(3)
.setExtendParamOne(item.getString("isEcppActivity"))
.setExtendParamTwo(item.getString("ecppActivityCode"))
.setExtendParamThree(item.getString("ecppActivityDesc"));
cardTemplateExtends.add(cardTemplateExtend);
}
if (StringUtils.isNotBlank(item.getString("brandCloudId"))){
item.set("brandId",brandMap.get(item.getString("brandCloudId")));
}
if (StringUtils.isNotBlank(item.getString("storeCloudId"))){
item.set("storeId",storeMap.get(item.getString("storeCloudId")));
}
if (StringUtils.isNotBlank(item.getString("payType"))){
List<String> payTypeList = Arrays.stream(item.getString("payType").split(",")).collect(Collectors.toList());
payTypeList.forEach(inner -> {
changePayType(inner, cardTemplateExtends, item, wxPayScoreMap);
});
} else {
CardTemplateExtend cardTemplateExtend = new CardTemplateExtend();
cardTemplateExtend.setTemplateId(item.getString("oldTemplateId"))
.setPayType(4);
cardTemplateExtends.add(cardTemplateExtend);
}
});
List<CardTemplate> entityList = RowUtil.toEntityList(rowList, CardTemplate.class);
SpringUtils.getBean(CardTemplateService.class).saveBatch(entityList);
Map<String, String> collect = entityList.stream().collect(Collectors.toMap(CardTemplate::getOldTemplateId, CardTemplate::getId));
LocalDateTime now = LocalDateTime.now();
cardTemplateExtends.forEach(item->{
item.setTemplateId(collect.get(item.getTemplateId()));
item.setCreateTime(now);
item.setUpdateTime(now);
});
SpringUtils.getBean(CardTemplateExtendService.class).saveBatch(cardTemplateExtends);
}
private Integer changeTimeLimitToTemplateType(String timeLimit) {
switch (timeLimit) {
case "课时卡":
return 0;
case "时限卡":
return 1;
default:
return 2;
}
}
private void changePayType(String payType,List<CardTemplateExtend> cardTemplateExtends,Row row,Map<String, WxPayScore> wxPayScoreMap) {
CardTemplateExtend cardTemplateExtend = new CardTemplateExtend();
switch (payType) {
//先学后付次付
case "1":
if (StringUtils.isNotBlank(row.getString("oncePlanId"))){
WxPayScore oncePlan = wxPayScoreMap.get(row.getString("oncePlanId"));
if (oncePlan != null){
cardTemplateExtend.setTemplateId(row.getString("oldTemplateId"))
.setExtendId(oncePlan.getId())
.setPayType(1);
cardTemplateExtends.add(cardTemplateExtend);
}
}
break;
//旧放心学合约
case "2":
cardTemplateExtend.setTemplateId(row.getString("oldTemplateId"))
.setPayType(2)
.setExtendParamOne(row.getString("stageNum"))
.setExtendParamTwo(row.getString("deposit"))
.setExtendParamThree(row.getString("bufferDays"));
cardTemplateExtends.add(cardTemplateExtend);
break;
//先学后付月付
case "5":
if (StringUtils.isNotBlank(row.getString("monthPlanId"))){
WxPayScore monthPlan = wxPayScoreMap.get(row.getString("monthPlanId"));
if (monthPlan != null){
cardTemplateExtend.setTemplateId(row.getString("oldTemplateId"))
.setExtendId(monthPlan.getId())
.setPayType(5);
cardTemplateExtends.add(cardTemplateExtend);
}
}
break;
default:
break;
}
}
/**
* 同步校区签约
* @author DB
* @since 2024/1/18
*/
@Test
public void syncOldStoreSignData() {
List<Row> rowList;
try {
DataSourceKey.use("jambox");
rowList = DbChain.table("t_signContract_mechanism")
.select("tsm.store_id as storeCloudId", "tsm.creation_time as createTime", "tsm.last_modification_date as updateTime","os.phone")
.from("t_signContract_mechanism").as("tsm")
.leftJoin("t_mechanism_info").as("tmi").on("tmi.store_id = tsm.store_id")
.leftJoin("OAM_staff").as("os").on("os.staff_id = tmi.clue_id")
.where("tsm.deleted = 1")
.list();
} finally {
DataSourceKey.clear();
}
Map<String, String> phoneToId = DbChain.table(STAFF.getTableName())
.select(STAFF.ID)
.select(SYS_USER.PHONE_NUMBER.as("phone"))
.from(STAFF)
.leftJoin(SYS_USER).on(SYS_USER.ID.eq(STAFF.USER_ID))
.list()
.stream().collect(Collectors.toMap(item -> item.getString("phone"), item -> item.getString("id")));
Map<String, String> cloudToId = SpringUtils.getBean(StoreExtendService.class).list()
.stream().collect(Collectors.toMap(StoreExtend::getStoreCloudId, StoreExtend::getStoreId));
rowList.forEach(item->{
if (StringUtils.isNotBlank(item.getString("phone"))){
item.set("sign_staff_id",phoneToId.get(item.getString("phone")));
}
item.set("store_id",cloudToId.get(item.getString("storeCloudId")));
});
List<StoreSign> entityList = RowUtil.toEntityList(rowList, StoreSign.class)
.stream().filter(item->StringUtils.isNotBlank(item.getStoreId())).collect(Collectors.toList());
Db.executeBatch(entityList, StoreSignMapper.class, (mapper, storeSign) -> {
// 以上的这个 mapper未被使用
UpdateChain.of(mapper)
.set(STORE_SIGN.CREATE_TIME,storeSign.getCreateTime())
.set(STORE_SIGN.UPDATE_TIME,storeSign.getUpdateTime())
.set(STORE_SIGN.SIGN_STAFF_ID,storeSign.getSignStaffId())
.where(STORE_SIGN.STORE_ID.eq(storeSign.getStoreId()))
.update();
});
}
@Test
public void removeExtendSignData(){
StoreSignService storeSignService = SpringUtils.getBean(StoreSignService.class);
List<StoreSign> list = storeSignService.queryChain()
.select(max(STORE_SIGN.ID).as(StoreSign::getId))
.groupBy(STORE_SIGN.STORE_ID)
.having(count(STORE_SIGN.STORE_ID).gt(1)).list();
storeSignService.removeByIds(list.stream().map(StoreSign::getId).collect(Collectors.toList()));
}
@Test
public void checkSpecialCharacter(){
String input = "排课000\uD83C\uDF3F\uD83C\uDF8B\uD83C\uDF15\uD83C\uDF44\uD83D\uDC1A";
//特殊字符过滤
String pattern = "[^a-zA-Z0-9]";
System.out.println(input.replaceAll(pattern, ""));
}
/**
* 同步校区签约数据
*/
@Test
public void syncStoreSignData(){
List<StoreSign> list = SpringUtils.getBean(StoreSignService.class).list();
List<Store> stores = new ArrayList<>();
list.forEach(item->{
Store store = new Store();
store.setId(item.getStoreId())
.setSignId(item.getId());
stores.add(store);
});
SpringUtils.getBean(StoreService.class).updateBatch(stores);
}
}

View File

@ -12,10 +12,22 @@ import com.cpop.jambox.business.service.StoreExtendService;
import com.cpop.jambox.framework.constant.JamboxCloudUrl;
import com.cpop.pay.framewok.config.wxPay.WxPayProperties;
import com.cpop.pay.framewok.handler.wxPay.WxPayHandler;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingBillV3Request;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingReceiverRequest;
import com.github.binarywang.wxpay.bean.profitsharing.request.ProfitSharingRequest;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingBillV3Result;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingOrderAmountQueryV3Result;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingResult;
import com.github.binarywang.wxpay.bean.profitsharing.result.ProfitSharingV3Result;
import com.github.binarywang.wxpay.bean.request.WxPayApplyTradeBillV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayPartnerOrderCloseV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayApplyBillV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.ProfitSharingService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
@ -28,6 +40,9 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.web.client.RestTemplate;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
@ -43,7 +58,7 @@ import static com.cpop.jambox.business.entity.table.StoreExtendTableDef.STORE_EX
* @since 2023-12-29 9:50
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles({"prod", "core", "jambox"})
@ActiveProfiles({"dev", "core", "jambox", "pay"})
public class CpopEasyLearnTest {
@Autowired
@ -199,4 +214,93 @@ public class CpopEasyLearnTest {
}
}
}
/**
* 关闭服务商订单
* @author DB
* @since 2024/1/12
*/
@Test
public void closePartnerOrderV3() throws WxPayException {
WxPayService wxPayService= wxPayHandler.getWxPayService();
WxPayPartnerOrderCloseV3Request wxPayPartnerOrderCloseV3Request = new WxPayPartnerOrderCloseV3Request();
wxPayPartnerOrderCloseV3Request.setSubMchId("1661323640");
wxPayPartnerOrderCloseV3Request.setOutTradeNo("1745820005743910912");
wxPayService.closePartnerOrderV3(wxPayPartnerOrderCloseV3Request);
}
/**
* 查询未完结订单
* @author DB
* @since 2024/1/19
*/
@Test
public void downloadBill() throws WxPayException {
WxPayService wxPayService = wxPayHandler.getWxPayService(null, "1663310469");
ProfitSharingService profitSharingService = wxPayService.getProfitSharingService();
ProfitSharingBillV3Request profitSharingBillV3Request = new ProfitSharingBillV3Request();
profitSharingBillV3Request.setSubMchId("1663310469");
String date = "2024-01-17";
profitSharingBillV3Request.setBillDate(date);
WxPayApplyTradeBillV3Request wxPayApplyTradeBillV3Request = new WxPayApplyTradeBillV3Request();
wxPayApplyTradeBillV3Request.setBillDate(date);
wxPayApplyTradeBillV3Request.setBillType("ALL");
WxPayApplyBillV3Result wxPayApplyBillV3Result = wxPayService.applyTradeBill(wxPayApplyTradeBillV3Request);
//ProfitSharingBillV3Result profitSharingBillV3Result = profitSharingService.profitSharingBill(profitSharingBillV3Request);
InputStream inputStream = wxPayService.downloadBill(wxPayApplyBillV3Result.getDownloadUrl());
new File("");
// 创建输出文件的路径
String filePath = "D:\\Lost\\下载\\" + date + ".txt";
// 将输入流中的内容写入文件
try (OutputStream outputStream = Files.newOutputStream(Paths.get(filePath))) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
System.out.println("内容成功写入文件");
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void queryOrderAndSharing() throws WxPayException {
WxPayService wxPayService = wxPayHandler.getWxPayService(null, "1663310469");
WxPayOrderQueryRequest wxPayOrderQueryRequest = new WxPayOrderQueryRequest();
wxPayOrderQueryRequest.setTransactionId("4200001925202401173471747106");
WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder(wxPayOrderQueryRequest);
ProfitSharingService profitSharingService = wxPayService.getProfitSharingService();
ProfitSharingV3Result profitSharingV3Result = profitSharingService.profitSharingQueryV3("105490200209170432", "4200002126202401189482541307", "1663310469");
ProfitSharingOrderAmountQueryV3Result profitSharingOrderAmountQueryV3Result = profitSharingService.profitSharingUnsplitAmountQueryV3("4200001925202401173471747106");
System.out.println(JSONObject.toJSONString(wxPayOrderQueryResult));
System.out.println(JSONObject.toJSONString(profitSharingV3Result));
}
@Test
public void orderProfitSharing() throws WxPayException {
//固定商户信息
Map<String, Object> mapReceiver = new HashMap<>(4);
mapReceiver.put("type", "MERCHANT_ID");
mapReceiver.put("account", wxPayProperties.getSharingAccount());
mapReceiver.put("amount", 900);
mapReceiver.put("description","分账到服务商");
List<Map<String, Object>> receivers = new ArrayList<>();
receivers.add(mapReceiver);
//分账请求参数
ProfitSharingRequest profitSharingRequest = new ProfitSharingRequest();
profitSharingRequest.setReceivers(JSONObject.toJSONString(receivers));
profitSharingRequest.setOutOrderNo("105490200209170432");
profitSharingRequest.setTransactionId("4200002126202401189482541307");
profitSharingRequest.setSubMchId("1663310469");
ProfitSharingResult profitSharingResult = wxPayService.getProfitSharingService().profitSharing(profitSharingRequest);
if (StringUtils.equals(profitSharingResult.getResultCode(), "SUCCESS")) {
//存入系统
DbChain.table("cp_sys_profit_sharing")
.set("out_profit_sharing_id", profitSharingResult.getOrderId())
.set("profit_sharing_status", 1)
.where("id = ?", profitSharingResult.getOutOrderNo())
.update();
}
}
}

View File

@ -59,7 +59,7 @@ import static com.cpop.system.business.entity.table.StoreTableDef.STORE;
*/
@Slf4j
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles(profiles = {"prod", "core"})
@ActiveProfiles(profiles = {"dev", "core"})
public class CpopImportTests {
/**
@ -1578,18 +1578,16 @@ public class CpopImportTests {
@Test
public void batchUpdateStaffPassword(){
List<Row> cpSysUser = DbChain.table("cp_sys_user")
.select("id","phone_number","password")
.select("id","phone_number")
.where("user_type = 'OAM_USER'")
.and("is_delete = 0")
.list();
List<SysUser> entityList = RowUtil.toEntityList(cpSysUser, SysUser.class);
//加密
PasswordEncoder passwordEncoder = SpringUtils.getBean(PasswordEncoder.class);
RsaUtils rsaUtils = SpringUtils.getBean(RsaUtils.class);
entityList.forEach(item -> {
if (!StringUtils.equals("1", item.getId())) {
String lastFourChars = "jambox" + item.getPhoneNumber().substring(item.getPhoneNumber().length() - 4);
item.setPassword(passwordEncoder.encode(lastFourChars));
item.setRsaPassword(rsaUtils.encrypt(lastFourChars));
}
});
@ -1640,4 +1638,5 @@ public class CpopImportTests {
});
financeReimburseService.updateBatch(updateEnetyList);
}
}

View File

@ -19,10 +19,6 @@
<groupId>com.cpop</groupId>
<artifactId>Cpop-Core</artifactId>
</dependency>
<dependency>
<groupId>com.cpop</groupId>
<artifactId>Cpop-Api</artifactId>
</dependency>
<dependency>
<groupId>com.cpop</groupId>
<artifactId>Cpop-Jambox</artifactId>
@ -31,6 +27,10 @@
<groupId>com.cpop</groupId>
<artifactId>Cpop-System</artifactId>
</dependency>
<dependency>
<groupId>com.cpop</groupId>
<artifactId>Cpop-Pay</artifactId>
</dependency>
<!--企业微信-->
<dependency>
<groupId>com.github.binarywang</groupId>
@ -41,11 +41,6 @@
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-open</artifactId>
</dependency>
<!--微信小程序-->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-miniapp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>

View File

@ -30,12 +30,7 @@ public class BusinessDistributeBo {
@NotNull(message = "业务等级不能为空")
@ApiModelProperty(value = "业务等级")
private Integer businessLevel;
/**
* 业务类型
*/
@NotNull(message = "业务类型不能为空")
@ApiModelProperty(value = "业务类型")
private Integer businessType;
/**
* 对接列表
*/
@ -58,11 +53,6 @@ public class BusinessDistributeBo {
*/
@ApiModelProperty(value = "备注")
private String remark;
/**
* 签约列表
*/
@ApiModelProperty(value = "签约列表")
private List<Sign> sign;
@Data
public static class ButtJoint {
@ -77,18 +67,4 @@ public class BusinessDistributeBo {
@ApiModelProperty(value = "接收员工id")
private String staffId;
}
@Data
public static class Sign {
/**
* 接收员工id
*/
@ApiModelProperty(value = "接收员工id")
private String staffId;
/**
* 剩余数量
*/
@ApiModelProperty(value = "剩余数量")
private Integer surplusQuantity;
}
}

View File

@ -0,0 +1,163 @@
package com.cpop.oam.business.bo;
import com.cpop.system.business.bo.StoreBo;
import com.cpop.system.business.bo.SyncBrandAndStoreBo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import java.sql.Date;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-16 11:35
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "CloudUnionCallbackBo对象", description = "云回调统一入参")
public class CloudUnionCallbackBo {
/**
* 回调枚举(DATA_IMPORT_CALLBACK:数据导入回调)
*/
@NotBlank(message = "回调枚举不能为空")
@ApiModelProperty(value = "回调枚举(DATA_IMPORT_CALLBACK:数据导入回调;SYNC_BRAND_AND_STORE_CALLBACK:同步品牌与校区)",required = true)
private String callbackEnum;
/**
* 主要id
*/
@ApiModelProperty(value = "主要id")
private String mainId;
/**
* 同步品牌与校区相关参数
*/
@ApiModelProperty(value = "同步品牌与校区相关参数")
private SyncBrandAndStore syncBrandAndStore;
@Data
@ApiModel("同步品牌与校区")
public class SyncBrandAndStore {
/**
* 品牌
*/
@ApiModelProperty(value = "品牌")
private SyncBrandAndStoreBo.BrandInfo brandInfo;
/**
* 校区
*/
@ApiModelProperty(value = "校区")
private SyncBrandAndStoreBo.StoreInfo storeInfo;
/**
* 品牌信息
*/
@Data
public class BrandInfo {
/**
* 云品牌id
*/
@ApiModelProperty(value = "云品牌id")
private String brandCloudId;
/**
* 品牌名
*/
@ApiModelProperty(value = "品牌名")
private String brandName;
}
/**
* 校区信息
*/
@Data
public class StoreInfo {
/**
* 云品牌id
*/
@ApiModelProperty(value = "云校区id")
private String storeCloudId;
/**
* 店铺/校区名
*/
@ApiModelProperty(value = "店铺/校区名")
private String storeName;
/**
* 店铺/校区地址
*/
@ApiModelProperty(value = "店铺/校区地址")
private String storeAddr;
/**
* 负责人
*/
@ApiModelProperty(value = "负责人")
private String personCharge;
/**
* 手机号
*/
@ApiModelProperty(value = "手机号")
private String phone;
/**
* 营业执照地址
*/
@ApiModelProperty(value = "营业执照地址")
private String licenseAddr;
/**
* 营业执照日期
*/
@ApiModelProperty(value = "营业执照日期")
private Date licenseDate;
/**
* 营业执照公司名
*/
@ApiModelProperty(value = "营业执照公司名")
private String licenseName;
/**
* 营业执照证书码
*/
@ApiModelProperty(value = "营业执照证书码")
private String licenseCode;
/**
* 营业执照法人名
*/
@ApiModelProperty(value = "营业执照法人名")
private String licenseUserName;
/**
* 营业执照图片地址
*/
@ApiModelProperty(value = "营业执照图片地址")
private String licensePicUrl;
/**
* 经度
*/
@ApiModelProperty(value = "经度")
private String longitude;
/**
* 纬度
*/
@ApiModelProperty(value = "纬度")
private String latitude;
}
}
}

View File

@ -47,6 +47,10 @@ public class TaskAuditCommentsBo {
@ApiModelProperty("任务权重(任务绩点)")
private Integer taskWeight;
public void setTaskWeight(String taskWeight) {
this.taskWeight = Integer.parseInt(taskWeight.split(",")[0]);
}
/**
* 备注(不通过时可以写入备注)
*/

View File

@ -10,10 +10,7 @@ import com.cpop.oam.business.bo.BusinessRemoveBo;
import com.cpop.oam.business.dto.BusinessDistributeDto;
import com.cpop.oam.business.service.BusinessService;
import com.cpop.oam.business.service.StaffService;
import com.cpop.oam.business.vo.BusinessInfoPageVo;
import com.cpop.oam.business.vo.BusinessPageVo;
import com.cpop.oam.business.vo.PersonBusinessInfoVo;
import com.cpop.oam.business.vo.StaffVo;
import com.cpop.oam.business.vo.*;
import com.mybatisflex.core.paginate.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -163,4 +160,32 @@ public class BusinessController {
return R.ok();
}
/**
* 查询未签约校区分页列表
* @author DB
* @since 2024/1/22
* @param params 请求参数
* @return R<Page<StorePoolPageVo>>
*/
@ApiOperation("查询未签约校区分页列表")
@GetMapping("/getUnSignStorePage")
public R<Page<BusinessUnSignPageVo>> getUnSignStorePage(@ApiParam("查询参数") @RequestParam(value = "params", required = false) String params) {
Page<BusinessUnSignPageVo> pageVo = businessService.getUnSignStorePage(params);
return R.ok(pageVo);
}
/**
* 校区签约
* @author DB
* @since 2024/1/22
* @param id 校区id
* @return R<Void>
*/
@ApiOperation("校区签约")
@PutMapping("/storeSign")
public R<Void> storeSign(@ApiParam(value = "校区id", required = true) @RequestParam(value = "id") String id) {
businessService.storeSign(id);
return R.ok();
}
}

View File

@ -52,7 +52,6 @@ public class WxPayController {
* @date 2023/11/15 11:06
* @return: com.cpop.core.base.R<java.lang.Void>
*/
@PreAuthorize("@aps.hasPermission('brandStore:brand:update')")
@ApiOperation("开通微信分账")
@PutMapping("/changeBrandSharing")
public R<Void> changeBrandSharing(@RequestBody @Validated ChangeWechatSharingBo bo) {

View File

@ -0,0 +1,42 @@
package com.cpop.oam.business.controller.callback;
import com.cpop.core.annontation.SimpleSignatureCheck;
import com.cpop.core.base.R;
import com.cpop.oam.business.bo.CloudUnionCallbackBo;
import com.cpop.oam.framework.enums.CloudCallbackEnums;
import com.cpop.oam.framework.strategy.cloud.CloudCallbackStrategy;
import com.cpop.system.business.vo.SysFileVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
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.RestController;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-16 11:28
*/
@Api(tags = "云回调controller")
@RestController
@RequestMapping("/cloudCallback")
public class CloudCallbackController {
/**
* 云联合回调
* @author DB
* @since 2024/1/16
* @param callback 回调参数
* @return R<Void>
*/
//@SimpleSignatureCheck
@ApiOperation("云联合回调")
@PostMapping("/cloudUnionCallback")
public R<Void> cloudUnionCallback(@RequestBody @Validated CloudUnionCallbackBo callback) {
CloudCallbackStrategy cloudCallbackStrategy = CloudCallbackEnums.valueOf(callback.getCallbackEnum()).getCloudCallbackStrategy();
cloudCallbackStrategy.callback(callback);
return R.ok();
}
}

View File

@ -6,6 +6,7 @@ import com.cpop.oam.business.bo.BusinessInfoPageBo;
import com.cpop.oam.business.bo.BusinessRemoveBo;
import com.cpop.oam.business.vo.BusinessInfoPageVo;
import com.cpop.oam.business.vo.BusinessPageVo;
import com.cpop.oam.business.vo.BusinessUnSignPageVo;
import com.cpop.oam.business.vo.PersonBusinessInfoVo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
@ -69,4 +70,21 @@ public interface BusinessService extends IService<Business> {
* @return PersonBusinessInfoVo
*/
PersonBusinessInfoVo getPersonBusinessInfoById(String id);
/**
* 查询未签约校区分页列表
* @author DB
* @since 2024/1/22
* @param params 请求参数
* @return Page<BusinessUnSignPageVo>
*/
Page<BusinessUnSignPageVo> getUnSignStorePage(String params);
/**
* 校区签约
* @author DB
* @since 2024/1/22
* @param id 主键
*/
void storeSign(String id);
}

View File

@ -83,7 +83,8 @@ public class BrandManagerServiceImpl extends ServiceImpl<BrandManagerMapper, Bra
.and(BRAND_MANAGER.PHONE.like(bo.getPhoneNumber()))
.and(BRAND_MANAGER.NAME.like(bo.getName()))
.and(BRAND.BRAND_NAME.like(bo.getBrandName()))
.groupBy(BRAND_MANAGER.ID),
.groupBy(BRAND_MANAGER.ID)
.orderBy(BRAND_MANAGER.CREATE_TIME.desc()),
BrandManagePageVo.class);
}

View File

@ -26,6 +26,7 @@ import com.cpop.oam.business.service.BusinessService;
import com.cpop.oam.business.service.BusinessStaffService;
import com.cpop.oam.business.vo.BusinessInfoPageVo;
import com.cpop.oam.business.vo.BusinessPageVo;
import com.cpop.oam.business.vo.BusinessUnSignPageVo;
import com.cpop.oam.business.vo.PersonBusinessInfoVo;
import com.cpop.system.business.bo.StoreRenewBo;
import com.cpop.system.business.entity.Store;
@ -49,6 +50,8 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import static com.cpop.jambox.business.entity.table.BrandExtendTableDef.BRAND_EXTEND;
import static com.cpop.jambox.business.entity.table.StoreExtendTableDef.STORE_EXTEND;
import static com.cpop.oam.business.entity.table.BusinessDetailTableDef.BUSINESS_DETAIL;
import static com.cpop.oam.business.entity.table.BusinessStaffTableDef.BUSINESS_STAFF;
import static com.cpop.oam.business.entity.table.BusinessTableDef.BUSINESS;
@ -112,42 +115,12 @@ public class BusinessServiceImpl extends ServiceImpl<BusinessMapper, Business> i
.setStartDate(bo.getStartAndEnd().get(0))
.setEndDate(bo.getStartAndEnd().get(1));
this.save(business);
Integer allSurplusQuantity;
//机构对接
if (business.getBusinessType() == 0){
allSurplusQuantity = createButtJoint(bo, business.getId());
} else {
allSurplusQuantity = createSign(bo,business.getId());
}
Integer allSurplusQuantity = createButtJoint(bo, business.getId());
business.setAllSurplusQuantity(allSurplusQuantity);
this.updateById(business);
//TODO:定时检查事务过期
}
/**
* 事务签约
* @author DB
* @since 2023/12/13
* @param bo 请求
* @param businessId 事务id
* @return Integer
*/
private Integer createSign(BusinessDistributeBo bo, String businessId) {
//事务详情数量标记
AtomicReference<Integer> flag = new AtomicReference<>(0);
if (bo.getSign().isEmpty()){
throw new ServiceException("签约人不能为空");
}
List<BusinessStaff> businessStaffs = BeanUtils.mapToList(bo.getSign(), BusinessStaff.class);
businessStaffs.forEach(item -> {
item.setBusinessId(businessId);
flag.updateAndGet(v -> v + item.getSurplusQuantity());
});
//保存负责员工
SpringUtils.getBean(BusinessStaffService.class).saveBatch(businessStaffs);
return flag.get();
}
/**
* 事务对接
* @author DB
@ -226,68 +199,7 @@ public class BusinessServiceImpl extends ServiceImpl<BusinessMapper, Business> i
*/
@Override
public Page<BusinessInfoPageVo> getBusinessInfoPage(BusinessInfoPageBo bo) {
//获取当前事务
Business business = this.getById(bo.getId());
//对接
if (business.getBusinessType() == 0) {
return getButtJoint(bo);
} else {
//签约
return getSign(bo);
}
}
/**
* 获取签约数据
* @author DB
* @since 2023/12/13
* @param bo 请求
* @return Page<BusinessInfoPageVo>
*/
private Page<BusinessInfoPageVo> getSign(BusinessInfoPageBo bo) {
//获取当前员工信息
JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
QueryWrapper queryWrapper = QueryWrapper.create();
//运营人员
if (loginUserInfo.getInteger("staffType") == 1) {
//查询自己处理中的校区的记录
queryWrapper.and(BUSINESS_STAFF.STAFF_ID.eq(loginUserInfo.getString("id"))
//获取所有无人处理的校区
.or(STORE.ID.notIn(select(distinct(BUSINESS_DETAIL.STORE_ID))
.from(BUSINESS_DETAIL)
.leftJoin(BUSINESS_STAFF).on(BUSINESS_STAFF.ID.eq(BUSINESS_DETAIL.BUSINESS_STAFF_ID))
.where(BUSINESS_STAFF.STAFF_ID.ne(loginUserInfo.getString("id"))
.and(BUSINESS_DETAIL.STORE_ID.isNotNull()))
)));
} else {
queryWrapper.and(BUSINESS_STAFF.STAFF_ID.in(bo.getStaffIds()));
}
PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
return SpringUtils.getBean(StoreService.class).getMapper().paginateAs(Page.of(pageDomain.getPageNum(), pageDomain.getPageSize()),
queryWrapper
.select(BUSINESS_DETAIL.ID.as(BusinessInfoPageVo::getId),BUSINESS_DETAIL.BUSINESS_ID, BUSINESS_DETAIL.DETAIL_STATUS, BUSINESS_DETAIL.DETAIL_DESC, BUSINESS_DETAIL.DETAIL_RECORD_TIME)
//品牌
.select(BRAND.BRAND_NAME)
//校区
.select(STORE.STORE_NAME, STORE.PERSON_CHARGE, STORE.PHONE, STORE.ID.as(BusinessInfoPageVo::getStoreId))
//营业执照
.select(STORE_LICENSE.LICENSE_NAME, STORE_LICENSE.LICENSE_USER_NAME, STORE_LICENSE.LICENSE_ADDR)
.leftJoin(BRAND).on(BRAND.ID.eq(STORE.BRAND_ID))
.leftJoin(STORE_LICENSE).on(STORE_LICENSE.STORE_ID.eq(STORE.ID))
.leftJoin(BUSINESS_DETAIL).on(BUSINESS_DETAIL.STORE_ID.eq(STORE.ID))
.leftJoin(BUSINESS_STAFF).on(BUSINESS_STAFF.ID.eq(BUSINESS_DETAIL.BUSINESS_STAFF_ID))
.leftJoin(STAFF).on(STAFF.ID.eq(BUSINESS_STAFF.STAFF_ID))
//品牌或校区名模糊查询
.and(BRAND.BRAND_NAME.like(bo.getBrandOrStore()).or(STORE.STORE_NAME.like(bo.getBrandOrStore())))
//校区地址或校区名模糊查询
.and(STORE_LICENSE.LICENSE_NAME.like(bo.getAddrOrName()).or(STORE_LICENSE.LICENSE_ADDR.like(bo.getAddrOrName())))
//未签约-非测试
.and(STORE.IS_TEST.eq(false))
.and(STORE.HAVE_ACTIVE.eq(false))
.and(BUSINESS_DETAIL.DETAIL_STATUS.eq(bo.getDetailStatus()))
.orderBy(BUSINESS_DETAIL.CREATE_TIME.asc()),
BusinessInfoPageVo.class);
return getButtJoint(bo);
}
/**
@ -382,23 +294,7 @@ public class BusinessServiceImpl extends ServiceImpl<BusinessMapper, Business> i
.where(BUSINESS_STAFF.BUSINESS_ID.eq(businessDetail.getBusinessId()))
.and(BUSINESS_STAFF.STAFF_ID.eq(loginUserInfo.getString("id")))
.update();
//机构签约
if (business.getBusinessType()== 1){
//校区自动延期一年
StoreSignService storeSignService = SpringUtils.getBean(StoreSignService.class);
StoreSign storeSign = storeSignService.getOne(QueryWrapper.create().where(STORE_SIGN.STORE_ID.eq(bo.getStoreId())));
if (storeSign == null) {
storeSign = new StoreSign();
storeSign.setStoreId(bo.getStoreId());
storeSign.setSignStaffId(loginUserInfo.getString("id"));
storeSignService.save(storeSign);
}
/*storeSign.setSignStaffId(loginUserInfo.getString("id"));
StoreRenewService storeRenewService = SpringUtils.getBean(StoreRenewService.class);
StoreRenewBo storeRenewBo = new StoreRenewBo();
storeRenewBo.setStoreId(bo.getStoreId()).setRenewType(1).setRenewDesc("机构签约自动续费一年").setRenewDate(LocalDate.now().plusYears(1));
storeRenewService.storeRenew(storeRenewBo);*/
}
}
}
@ -459,4 +355,51 @@ public class BusinessServiceImpl extends ServiceImpl<BusinessMapper, Business> i
.and(BUSINESS_STAFF.STAFF_ID.eq(loginUserInfo.getString("id"))),
PersonBusinessInfoVo.class);
}
/**
* 查询未签约校区分页列表
* @author DB
* @since 2024/1/22
* @param params 请求参数
* @return Page<BusinessUnSignPageVo>
*/
@Override
public Page<BusinessUnSignPageVo> getUnSignStorePage(String params) {
PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
return this.pageAs(Page.of(pageDomain.getPageNum(), pageDomain.getPageSize()),
QueryWrapper.create()
.select(STORE.ID, STORE.STORE_NAME, STORE.PERSON_CHARGE, STORE.PHONE, STORE.BRAND_ID)
.select(BRAND.BRAND_NAME)
.select(STORE_LICENSE.LICENSE_PIC_URL)
.select(BRAND_EXTEND.BRAND_CLOUD_ID)
.select(STORE_EXTEND.STORE_CLOUD_ID)
.from(STORE)
.leftJoin(BRAND).on(BRAND.ID.eq(STORE.BRAND_ID))
.leftJoin(STORE_LICENSE).on(STORE_LICENSE.STORE_ID.eq(STORE.ID))
.leftJoin(BRAND_EXTEND).on(BRAND_EXTEND.BRAND_ID.eq(BRAND.ID))
.leftJoin(STORE_EXTEND).on(STORE_EXTEND.STORE_ID.eq(STORE.ID))
.leftJoin(STORE_SIGN).on(STORE_SIGN.ID.eq(STORE.SIGN_ID))
.where(STORE.SIGN_ID.isNull())
.and(STORE.STORE_NAME.like(params)
.or(STORE.PERSON_CHARGE.like(params)
.or(STORE.PHONE.eq(params))))
.orderBy(STORE.CREATE_TIME.desc()),
BusinessUnSignPageVo.class);
}
/**
* 校区签约
* @author DB
* @since 2024/1/22
* @param id 主键
*/
@Override
public void storeSign(String id) {
JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
StoreSign storeSign = new StoreSign();
storeSign.setStoreId(id);
storeSign.setSignStaffId(loginUserInfo.getString("id"));
StoreSignService storeSignService = SpringUtils.getBean(StoreSignService.class);
storeSignService.save(storeSign);
}
}

View File

@ -1,5 +1,6 @@
package com.cpop.oam.business.service.impl;
import cn.hutool.core.util.IdUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelDataConvertException;
@ -12,10 +13,12 @@ import com.cpop.core.base.entity.PageDomain;
import com.cpop.core.base.enums.SourceType;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.handler.TencentCosHandler;
import com.cpop.core.service.RedisService;
import com.cpop.core.utils.SpringUtils;
import com.cpop.core.utils.file.FileUploadUtils;
import com.cpop.core.utils.file.FileUtils;
import com.cpop.core.utils.sql.SqlUtils;
import com.cpop.core.utils.uuid.IdUtils;
import com.cpop.jambox.business.entity.StoreExtend;
import com.cpop.jambox.business.service.StoreExtendService;
import com.cpop.jambox.framework.constant.JamboxCloudUrl;
@ -24,6 +27,7 @@ import com.cpop.oam.business.bo.DataImportPageBo;
import com.cpop.oam.business.dto.DataImportDto;
import com.cpop.oam.business.dto.DataImportParamsDto;
import com.cpop.oam.business.vo.DataImportPageVo;
import com.cpop.oam.framework.constant.OamRedisConstant;
import com.cpop.oam.framework.constant.WebHookKeyConstant;
import com.cpop.system.business.vo.SysFileVo;
import com.mybatisflex.core.paginate.Page;
@ -34,14 +38,17 @@ import com.cpop.oam.business.mapper.DataImportMapper;
import com.cpop.oam.business.service.DataImportService;
import com.qcloud.cos.model.UploadResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.conn.ConnectTimeoutException;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import static com.alibaba.excel.cache.Ehcache.BATCH_COUNT;
import static com.cpop.jambox.business.entity.table.StoreExtendTableDef.STORE_EXTEND;
@ -101,11 +108,36 @@ public class DataImportServiceImpl extends ServiceImpl<DataImportMapper, DataImp
*/
@Override
public void importNow(String id) {
//读取数据
DataImport dataImport = this.getById(id);
importNow(dataImport);
//分布式锁进行幂等处理
RedisService redisService = SpringUtils.getBean(RedisService.class);
//分布式锁进行幂等处理
Lock userIdLock = redisService.distributedLock(OamRedisConstant.DATA_IMPORT_LOCK + id);
if (userIdLock.tryLock()) {
try {
//读取数据
DataImport dataImport = this.getById(id);
if (dataImport.getImportStatus()) {
throw new ServiceException("数据已导入,请刷新页面");
}
importNow(dataImport);
} catch (Exception e) {
throw new ServiceException(e.getMessage());
} finally {
//释放锁
userIdLock.unlock();
}
} else {
//获取锁失败直接返回空
throw new ServiceException("请勿重复导入");
}
}
/**
* 现在导入
* @author DB
* @since 2024/1/15
* @param dataImport 数据导入
*/
@Override
public void importNow(DataImport dataImport) {
//读取数据
@ -121,18 +153,7 @@ public class DataImportServiceImpl extends ServiceImpl<DataImportMapper, DataImp
try {
SpringUtils.getBean(RestTemplate.class).postForObject(JamboxCloudUrl.DATA_IMPORT, dataImportParamsDto, String.class);
} catch (Exception e) {
//数据导入异常通知
try {
SpringUtils.getBean(WebHookSendHandler.class)
.webHookSendText(WebHookKeyConstant.PRODUCT_BOT,
new ArrayList<>(),
"==========有一条校区数据导入失败==========\n" +
"导入id:" + dataImport.getId() + "\n" +
"校区id:" + dataImport.getStoreId() + "\n",
true);
} catch (IOException ex) {
throw new ServiceException("发送消息通知失败!");
}
log.info("数据导入超时,导入id为{}", dataImport.getId());
}
}
@ -155,7 +176,7 @@ public class DataImportServiceImpl extends ServiceImpl<DataImportMapper, DataImp
public void invoke(DataImportDto dataImportDto, AnalysisContext analysisContext) {
//检查手机号
if (StringUtils.isBlank(dataImportDto.getPhone())) {
throw new ServiceException("手机号为空!");
dataImportDto.setPhone(IdUtil.getSnowflakeNextIdStr());
}
//课卡类型
if (StringUtils.isBlank(dataImportDto.getCardType())) {
@ -187,7 +208,7 @@ public class DataImportServiceImpl extends ServiceImpl<DataImportMapper, DataImp
}
//课卡名称
if (StringUtils.isBlank(dataImportDto.getCardName())) {
throw new ServiceException("课卡名称不能为空");
throw new ServiceException(String.format("第%s行课卡名称为空,请核实", analysisContext.readRowHolder().getRowIndex() + 1));
}
//停卡时剩余天数
if (dataImportDto.getStopCardRemainingDays() == null) {
@ -225,9 +246,14 @@ public class DataImportServiceImpl extends ServiceImpl<DataImportMapper, DataImp
if (exception instanceof ExcelDataConvertException) {
ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
throw new ServiceException("" + (excelDataConvertException.getRowIndex() + 1) + "行,第" + (excelDataConvertException.getColumnIndex() + 1) + "列解析异常,数据为:" + excelDataConvertException.getCellData());
} else {
throw new ServiceException(exception.getMessage());
}
}
}).sheet().doRead();
if (cachedDataList.isEmpty()){
throw new ServiceException("导入数据为空,请检查文件内容,按照模板格式导入");
}
tempFile = File.createTempFile(fileName, ".xlsx");
log.info("文件名:{};临时文件地址: {}", fileName, tempFile.getPath());
EasyExcel.write(tempFile.getPath(), DataImportDto.class)

View File

@ -15,6 +15,7 @@ import com.cpop.core.utils.SecurityUtils;
import com.cpop.core.utils.SpringUtils;
import com.cpop.core.utils.sql.SqlUtils;
import com.cpop.oam.business.bo.*;
import com.cpop.oam.business.entity.DataImport;
import com.cpop.oam.business.entity.Staff;
import com.cpop.oam.business.entity.Task;
import com.cpop.oam.business.entity.TaskStaffGroup;
@ -25,8 +26,13 @@ import com.cpop.oam.business.service.TaskStaffGroupService;
import com.cpop.oam.business.service.TaskWorkOrderService;
import com.cpop.oam.business.vo.*;
import com.cpop.oam.framework.constant.OamConfigKey;
import com.cpop.oam.framework.constant.OamRedisConstant;
import com.cpop.oam.framework.constant.WebHookKeyConstant;
import com.cpop.oam.framework.enums.OamConfigEnum;
import com.cpop.system.business.entity.DictData;
import com.cpop.system.business.service.DictDataService;
import com.cpop.system.business.service.DictTypeService;
import com.cpop.system.framework.utils.DictUtils;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
@ -44,6 +50,7 @@ import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;
import static com.cpop.core.base.table.table.SysUserTableDef.SYS_USER;
@ -225,6 +232,11 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
}
}
/**
* 任务评级
*/
private final String OAM_TASK_RATING = "oam_task_rating";
/**
* 技术模块-任务领取-技术人员领取任务
*
@ -235,64 +247,59 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
@Override
@Transactional(rollbackFor = Exception.class)
public void claimTask(String id) {
// 查询任务
Task task = this.getById(id);
// 进行中 接受时间
task.setTaskStatus(2).setTaskReceiptTime(LocalDateTime.now());
// 如果任务没有设置预期完成时间则按照任务评级进行设置默认
if (task.getExpectedCompletionDate() == null) {
// 获取任务评级
String taskRating = task.getTaskRating();
LocalDate now = LocalDate.now();
switch (taskRating) {
case "A":
// 30天
task.setExpectedCompletionDate(now.plusDays(30));
break;
case "B":
// 21天
task.setExpectedCompletionDate(now.plusDays(21));
break;
case "C":
// 15天
task.setExpectedCompletionDate(now.plusDays(15));
break;
case "D":
// 7天
task.setExpectedCompletionDate(now.plusDays(7));
break;
case "E":
// 3天
task.setExpectedCompletionDate(now.plusDays(3));
break;
default:
// 1天
task.setExpectedCompletionDate(now.plusDays(1));
break;
//分布式锁进行幂等处理
RedisService redisService = SpringUtils.getBean(RedisService.class);
//分布式锁进行幂等处理
Lock userIdLock = redisService.distributedLock(OamRedisConstant.TASK_CLAIM_LOCK + id);
if (userIdLock.tryLock()) {
try {
// 查询任务
Task task = this.getById(id);
if (task.getTaskStatus() == 2){
throw new ServiceException("任务已领取,请刷新页面");
}
// 进行中 接受时间
task.setTaskStatus(2).setTaskReceiptTime(LocalDateTime.now());
// 如果任务没有设置预期完成时间则按照任务评级进行设置默认
if (task.getExpectedCompletionDate() == null) {
// 获取任务评级
String taskRating = task.getTaskRating();
LocalDate now = LocalDate.now();
String dictValue = DictUtils.getDictValue(OAM_TASK_RATING, taskRating);
task.setExpectedCompletionDate(now.plusDays(Integer.parseInt(dictValue.split(",")[1])));
}
// 获取当前用户
JSONObject loginUser = SecurityUtils.getInstance().getLoginUserInfo();
if (!Constants.SUPER_ADMIN.equals(loginUser.getString("userName"))) {
// 获取当前员工
Staff staff = SpringUtils.getBean(StaffService.class)
.getOne(QueryWrapper.create().where(STAFF.USER_ID.eq(loginUser.getString("userId"))));
task.setResponsibleStaffId(staff.getId());
}
this.updateById(task);
// 添加主要负责人组
TaskStaffGroup taskStaffGroup = new TaskStaffGroup();
taskStaffGroup.setStaffId(task.getResponsibleStaffId()).setTaskId(id).setGradePoint(task.getTaskWeight());
SpringUtils.getBean(TaskStaffGroupService.class).save(taskStaffGroup);
// 通知所有人
try {
SpringUtils.getBean(WebHookSendHandler.class)
.webHookSendText(WebHookKeyConstant.PRODUCT_BOT,
Collections.singletonList(loginUser.getString("phoneNumber")),
"==========任务领取==========" + "\n" + task.getTaskContent(),
false);
} catch (IOException e) {
throw new ServiceException("发送任务领取通知失败!");
}
} catch (Exception e) {
throw new ServiceException(e.getMessage());
} finally {
//释放锁
userIdLock.unlock();
}
}
// 获取当前用户
JSONObject loginUser = SecurityUtils.getInstance().getLoginUserInfo();
if (!Constants.SUPER_ADMIN.equals(loginUser.getString("userName"))) {
// 获取当前员工
Staff staff = SpringUtils.getBean(StaffService.class)
.getOne(QueryWrapper.create().where(STAFF.USER_ID.eq(loginUser.getString("userId"))));
task.setResponsibleStaffId(staff.getId());
}
this.updateById(task);
// 添加主要负责人组
TaskStaffGroup taskStaffGroup = new TaskStaffGroup();
taskStaffGroup.setStaffId(task.getResponsibleStaffId()).setTaskId(id).setGradePoint(task.getTaskWeight());
SpringUtils.getBean(TaskStaffGroupService.class).save(taskStaffGroup);
// 通知所有人
try {
SpringUtils.getBean(WebHookSendHandler.class)
.webHookSendText(WebHookKeyConstant.PRODUCT_BOT,
Collections.singletonList(loginUser.getString("phoneNumber")),
"==========任务领取==========" + "\n" + task.getTaskContent(),
false);
} catch (IOException e) {
throw new ServiceException("发送任务领取通知失败!");
} else {
//获取锁失败直接返回空
throw new ServiceException("请勿重复领取");
}
}
@ -346,27 +353,34 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
.where(STAFF.ID.eq(staffId)));
//对比当前员工是否是测试管理员
if (!Arrays.asList(testStaffPhones.split(",")).contains(staff.getString("phoneNumber"))) {
queryWrapper.and(TASK.TASK_STATUS.in(2, 3))
queryWrapper.and(TASK.TASK_STATUS.in(2, 3, 8, 9))
.and(TASK_STAFF_GROUP.STAFF_ID.eq(staffId));
} else {
//测试人员
queryWrapper.and(TASK.TASK_STATUS.eq(3))
queryWrapper.and(TASK.TASK_STATUS.in(3, 8, 9))
.groupBy(TASK.ID);
}
} else {
JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
//对比当前员工是否是测试管理员
if (!Arrays.asList(testStaffPhones.split(",")).contains(loginUserInfo.getString("phoneNumber"))) {
queryWrapper.and(TASK.TASK_STATUS.in(2, 3))
queryWrapper.and(TASK.TASK_STATUS.in(2, 3, 8, 9))
.and(TASK_STAFF_GROUP.STAFF_ID.eq(loginUserInfo.getString("id")));
} else {
//测试人员
queryWrapper.and(TASK.TASK_STATUS.eq(3))
queryWrapper.and(TASK.TASK_STATUS.in(3, 8, 9))
.groupBy(TASK.ID);
}
}
if (startDate != null && endDate != null) {
queryWrapper.and(dateFormat(TASK.TASK_RECEIPT_TIME, "%Y-%m-%d").between(startDate, endDate));
} else {
LocalDate date = LocalDate.now();
// 获取当前月的第一天
LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth());
// 获取当前月的最后一天
LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth());
queryWrapper.and(dateFormat(TASK.TASK_RECEIPT_TIME, "%Y-%m-%d").between(firstDay, lastDay));
}
return this.mapper.paginateAs(pageDomain.getPageNum(),
pageDomain.getPageSize(),
@ -741,7 +755,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
//所有技术员工信息
Map<String, Staff> staffMap = SpringUtils.getBean(StaffService.class).queryChain()
.leftJoin(SYS_USER).on(SYS_USER.ID.eq(STAFF.USER_ID))
.where(STAFF.STAFF_TYPE.eq(0))
.where(STAFF.STAFF_TYPE.in(0, 2))
.and(SYS_USER.STATUS.eq(1))
.list()
.stream().collect(Collectors.toMap(Staff::getId, item -> item));
@ -784,7 +798,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
queryWrapper.and(TASK_STAFF_GROUP.STAFF_ID.eq(loginUserInfo.getString("id")));
}
if (startDate!=null && endDate!=null){
if (startDate != null && endDate != null) {
queryWrapper.and(dateFormat(TASK.TASK_RECEIPT_TIME, "%Y-%m-%d").between(startDate, endDate));
} else {
LocalDate now = LocalDate.now();

View File

@ -0,0 +1,71 @@
package com.cpop.oam.business.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-22 13:47
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "校区/店铺未签约分页返回对象")
public class BusinessUnSignPageVo {
/**
* 校区id
*/
@ApiModelProperty(value = "校区id")
private String id;
/**
* 校区名
*/
@ApiModelProperty(value = "校区名")
private String storeName;
/**
* 负责人
*/
@ApiModelProperty(value = "负责人")
private String personCharge;
/**
* 手机号
*/
@ApiModelProperty(value = "手机号")
private String phone;
/**
* 营业执照地址
*/
@ApiModelProperty(value = "营业执照地址")
private String licensePicUrl;
/**
* 云校区id
*/
@ApiModelProperty(value = "云校区id")
private String storeCloudId;
/**
* 品牌id
*/
@ApiModelProperty(value = "品牌id")
private String brandId;
/**
* 云品牌id
*/
@ApiModelProperty(value = "云品牌id")
private String brandCloudId;
/**
* 品牌名
*/
@ApiModelProperty(value = "品牌名")
private String brandName;
}

View File

@ -0,0 +1,19 @@
package com.cpop.oam.framework.constant;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-19 14:51
*/
public interface OamRedisConstant {
/**
* 数据导入幂等锁
*/
String DATA_IMPORT_LOCK = "oam:dataImportLock:dataImport:";
/**
* 任务领取幂等锁
*/
String TASK_CLAIM_LOCK = "oam:taskClaimLock:task:";
}

View File

@ -0,0 +1,50 @@
package com.cpop.oam.framework.enums;
import com.cpop.core.utils.SpringUtils;
import com.cpop.oam.framework.strategy.cloud.CloudCallbackStrategy;
import com.cpop.oam.framework.strategy.cloud.CloudDataImportCallbackStrategy;
import com.cpop.oam.framework.strategy.cloud.CloudSyncBrandOrStoreCallbackStrategy;
import lombok.Getter;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-16 11:38
*/
@Getter
public enum CloudCallbackEnums {
/**
* 数据导入回调
*/
DATA_IMPORT_CALLBACK(0, "dataImportCallback", SpringUtils.getBean(CloudDataImportCallbackStrategy.class)),
/**
* 同步品牌与校区回调
*/
SYNC_BRAND_AND_STORE_CALLBACK(1, "syncBrandAndStoreCallback", SpringUtils.getBean(CloudSyncBrandOrStoreCallbackStrategy.class))
;
CloudCallbackEnums(Integer code, String name, CloudCallbackStrategy cloudCallbackStrategy) {
this.code = code;
this.name = name;
this.cloudCallbackStrategy = cloudCallbackStrategy;
}
private Integer code;
private String name;
private CloudCallbackStrategy cloudCallbackStrategy;
public void setCode(Integer code) {
this.code = code;
}
public void setName(String name) {
this.name = name;
}
public void setCloudCallbackStrategy(CloudCallbackStrategy cloudCallbackStrategy) {
this.cloudCallbackStrategy = cloudCallbackStrategy;
}
}

View File

@ -0,0 +1,19 @@
package com.cpop.oam.framework.strategy.cloud;
import com.cpop.oam.business.bo.CloudUnionCallbackBo;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-16 11:42
*/
public interface CloudCallbackStrategy {
/**
* 回调
* @author DB
* @since 2024/1/16
*/
void callback(CloudUnionCallbackBo callback);
}

View File

@ -0,0 +1,43 @@
package com.cpop.oam.framework.strategy.cloud;
import com.cpop.api.tencent.wxWork.handler.WebHookSendHandler;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.utils.SpringUtils;
import com.cpop.oam.business.bo.CloudUnionCallbackBo;
import com.cpop.oam.business.entity.DataImport;
import com.cpop.oam.business.service.DataImportService;
import com.cpop.oam.framework.constant.WebHookKeyConstant;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.ArrayList;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-16 11:44
*/
@Component
public class CloudDataImportCallbackStrategy implements CloudCallbackStrategy {
/**
* 回调策略
*/
@Override
public void callback(CloudUnionCallbackBo callback) {
DataImportService dataImportService = SpringUtils.getBean(DataImportService.class);
DataImport dataImport = dataImportService.getById(callback.getMainId());
//数据导入异常通知
try {
SpringUtils.getBean(WebHookSendHandler.class)
.webHookSendText(WebHookKeyConstant.PRODUCT_BOT,
new ArrayList<>(),
"==========有一条校区数据导入失败==========\n" +
"导入id:" + dataImport.getId() + "\n" +
"校区id:" + dataImport.getStoreId() + "\n",
true);
} catch (IOException ex) {
throw new ServiceException("发送消息通知失败!");
}
}
}

View File

@ -0,0 +1,84 @@
package com.cpop.oam.framework.strategy.cloud;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.core.base.entity.LoginUser;
import com.cpop.core.base.enums.SourceType;
import com.cpop.core.utils.SecurityUtils;
import com.cpop.core.utils.SpringUtils;
import com.cpop.oam.business.bo.CloudUnionCallbackBo;
import com.cpop.system.business.bo.SyncBrandAndStoreBo;
import com.cpop.system.business.entity.Brand;
import com.cpop.system.business.entity.Store;
import com.cpop.system.business.entity.StoreLicense;
import com.cpop.system.business.service.BrandService;
import com.cpop.system.business.service.StoreLicenseService;
import com.cpop.system.business.service.StoreService;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.DbChain;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.row.RowKey;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
*
* @author DB
* @version 1.0.0
* @since 2024-01-16 14:37
*/
@Component
public class CloudSyncBrandOrStoreCallbackStrategy implements CloudCallbackStrategy{
/**
* 回调策略
* @author DB
* @since 2024/1/16
* @param callback 回调参数
*/
@Override
public void callback(CloudUnionCallbackBo callback) {
SyncBrandAndStoreBo.BrandInfo brandInfo = callback.getSyncBrandAndStore().getBrandInfo();
//查询品牌
Row brandExtend = DbChain.table("cp_j_brand_extend").where("brand_cloud_id = ?", brandInfo.getBrandCloudId()).one();
Brand brand;
LocalDateTime now = LocalDateTime.now();
LoginUser loginUser = SecurityUtils.getInstance().getLoginUser();
BrandService brandService = SpringUtils.getBean(BrandService.class);
if (brandExtend.isEmpty()) {
brand = new Brand();
brand.setBrandName(brandInfo.getBrandName()).setSourceType(SourceType.JAMBOX.toString());
brandService.save(brand);
//保存拓展
RowKey brandKey = RowKey.SNOW_FLAKE_ID;
DbChain.table("cp_j_brand_extend")
.setId(brandKey)
.set("brand_id", brand.getId())
.set("brand_cloud_id", brandInfo.getBrandCloudId())
.set("create_time", now)
.set("update_time", now)
.set("create_user_id", loginUser == null ? "1" : loginUser.getUserId())
.set("update_user_id", loginUser == null ? "1" : loginUser.getUserId())
.save();
}else {
brand = brandService.getById(brandExtend.getString("brandId"));
}
SyncBrandAndStoreBo.StoreInfo storeInfo = callback.getSyncBrandAndStore().getStoreInfo();
Store store = BeanUtils.mapToClass(storeInfo, Store.class);
store.setBrandId(brand.getId()).setSourceType(SourceType.JAMBOX.toString());
SpringUtils.getBean(StoreService.class).save(store);
//拓展
Row row = Row.ofKey(RowKey.SNOW_FLAKE_ID);
row.set("store_cloud_id", storeInfo.getStoreCloudId());
row.set("store_id", store.getId());
row.set("create_time", now);
row.set("update_time", now);
row.set("create_user_id", loginUser == null ? "1" : loginUser.getUserId());
row.set("update_user_id", loginUser == null ? "1" : loginUser.getUserId());
Db.insert("cp_j_store_extend",row);
//营业执照
StoreLicense storeLicense = BeanUtils.mapToClass(storeInfo, StoreLicense.class);
storeLicense.setStoreId(store.getId());
SpringUtils.getBean(StoreLicenseService.class).save(storeLicense);
}
}

View File

@ -41,6 +41,7 @@ public class WxPayConfiguration {
payConfig.setPrivateCertPath(this.properties.getPrivateCertPath());
//通知地址
payConfig.setNotifyUrl(this.properties.getNotifyUrl());
payConfig.setServiceId(this.properties.getServiceId());
// 可以指定是否使用沙箱环境
payConfig.setUseSandboxEnv(false);
WxPayService wxPayService = new WxPayServiceImpl();

View File

@ -81,4 +81,23 @@ public class WxPayProperties {
*/
private String easyLearnUnionPayNotifyUrl;
/**
* 服务id
*/
private String serviceId;
/**
* 服务商模式下的子商户公众账号ID
*/
private String serviceAppId;
/**
* 先学后付用户签约计划通知地址
*/
private String learnNowPayLaterUserSignPlanNotifyUrl;
/**
* 先学后付用户支付成功通知地址
*/
private String learnNowPayLaterServiceOrderNotifyUrl;
}

View File

@ -1,27 +1,21 @@
package com.cpop.pay.framewok.handler.wxPay;
import com.alibaba.fastjson.JSONObject;
import com.cpop.common.utils.ServletUtils;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.exception.UtilException;
import com.cpop.core.utils.SecurityUtils;
import com.cpop.pay.framewok.core.dto.LearnNowPayLaterPlanDto;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreSignPlanRequest;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreSignPlanResult;
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.PartnerPayScoreSignPlanService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.row.RowKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
/**
* @author DB
@ -29,6 +23,7 @@ import java.util.ArrayList;
* @description
*/
@Component
@Slf4j
public class WxPayHandler {
@Autowired
@ -142,48 +137,19 @@ public class WxPayHandler {
}
/**
* 创建支付分计划
* 获取签约头
* @author DB
* @since 2024/1/8
* @param wxPayService 微信支付
* @param dto 先学后付计划
* @return WxPartnerPayScoreSignPlanResult
* @since 2024/1/20
* @return SignatureHeader
*/
@Transactional(rollbackFor = Exception.class)
public WxPartnerPayScoreSignPlanResult createPayScorePlan(WxPayService wxPayService, LearnNowPayLaterPlanDto dto) {
Row row = Row.ofKey(RowKey.SNOW_FLAKE_ID);
row.set("sign_account", wxPayService.getConfig().getSubMchId());
row.set("plan_name", dto.getPlanName());
row.set("plan_duration", dto.getPlanDuration());
row.set("deduction_quantity", dto.getDeductionQuantity());
row.set("total_original_price", dto.getTotalOriginalPrice());
row.set("total_actual_price", dto.getTotalActualPrice());
row.set("plan_source", dto.getOrderSource().toString());
//插入计划
Db.insert("cp_sys_wx_pay_score", row);
PartnerPayScoreSignPlanService partnerPayScoreSignPlanService = wxPayService.getPartnerPayScoreSignPlanService();
WxPartnerPayScoreSignPlanRequest planRequest = BeanUtils.mapToClass(dto, WxPartnerPayScoreSignPlanRequest.class);
planRequest.setMerchantPlanNo(row.getString("id"));
WxPartnerPayScoreSignPlanResult plans;
try {
plans = partnerPayScoreSignPlanService.createPlans(planRequest);
} catch (WxPayException e) {
throw new UtilException(e);
}
ArrayList<Row> detailRows = new ArrayList<>();
//更新计划详情
plans.getPlanDetailList().forEach(item -> {
Row detailRow = Row.ofKey(RowKey.SNOW_FLAKE_ID);
detailRow.set("sys_wx_pay_score_id", row.getString("id"));
detailRow.set("plan_detail_no", item.getPlanDetailNo());
detailRow.set("original_price", item.getOriginalPrice());
detailRow.set("actual_price", item.getActualPrice());
detailRow.set("plan_discount_description", item.getPlanDiscountDescription());
detailRow.set("plan_detail_name", item.getPlanDetailName());
detailRows.add(detailRow);
});
//批量插入
Db.insertBatch("cp_sys_wx_pay_score_detail", detailRows);
return plans;
public SignatureHeader getSignatureHeader() {
HttpServletRequest request = ServletUtils.getRequest();
SignatureHeader signatureHeader = new SignatureHeader();
signatureHeader.setSigned(request.getHeader("Wechatpay-Signature"));
signatureHeader.setNonce(request.getHeader("Wechatpay-Nonce"));
signatureHeader.setSerialNo(request.getHeader("Wechatpay-Serial"));
signatureHeader.setTimeStamp(request.getHeader("Wechatpay-Timestamp"));
log.info("微信支付分回调ID:{}",request.getHeader("Request-ID"));
return signatureHeader;
}
}

View File

@ -142,7 +142,7 @@ public class WxPayAsyncTask {
throw new ServiceException(profitSharingResult.getReturnMsg());
}
} catch (WxPayException e) {
if (flag > 5) {
if (flag > 2) {
if (OrderSource.MALL == orderSource) {
//关闭商城支付
DbChain.table("cp_sys_brand")

View File

@ -2,12 +2,16 @@ wx:
#微信支付
pay:
#微信公众号或者小程序等的appid
appId: wx20853d18c455e874
app-id: wx20853d18c455e874
#微信支付商户号
mchId: 1618884922
mch-id: 1618884922
#微信支付商户密钥
mchKey: JamBox20230919174000000000000002
apiV3Key: JamBox20230919174000000000000002
mch-key: JamBox20230919174000000000000002
api-v3-key: JamBox20230919174000000000000002
#服务id
service-id: 00003053000000169450961228104460
#分账服务商账号
sharingAccount: 1618884922
sharingAccountName: 果酱盒子
sharing-account: 1618884922
sharing-account-name: 果酱盒子
#服务商appid
service-app-id: wx1eb0e5fb7dac3c05

View File

@ -24,6 +24,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.cpop</groupId>
<artifactId>Cpop-Api</artifactId>
</dependency>
</dependencies>
<build>

Some files were not shown because too many files have changed in this diff Show More