diff --git a/Cpop-Core/src/main/java/com/cpop/core/config/AsyncScheduledTaskConfig.java b/Cpop-Core/src/main/java/com/cpop/core/config/AsyncScheduledTaskConfig.java index 5836703..095fb9a 100644 --- a/Cpop-Core/src/main/java/com/cpop/core/config/AsyncScheduledTaskConfig.java +++ b/Cpop-Core/src/main/java/com/cpop/core/config/AsyncScheduledTaskConfig.java @@ -42,7 +42,7 @@ public class AsyncScheduledTaskConfig { //允许线程的空闲时间30秒 executor.setKeepAliveSeconds(config.getKeepAliveSeconds()); //设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean - executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setWaitForTasksToCompleteOnShutdown(false); //设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住 executor.setAwaitTerminationSeconds(config.getAwaitTerminationSeconds()); /** diff --git a/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application-dev.yml b/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application-dev.yml index eb72a9a..7ca37c9 100644 --- a/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application-dev.yml +++ b/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application-dev.yml @@ -4,7 +4,7 @@ cpop: profile: E:/Cpop/uploadPath jwt: #白名单 - whiteList: /login,/miniLogin,/wxPay/callback/notify/**,/mini/brand/jamboxBrandIsInMall/*,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources + whiteList: /login,/miniLogin,/test/**,/wxPay/callback/notify/**,/mini/brand/jamboxBrandIsInMall/*,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources gateway: rsa-keypair: # 公钥文件 @@ -85,11 +85,17 @@ knife4j: api-rule-resources: - com.cpop.mall.business.controller.backstage Mall-Mini: - #后台 + #小程序 group-name: Mall-Mini api-rule: package api-rule-resources: - com.cpop.mall.business.controller.mini + Mall-Test: + #测试 + group-name: Mall-Test + api-rule: package + api-rule-resources: + - com.cpop.mall.business.controller.test #系统 System: group-name: System diff --git a/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application-prod.yml b/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application-prod.yml index 7b8880a..e4a58f3 100644 --- a/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application-prod.yml +++ b/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application-prod.yml @@ -4,7 +4,7 @@ cpop: profile: /root/cpop-union/cpop-mall/upload jwt: #白名单 - whiteList: /login,/miniLogin,/wxPay/callback/notify/**,/profile/** + whiteList: /login,/miniLogin,/mini/brand/jamboxBrandIsInMall/*,/wxPay/callback/notify/**,/profile/** #拦截 gateway: rsa-keypair: diff --git a/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application-test.yml b/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application-test.yml index 6ccd3e1..1413eb1 100644 --- a/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application-test.yml +++ b/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application-test.yml @@ -4,7 +4,7 @@ cpop: profile: /root/cpop-union/cpop-mall/upload jwt: #白名单 - whiteList: /login,/miniLogin,/wxPay/callback/notify/**,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*,/wxCp/portal/* + whiteList: /login,/miniLogin,/mini/brand/jamboxBrandIsInMall/*,/wxPay/callback/notify/**,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*,/wxCp/portal/* #拦截 gateway: rsa-keypair: diff --git a/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application.yml b/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application.yml index fd7e98e..82ec1b6 100644 --- a/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application.yml +++ b/Cpop-Mall/Cpop-Mall-Web/src/main/resources/application.yml @@ -31,7 +31,7 @@ spring: max-file-size: 1024MB max-request-size: 300MB profiles: - active: local,core,mall,system + active: dev,core,mall,system datasource: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver @@ -106,7 +106,7 @@ task: # 设置空闲线程存活时间(秒 keepAliveSeconds: 300 # 设置队列容量 - queueCapacity: 100 + queueCapacity: 10240 # 设置线程名称前缀 threadNamePrefix: "Cpop-Mall-AsyncNotify-" # 设置线程池等待终止时间(秒) @@ -131,11 +131,11 @@ wx: #微信支付 pay: #微信公众号或者小程序等的appid - appId: wx1eb0e5fb7dac3c05 + appId: wx20853d18c455e874 #微信支付商户号 mchId: 1618884922 #微信支付商户密钥 mchKey: JamBox20230919174000000000000002 apiV3Key: JamBox20230919174000000000000002 - #服务商账号 - sharingAccount: 1618436087 + #分账服务商账号 + sharingAccount: 1618884922 diff --git a/Cpop-Mall/Cpop-Mall-Web/src/test/java/com/cpop/mall/web/CpopWxPayTests.java b/Cpop-Mall/Cpop-Mall-Web/src/test/java/com/cpop/mall/web/CpopWxPayTests.java index 1884f5b..a6c8a9c 100644 --- a/Cpop-Mall/Cpop-Mall-Web/src/test/java/com/cpop/mall/web/CpopWxPayTests.java +++ b/Cpop-Mall/Cpop-Mall-Web/src/test/java/com/cpop/mall/web/CpopWxPayTests.java @@ -38,7 +38,7 @@ public class CpopWxPayTests { @Test public void refund() throws WxPayException { Brand brand = SpringUtils.getBean(BrandService.class).getById("75140168047210496"); - Order order = SpringUtils.getBean(OrderService.class).getById("77257142464598016"); + Order order = SpringUtils.getBean(OrderService.class).getById("77602361596874752"); WxPayRefundV3Request request = new WxPayRefundV3Request(); WxPayRefundV3Request.Amount amount = new WxPayRefundV3Request.Amount(); //退款金额(单位分) diff --git a/Cpop-Mall/src/main/java/com/cpop/mall/business/controller/test/TestController.java b/Cpop-Mall/src/main/java/com/cpop/mall/business/controller/test/TestController.java new file mode 100644 index 0000000..c46914e --- /dev/null +++ b/Cpop-Mall/src/main/java/com/cpop/mall/business/controller/test/TestController.java @@ -0,0 +1,55 @@ +package com.cpop.mall.business.controller.test; + +import com.cpop.core.base.R; +import com.cpop.mall.business.bo.MallRoleBo; +import com.cpop.mall.business.bo.MallRolePageBo; +import com.cpop.mall.business.service.RoleBrandService; +import com.cpop.mall.business.task.ProductRecordSyncStockTask; +import com.cpop.mall.business.vo.MallRolePageVo; +import com.cpop.system.business.bo.MenuListBo; +import com.cpop.system.business.bo.RoleStatusBo; +import com.cpop.system.business.service.MenuService; +import com.cpop.system.business.vo.MenuVo; +import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse; +import com.mybatisflex.core.paginate.Page; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author DB + * @createTime 2023/10/19 18:14 + * @description + */ +@RestController +@Api(tags = "商城测试接口") +@RequestMapping("/test") +public class TestController { + + @Autowired + private ProductRecordSyncStockTask productRecordSyncStockTask; + + /** + * @descriptions 并发批量扣减库存测试 + * @author DB + * @date 2023/11/02 9:47 + * @return: java.lang.String + */ + @ApiOperation("并发批量扣减库存测试") + @PostMapping("/concurrencyDeductionStockTest") + public R concurrencyDeductionStockTest(){ + for (int i = 0; i < 10000; i++) { + Map map = new HashMap<>(1); + map.put("77212443863334912", 1); + productRecordSyncStockTask.asyncUpdateRecords(map); + } + return R.ok(); + } +} diff --git a/Cpop-Mall/src/main/java/com/cpop/mall/business/service/impl/OrderServiceImpl.java b/Cpop-Mall/src/main/java/com/cpop/mall/business/service/impl/OrderServiceImpl.java index c6aff6e..1f518e9 100644 --- a/Cpop-Mall/src/main/java/com/cpop/mall/business/service/impl/OrderServiceImpl.java +++ b/Cpop-Mall/src/main/java/com/cpop/mall/business/service/impl/OrderServiceImpl.java @@ -25,12 +25,15 @@ import com.cpop.mall.business.vo.OrderPageVo; import com.cpop.mall.framework.config.wxPay.WxPayProperties; import com.cpop.mall.framework.constant.MallRedisConstant; import com.cpop.mall.framework.handler.WxPayHandler; +import com.cpop.system.business.entity.Brand; import com.cpop.system.business.entity.ProfitSharing; +import com.cpop.system.business.service.BrandService; import com.cpop.system.business.service.ProfitSharingService; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; +import com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingReceiverRequest; +import com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingRequest; +import com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingResult; import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingReceiver; -import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingRequest; -import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingResult; import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.service.WxPayService; @@ -136,9 +139,9 @@ public class OrderServiceImpl extends ServiceImpl implements public Object placeOrder(PlaceOrderBo bo) { RedisService redisService = SpringUtils.getBean(RedisService.class); //获取当前下单用户信息 - JSONObject loginStaffInfo = SecurityUtils.getInstance().getLoginUserInfo(); + JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo(); //分布式锁进行幂等处理 - Lock userIdLock = redisService.distributedLock(MallRedisConstant.IDEMPOTENT_LOCK_USER_PAY + loginStaffInfo.getString("userId")); + Lock userIdLock = redisService.distributedLock(MallRedisConstant.IDEMPOTENT_LOCK_USER_PAY + loginUserInfo.getString("userId")); if (userIdLock.tryLock()) { //检查库存 Map recordNumIsEnough = recordNumIsEnough(bo.getPlaceOrderDetailList()); @@ -159,11 +162,11 @@ public class OrderServiceImpl extends ServiceImpl implements order.setOrderStatus(0) .setPreviousStatus(0) //获取当前用户所属品牌 - .setBrandId(loginStaffInfo.getString("brandId")) + .setBrandId(loginUserInfo.getString("brandId")) .setProductNames(productList.stream().map(Product::getProductName).collect(Collectors.joining(","))) - .setPayUserId(loginStaffInfo.getString("userId")); + .setPayUserId(loginUserInfo.getString("userId")); if (StringUtils.isBlank(bo.getPayUserName())) { - order.setPayUserName(loginStaffInfo.getString("nickName")); + order.setPayUserName(loginUserInfo.getString("nickName")); } this.save(order); //保存订单详情 @@ -173,11 +176,18 @@ public class OrderServiceImpl extends ServiceImpl implements SpringUtils.getBean(OrderDetailService.class).saveBatch(orderDetails); //微信支付 if (bo.getPayType() == 0) { + //微信支付统一下单 + WxPayService wxPayService = wxPayHandler.getWxPayService(); WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest(); - //需要分账 - orderRequest.setProfitSharing("Y") - .setSpbillCreateIp(IpUtils.getHostIp()) - .setSubOpenid(loginStaffInfo.getString("openId")) + //查询是否是服务商系品牌 + String brandId = loginUserInfo.getString("brandId"); + Brand brand = SpringUtils.getBean(BrandService.class).getById(brandId); + if (StringUtils.isBlank(brand.getWxAppId()) || !StringUtils.equals(brand.getWxAppId(), wxPayService.getConfig().getAppId())) { + //需要分账 + orderRequest.setProfitSharing("Y"); + } + orderRequest.setSpbillCreateIp(IpUtils.getHostIp()) + .setOpenid(loginUserInfo.getString("openId")) //商品描述 .setBody(productList.stream().map(Product::getDescription).collect(Collectors.joining(","))) //商品详情 @@ -186,8 +196,6 @@ public class OrderServiceImpl extends ServiceImpl implements //元转分 .setTotalFee(bo.getTotalAmount().scaleByPowerOfTen(2).intValue()) .setTradeType("JSAPI"); - //微信支付统一下单 - WxPayService wxPayService = wxPayHandler.getWxPayService(); return wxPayService.createOrder(orderRequest); } else { return pointPay(recordNumIsEnough, order.getId()); @@ -317,34 +325,14 @@ public class OrderServiceImpl extends ServiceImpl implements .where(ORDER_DETAIL.ORDER_ID.eq(orderId)).list(); //订单数量集合 Map orderNumMap = orderDetails.stream().collect(Collectors.toMap(OrderDetail::getProductRecordId, OrderDetail::getNumber)); - //TODO:分账先注释 - ProfitSharing profitSharing = new ProfitSharing(); - profitSharing.setOrderId(orderId) - .setProfitSharingStatus(0) - .setOrderSource(OrderSource.MALL.toString()); - ProfitSharingService profitSharingService = SpringUtils.getBean(ProfitSharingService.class); - profitSharingService.save(profitSharing); - ProfitSharingRequest sharingRequest = new ProfitSharingRequest(); - ProfitSharingReceiver profitSharingReceiver = new ProfitSharingReceiver(); - List profitSharingReceivers = new ArrayList<>(); - Double ceil = Math.ceil(notifyResult.getTotalFee() * OrderSource.MALL.getRate()); - profitSharingReceiver.setAmount(ceil.longValue()); - profitSharingReceiver.setDescription("向服务商分账"); - profitSharingReceiver.setType("MERCHANT_ID"); - profitSharingReceiver.setRelationType("SERVICE_PROVIDER"); - profitSharingReceiver.setAccount(wxPayProperties.getSharingAccount()); - profitSharingReceivers.add(profitSharingReceiver); - sharingRequest.setTransactionId(notifyResult.getTransactionId()); - sharingRequest.setOutOrderNo(profitSharing.getOrderId()); - //分账结束 - sharingRequest.setUnfreezeUnsplit(true); - sharingRequest.setAppid(wxPayProperties.getAppId()); - sharingRequest.setReceivers(profitSharingReceivers); - ProfitSharingResult profitSharingResult = wxPayService.getProfitSharingV3Service().profitSharing(sharingRequest); - //更新分账订单 - profitSharingService.updateChain().set(PROFIT_SHARING.OUT_PROFIT_SHARING_ID,profitSharingResult.getOrderId()) - .set(PROFIT_SHARING.AMOUNT, ceil.longValue()).set(PROFIT_SHARING.PROFIT_SHARING_STATUS, 1).set(PROFIT_SHARING.PAY_ACCOUNT, wxPayProperties.getSharingAccount()) - .where(PROFIT_SHARING.ID.eq(profitSharing.getId())).update(); + //查询订单信息 + Order order = this.getById(orderId); + //获取订单品牌信息 + Brand brand = SpringUtils.getBean(BrandService.class).getById(order.getBrandId()); + if (StringUtils.isBlank(brand.getWxAppId()) || !StringUtils.equals(brand.getWxAppId(), wxPayService.getConfig().getAppId())) { + //需要分账 + wxPayProfitSharing(orderId, notifyResult, wxPayService); + } //异步更新 SpringUtils.getBean(ProductRecordSyncStockTask.class).asyncUpdateRecords(orderNumMap); } catch (WxPayException e) { @@ -352,6 +340,51 @@ public class OrderServiceImpl extends ServiceImpl implements } } + /** + * @descriptions 微信支付分账 + * @author DB + * @date 2023/11/02 15:26 + * @param orderId 订单id + * @param notifyResult 微信支付结果 + * @param wxPayService 微信支付 + * @return: void + */ + private void wxPayProfitSharing(String orderId, WxPayOrderNotifyResult notifyResult, WxPayService wxPayService) throws WxPayException { + ProfitSharing profitSharing = new ProfitSharing(); + profitSharing.setOrderId(orderId) + .setProfitSharingStatus(0) + .setOrderSource(OrderSource.MALL.toString()); + ProfitSharingService profitSharingService = SpringUtils.getBean(ProfitSharingService.class); + profitSharingService.save(profitSharing); + Double ceil = Math.ceil(notifyResult.getTotalFee() * OrderSource.MALL.getRate()); + //固定商户信息 + Map mapReceiver = new HashMap<>(4); + mapReceiver.put("type", "MERCHANT_ID"); + mapReceiver.put("account", wxPayProperties.getSharingAccount()); + mapReceiver.put("relation_type", "SERVICE_PROVIDER"); + mapReceiver.put("amount", ceil.longValue()); + mapReceiver.put("name","果酱盒子"); + mapReceiver.put("description", "分账到服务商"); + /* + //添加分账接收方 + ProfitSharingReceiverRequest profitSharingReceiver = new ProfitSharingReceiverRequest(); + profitSharingReceiver.setReceiver(JSONObject.toJSONString(mapReceiver)); + wxPayService.getProfitSharingService().addReceiver(profitSharingReceiver);*/ + //分账 + ProfitSharingRequest profitSharingRequest = new ProfitSharingRequest(); + List> receivers = new ArrayList<>(1); + receivers.add(mapReceiver); + profitSharingRequest.setReceivers(JSONObject.toJSONString(receivers)); + profitSharingRequest.setSignType("HMAC-SHA256"); + profitSharingRequest.setOutOrderNo(profitSharing.getId()); + profitSharingRequest.setTransactionId(notifyResult.getTransactionId()); + ProfitSharingResult profitSharingResult = wxPayService.getProfitSharingService().profitSharing(profitSharingRequest); + //更新分账订单 + profitSharingService.updateChain().set(PROFIT_SHARING.OUT_PROFIT_SHARING_ID, profitSharingResult.getOrderId()) + .set(PROFIT_SHARING.AMOUNT, ceil.longValue()).set(PROFIT_SHARING.PROFIT_SHARING_STATUS, 1).set(PROFIT_SHARING.PAY_ACCOUNT, wxPayProperties.getSharingAccount()) + .where(PROFIT_SHARING.ID.eq(profitSharing.getId())).update(); + } + /** * @descriptions 取消订单 * @author DB diff --git a/Cpop-Mall/src/main/java/com/cpop/mall/framework/config/wxPay/WxPayProperties.java b/Cpop-Mall/src/main/java/com/cpop/mall/framework/config/wxPay/WxPayProperties.java index c997062..a5e2724 100644 --- a/Cpop-Mall/src/main/java/com/cpop/mall/framework/config/wxPay/WxPayProperties.java +++ b/Cpop-Mall/src/main/java/com/cpop/mall/framework/config/wxPay/WxPayProperties.java @@ -26,16 +26,6 @@ public class WxPayProperties { */ private String mchKey; - /** - * 服务商模式下的子商户公众账号ID,普通模式请不要配置,请在配置文件中将对应项删除 - */ - private String subAppId; - - /** - * 服务商模式下的子商户号,普通模式请不要配置,最好是请在配置文件中将对应项删除 - */ - private String subMchId; - /** * apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定 */ diff --git a/Cpop-System/src/main/java/com/cpop/system/business/bo/BrandBo.java b/Cpop-System/src/main/java/com/cpop/system/business/bo/BrandBo.java index 926a05f..8b2d3af 100644 --- a/Cpop-System/src/main/java/com/cpop/system/business/bo/BrandBo.java +++ b/Cpop-System/src/main/java/com/cpop/system/business/bo/BrandBo.java @@ -32,6 +32,12 @@ public class BrandBo { @ApiModelProperty("微信商户号") private String wxMchId; + /** + * 微信Appid + */ + @ApiModelProperty("微信Appid") + private String wxAppId; + /** * 微信支付密钥 */ diff --git a/Cpop-System/src/main/java/com/cpop/system/business/entity/Brand.java b/Cpop-System/src/main/java/com/cpop/system/business/entity/Brand.java index 7957dbd..4070e00 100644 --- a/Cpop-System/src/main/java/com/cpop/system/business/entity/Brand.java +++ b/Cpop-System/src/main/java/com/cpop/system/business/entity/Brand.java @@ -40,6 +40,11 @@ public class Brand extends BaseEntity implements Serializable { */ private String brandName; + /** + * 微信appid + */ + private String wxAppId; + /** * 微信商户号 */ diff --git a/Cpop-System/src/main/java/com/cpop/system/business/service/impl/BrandServiceImpl.java b/Cpop-System/src/main/java/com/cpop/system/business/service/impl/BrandServiceImpl.java index 27d322b..9a2cec1 100644 --- a/Cpop-System/src/main/java/com/cpop/system/business/service/impl/BrandServiceImpl.java +++ b/Cpop-System/src/main/java/com/cpop/system/business/service/impl/BrandServiceImpl.java @@ -76,6 +76,7 @@ public class BrandServiceImpl extends ServiceImpl implements } Brand sysBrand = new Brand(); sysBrand.setBrandName(brand.getString("name")) + .setWxAppId(brand.getString("appid")) .setWxMchId(brand.getString("wxMchId")) .setWxMchKey(brand.getString("wxMchKey")) .setWxKeyPath(brand.getString("wxKeyPath"))