diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 000000000..639e529ea --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,53 @@ +version: '3.8' + +services: + # ==================== RabbitMQ ==================== + rabbitmq: + image: rabbitmq:3.13-management + container_name: rabbitmq + restart: unless-stopped + ports: + - "5671:5671" # AMQP over TLS/SSL + - "5672:5672" # AMQP 协议端口(应用连接用) + - "4369:4369" # Erlang 端口映射守护进程(epmd) + - "15671:15671" # Management UI over TLS/SSL + - "15672:15672" # Management UI 端口(浏览器访问) + - "25672:25672" # Erlang 集群通信端口 + environment: + - RABBITMQ_DEFAULT_USER=admin + - RABBITMQ_DEFAULT_PASS=admin + volumes: + - /home/docker/rabbitmq/data:/var/lib/rabbitmq + - /home/docker/rabbitmq/logs:/var/log/rabbitmq + user: "1000:1000" # RabbitMQ 容器默认使用 uid 1000 + + # ==================== Nacos 2.0.3 ==================== + nacos: + image: nacos/nacos-server:2.0.3 + container_name: nacos + restart: always + privileged: true + ports: + - "8848:8848" # Nacos 主端口(HTTP API) + - "9848:9848" # Nacos 客户端 gRPC 端口 + - "9849:9849" # Nacos 客户端 gRPC 端口(用于服务发现) + environment: + - JVM_XMS=256m # JVM 初始堆内存 + - JVM_XMX=256m # JVM 最大堆内存 + - MODE=standalone # 单机模式 + - PREFER_HOST_MODE=hostname # 主机名模式 + - NACOS_AUTH_ENABLE=true # 开启认证 + - NACOS_AUTH_TOKEN=ZTQzMzgwNDk4YTkyNDAxOTkzOWZmODYwNzQ5ODFjNDA= + - NACOS_AUTH_IDENTITY_KEY=OTU0ZWQ2Y2MxYjB1NDF1YWII0WQ4NWAkNZI2N2Q0Yzk= + - NACOS_AUTH_IDENTITY_VALUE=MGFjNmU3ZjgwZmM2NDAkMzg3MTNmMDQ4ODE5ZDAwOTQ= + volumes: + - /home/docker/nacos/data:/home/nacos/data + - /home/docker/nacos/logs:/home/nacos/logs + +volumes: + rabbitmq_data: + driver: local + nacos_data: + driver: local + nacos_logs: + driver: local \ No newline at end of file diff --git a/jsowell-admin/src/main/java/com/jsowell/api/uniapp/customer/TempController.java b/jsowell-admin/src/main/java/com/jsowell/api/uniapp/customer/TempController.java index 2d8f1d8eb..d2eb68aca 100644 --- a/jsowell-admin/src/main/java/com/jsowell/api/uniapp/customer/TempController.java +++ b/jsowell-admin/src/main/java/com/jsowell/api/uniapp/customer/TempController.java @@ -41,11 +41,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.math.BigDecimal; -import java.text.ParseException; import java.time.LocalDateTime; -import java.time.LocalTime; import java.time.format.DateTimeFormatter; -import java.util.Date; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -1104,6 +1101,7 @@ public class TempController extends BaseController { @PostMapping("/batchUpdateOrderReviewByDatePoor") public RestApiResponse batchUpdateOrderReviewByDatePoor(@RequestBody UpdateOrderReviewDTO dto) { + logger.info("批量更新订单评价, param:{}", JSON.toJSONString(dto)); RestApiResponse response = null; try { // 根据传来的开始日期、结束日期按天划分为批次,对每个批次进行批量更新 @@ -1114,7 +1112,8 @@ public class TempController extends BaseController { // 将startTime、endTime转换成localDateTime LocalDateTime localStartTime = LocalDateTime.parse(date + "T00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"));; LocalDateTime localEndTime = LocalDateTime.parse(date + "T23:59:59", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"));; - int i = orderBasicInfoService.updateOrderReviewFlagTemp(localStartTime, localEndTime, null); + int i = orderBasicInfoService.updateOrderReviewFlagTemp(localStartTime, localEndTime, dto.getStationId(), dto.getRatio()); + logger.info("批量更新订单评价, 批次:{}, 影响行数:{}", date, i); } response = new RestApiResponse<>(); } catch (Exception e) { diff --git a/jsowell-admin/src/main/resources/application-dev.yml b/jsowell-admin/src/main/resources/application-dev.yml index 5de23e895..6db512605 100644 --- a/jsowell-admin/src/main/resources/application-dev.yml +++ b/jsowell-admin/src/main/resources/application-dev.yml @@ -9,7 +9,7 @@ spring: # redis 配置 redis: # 地址 - host: 106.14.94.149 + host: 192.168.0.8 # 端口,默认为6379 port: 6379 # 数据库索引 @@ -38,9 +38,9 @@ spring: master: # url: jdbc:mysql://106.14.94.149:3306/jsowell_pre?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 # username: jsowell_pre - url: jdbc:mysql://192.168.0.32:3306/jsowell_dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 - username: jsowell_dev - password: 123456 + url: jdbc:mysql://192.168.0.8:3306/jsowell_prd?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + username: jsowell_prd + password: dev@js160829 # 从库数据源 slave: # 从数据源开关/默认关闭 @@ -273,9 +273,9 @@ dubbo: registry: address: nacos://106.14.94.149:8848 parameters: - namespace: 200784c9-7e8f-4b2b-a44f-1eb52e675491 + namespace: e328faaf-8516-42d0-817a-7406232b3581 username: nacos - password: 3rtJPEb0KaUs5NAm + password: 79HMu!6nlOiLm^Q[ protocol: name: dubbo port: -1 diff --git a/jsowell-admin/src/main/resources/application-sit.yml b/jsowell-admin/src/main/resources/application-sit.yml index d1889bc1a..05046b21d 100644 --- a/jsowell-admin/src/main/resources/application-sit.yml +++ b/jsowell-admin/src/main/resources/application-sit.yml @@ -48,7 +48,7 @@ spring: # 数据库索引 database: 0 # 密码 - password: 123456 + password: js160829 # 连接超时时间 timeout: 10s lettuce: diff --git a/jsowell-admin/src/test/java/PaymentTestController.java b/jsowell-admin/src/test/java/PaymentTestController.java index 1ab1b3fa1..45eb56748 100644 --- a/jsowell-admin/src/test/java/PaymentTestController.java +++ b/jsowell-admin/src/test/java/PaymentTestController.java @@ -8,12 +8,18 @@ import com.huifu.adapay.core.exception.BaseAdaPayException; import com.huifu.adapay.model.Payment; import com.huifu.adapay.model.PaymentReverse; import com.huifu.adapay.model.Refund; +import com.jsowell.adapay.common.AdaPayment; import com.jsowell.JsowellApplication; import com.jsowell.adapay.common.DivMember; import com.jsowell.adapay.common.PaymentConfirmInfo; +import com.jsowell.adapay.common.RefundInfo; +import com.jsowell.adapay.config.AbstractAdapayConfig; import com.jsowell.adapay.dto.PaymentConfirmParam; +import com.jsowell.adapay.dto.QueryConfirmReverseDTO; import com.jsowell.adapay.dto.QueryPaymentConfirmDTO; +import com.jsowell.adapay.factory.AdapayConfigFactory; import com.jsowell.adapay.operation.PaymentReverseOperation; +import com.jsowell.adapay.response.ConfirmReverseResponse; import com.jsowell.adapay.response.PaymentConfirmResponse; import com.jsowell.adapay.response.PaymentReverseResponse; import com.jsowell.adapay.response.QueryPaymentConfirmDetailResponse; @@ -24,10 +30,12 @@ import com.jsowell.api.uniapp.customer.TempController; import com.jsowell.common.constant.CacheConstants; import com.jsowell.common.constant.Constants; import com.jsowell.common.core.redis.RedisCache; +import com.jsowell.common.enums.adapay.AdapayStatusEnum; import com.jsowell.common.enums.ykc.ScenarioEnum; import com.jsowell.common.util.AdapayUtil; import com.jsowell.common.util.DateUtils; import com.jsowell.common.util.PageUtils; +import com.jsowell.common.util.StringUtils; import com.jsowell.pile.domain.AdapayUnsplitRecord; import com.jsowell.pile.domain.OrderBasicInfo; import com.jsowell.pile.domain.OrderDetail; @@ -60,7 +68,7 @@ import java.util.concurrent.TimeUnit; /** * 专用处理汇付支付相关 */ -@ActiveProfiles("dev") +@ActiveProfiles("sit") @SpringBootTest(classes = JsowellApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @RunWith(SpringRunner.class) public class PaymentTestController { @@ -940,4 +948,197 @@ public class PaymentTestController { logger.info("{}", JSON.toJSONString(paymentConfirmInfo)); } + + @Test + public void queryPaymentAllInfoTest() throws BaseAdaPayException { + String paymentId = System.getProperty("paymentId"); + if (StringUtils.isBlank(paymentId)) { + throw new IllegalArgumentException("请通过 -DpaymentId=支付ID 传入 paymentId"); + } + JSONObject result = queryPaymentAllInfo(paymentId); + logger.info("paymentId:{}, result:{}", paymentId, JSON.toJSONString(result)); + } + + public JSONObject queryPaymentAllInfo(String paymentId) throws BaseAdaPayException { + if (StringUtils.isBlank(paymentId)) { + throw new IllegalArgumentException("paymentId不能为空"); + } + + PaymentQueryContext context = queryPaymentContext(paymentId); + if (context == null) { + throw new IllegalArgumentException("未匹配到支付单,paymentId:" + paymentId); + } + + QueryPaymentConfirmDTO queryPaymentConfirmDTO = new QueryPaymentConfirmDTO(); + queryPaymentConfirmDTO.setWechatAppId(context.getWechatAppId()); + queryPaymentConfirmDTO.setPaymentId(paymentId); + QueryPaymentConfirmDetailResponse confirmResponse = adapayService.queryPaymentConfirmList(queryPaymentConfirmDTO); + List paymentConfirms = confirmResponse == null || CollectionUtils.isEmpty(confirmResponse.getPaymentConfirms()) + ? Lists.newArrayList() + : paymentResponseToList(confirmResponse.getPaymentConfirms()); + + List paymentReverses = adapayService.queryPaymentReverse(paymentId, context.getWechatAppId()); + if (paymentReverses == null) { + paymentReverses = Lists.newArrayList(); + } + + List refunds = adapayService.queryPaymentRefund(paymentId, context.getWechatAppId()); + if (refunds == null) { + refunds = Lists.newArrayList(); + } + + AdaPayment payment = context.getPayment(); + BigDecimal payAmount = safeAmount(payment.getPay_amt()); + BigDecimal apiConfirmedAmount = safeAmount(payment.getConfirmed_amt()); + BigDecimal apiRefundedAmount = safeAmount(payment.getRefunded_amt()); + BigDecimal apiReservedAmount = safeAmount(payment.getReserved_amt()); + + BigDecimal successConfirmedAmount = sumConfirmedAmount(paymentConfirms, context.getWechatAppId()); + BigDecimal successRefundAmount = sumRefundAmount(refunds); + BigDecimal successReverseAmount = sumReverseAmount(paymentReverses); + + BigDecimal alreadySplitAmount = apiConfirmedAmount.compareTo(BigDecimal.ZERO) > 0 + ? apiConfirmedAmount + : successConfirmedAmount; + BigDecimal alreadyRefundAmount; + if (StringUtils.equals("delay", payment.getPay_mode())) { + alreadyRefundAmount = successReverseAmount.compareTo(BigDecimal.ZERO) > 0 + ? successReverseAmount + : apiReservedAmount; + } else { + alreadyRefundAmount = successRefundAmount.compareTo(BigDecimal.ZERO) > 0 + ? successRefundAmount + : apiRefundedAmount; + } + BigDecimal unsplitAmount = payAmount.subtract(alreadySplitAmount).subtract(alreadyRefundAmount); + if (unsplitAmount.compareTo(BigDecimal.ZERO) < 0) { + unsplitAmount = BigDecimal.ZERO; + } + + JSONObject summary = new JSONObject(); + summary.put("payMode", payment.getPay_mode()); + summary.put("payAmount", AdapayUtil.formatAmount(payAmount)); + summary.put("apiConfirmedAmount", AdapayUtil.formatAmount(apiConfirmedAmount)); + summary.put("apiRefundedAmount", AdapayUtil.formatAmount(apiRefundedAmount)); + summary.put("apiReservedAmount", AdapayUtil.formatAmount(apiReservedAmount)); + summary.put("successConfirmedAmount", AdapayUtil.formatAmount(successConfirmedAmount)); + summary.put("successRefundAmount", AdapayUtil.formatAmount(successRefundAmount)); + summary.put("successReverseAmount", AdapayUtil.formatAmount(successReverseAmount)); + summary.put("alreadySplitAmount", AdapayUtil.formatAmount(alreadySplitAmount)); + summary.put("alreadyRefundAmount", AdapayUtil.formatAmount(alreadyRefundAmount)); + summary.put("unsplitAmount", AdapayUtil.formatAmount(unsplitAmount)); + + JSONObject result = new JSONObject(); + result.put("paymentId", paymentId); + result.put("wechatAppId", context.getWechatAppId()); + result.put("adapayAppId", context.getAdapayAppId()); + result.put("payment", payment); + result.put("paymentRaw", JSON.parseObject(JSON.toJSONString(payment))); + result.put("paymentConfirms", paymentConfirms); + result.put("paymentReverses", paymentReverses); + result.put("refunds", refunds); + result.put("summary", summary); + return result; + } + + private PaymentQueryContext queryPaymentContext(String paymentId) throws BaseAdaPayException { + List configList = AdapayConfigFactory.getAllConfig(); + if (CollectionUtils.isEmpty(configList)) { + throw new IllegalStateException("未加载到汇付商户配置"); + } + + for (AbstractAdapayConfig config : configList) { + AdaPayment payment = adapayService.queryPaymentDetailWithFallback(paymentId, config.getWechatAppId()); + if (payment != null) { + return new PaymentQueryContext(config.getWechatAppId(), config.getAdapayAppId(), payment); + } + } + return null; + } + + private BigDecimal sumConfirmedAmount(List paymentConfirms, String wechatAppId) throws BaseAdaPayException { + BigDecimal totalAmount = BigDecimal.ZERO; + if (CollectionUtils.isEmpty(paymentConfirms)) { + return totalAmount; + } + for (PaymentConfirmInfo paymentConfirm : paymentConfirms) { + if (isConfirmReversed(paymentConfirm, wechatAppId)) { + continue; + } + totalAmount = totalAmount.add(safeAmount(paymentConfirm.getConfirmedAmt())); + } + return totalAmount; + } + + private boolean isConfirmReversed(PaymentConfirmInfo paymentConfirm, String wechatAppId) throws BaseAdaPayException { + QueryConfirmReverseDTO queryConfirmReverseDTO = QueryConfirmReverseDTO.builder() + .wechatAppId(wechatAppId) + .paymentConfirmId(paymentConfirm.getId()) + .build(); + ConfirmReverseResponse confirmReverseResponse = adapayService.queryConfirmReverse(queryConfirmReverseDTO); + return confirmReverseResponse != null && confirmReverseResponse.isSuccess(); + } + + private BigDecimal sumRefundAmount(List refunds) { + BigDecimal totalAmount = BigDecimal.ZERO; + if (CollectionUtils.isEmpty(refunds)) { + return totalAmount; + } + for (RefundInfo refund : refunds) { + if (!StringUtils.equals("S", refund.getTrans_status())) { + continue; + } + totalAmount = totalAmount.add(safeAmount(refund.getRefund_amt())); + } + return totalAmount; + } + + private BigDecimal sumReverseAmount(List paymentReverses) { + BigDecimal totalAmount = BigDecimal.ZERO; + if (CollectionUtils.isEmpty(paymentReverses)) { + return totalAmount; + } + for (PaymentReverseResponse paymentReverseResponse : paymentReverses) { + if (!StringUtils.equals(AdapayStatusEnum.SUCCEEDED.getValue(), paymentReverseResponse.getStatus())) { + continue; + } + totalAmount = totalAmount.add(safeAmount(paymentReverseResponse.getReverse_amt())); + } + return totalAmount; + } + + private BigDecimal safeAmount(String amount) { + if (StringUtils.isBlank(amount)) { + return BigDecimal.ZERO; + } + return new BigDecimal(amount); + } + + private List paymentResponseToList(List paymentConfirms) { + return Lists.newArrayList(paymentConfirms); + } + + private static class PaymentQueryContext { + private final String wechatAppId; + private final String adapayAppId; + private final AdaPayment payment; + + private PaymentQueryContext(String wechatAppId, String adapayAppId, AdaPayment payment) { + this.wechatAppId = wechatAppId; + this.adapayAppId = adapayAppId; + this.payment = payment; + } + + private String getWechatAppId() { + return wechatAppId; + } + + private String getAdapayAppId() { + return adapayAppId; + } + + private AdaPayment getPayment() { + return payment; + } + } } diff --git a/jsowell-pile/src/main/java/com/jsowell/adapay/service/AdapayService.java b/jsowell-pile/src/main/java/com/jsowell/adapay/service/AdapayService.java index 295b56d1c..5ff62e405 100644 --- a/jsowell-pile/src/main/java/com/jsowell/adapay/service/AdapayService.java +++ b/jsowell-pile/src/main/java/com/jsowell/adapay/service/AdapayService.java @@ -1345,7 +1345,74 @@ public class AdapayService { } /** - * 查询支付退款对象 + * 按汇付文档查询支付对象详情 + * Payment.query(paymentId, merchantKey) + */ + public AdaPayment queryPaymentDetail(String paymentId, String wechatAppId) throws BaseAdaPayException { + AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); + if (config == null) { + throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); + } + Map response = Payment.query(paymentId, config.getWechatAppId()); + if (response == null || response.isEmpty()) { + return null; + } + String resultPaymentId = (String) response.get("id"); + String errorCode = (String) response.get("error_code"); + if (!StringUtils.equals(paymentId, resultPaymentId) || StringUtils.isNotBlank(errorCode)) { + return null; + } + return JSON.parseObject(JSON.toJSONString(response), AdaPayment.class); + } + + /** + * 按汇付文档通过 payment_id 查询支付对象列表 + * 作为 Payment.query 的补充,用于查询 3 天前的交易 + */ + public List queryPaymentListByPaymentId(String paymentId, String wechatAppId) throws BaseAdaPayException { + List resultList = Lists.newArrayList(); + AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); + if (config == null) { + throw new BusinessException(ReturnCodeEnum.CODE_ADAPAY_CONFIG_IS_NULL_ERROR); + } + Map queryListParam = Maps.newHashMap(); + queryListParam.put("app_id", config.getAdapayAppId()); + queryListParam.put("payment_id", paymentId); + queryListParam.put("page_index", 1); + queryListParam.put("page_size", 1); + Map paymentListResult = Payment.queryList(queryListParam, config.getWechatAppId()); + if (paymentListResult == null || paymentListResult.isEmpty()) { + return resultList; + } + + JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(paymentListResult)); + List payments = jsonObject.getList("payments", AdaPayment.class, JSONReader.Feature.FieldBased); + if (CollectionUtils.isNotEmpty(payments)) { + resultList.addAll(payments); + } + return resultList; + } + + /** + * 查询支付对象详情 + * 先查 Payment.query,未命中时再按 payment_id 查询列表 + */ + public AdaPayment queryPaymentDetailWithFallback(String paymentId, String wechatAppId) throws BaseAdaPayException { + AdaPayment payment = queryPaymentDetail(paymentId, wechatAppId); + if (payment != null) { + return payment; + } + + List payments = queryPaymentListByPaymentId(paymentId, wechatAppId); + if (CollectionUtils.isEmpty(payments)) { + return null; + } + return payments.get(0); + } + + /** + * 按汇付文档通过 payment_id 查询退款对象 + * Refund.query({payment_id}, merchantKey) */ public List queryPaymentRefund(String paymentId, String wechatAppId) throws BaseAdaPayException { AbstractAdapayConfig config = AdapayConfigFactory.getConfig(wechatAppId); @@ -1354,7 +1421,6 @@ public class AdapayService { } Map refundParams = Maps.newHashMap(); refundParams.put("payment_id", paymentId); - refundParams.put("app_id", config.getAdapayAppId()); Map response = Refund.query(refundParams, config.getWechatAppId()); PaymentRefundResponse paymentRefundResponse = JSON.parseObject(JSON.toJSONString(response), PaymentRefundResponse.class); List refunds = paymentRefundResponse.getRefunds(); diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/dto/QueryOrderDTO.java b/jsowell-pile/src/main/java/com/jsowell/pile/dto/QueryOrderDTO.java index b7be18277..3440f025d 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/dto/QueryOrderDTO.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/dto/QueryOrderDTO.java @@ -83,6 +83,8 @@ public class QueryOrderDTO extends BaseEntity { */ private String payMode; + private List payModeList; + /** * 订单编号列表 */ @@ -98,6 +100,11 @@ public class QueryOrderDTO extends BaseEntity { */ private String endSettleTime; + /** + * 审核标志 + */ + private String reviewFlag; + /** * 会员组编号 */ diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/dto/UpdateOrderReviewDTO.java b/jsowell-pile/src/main/java/com/jsowell/pile/dto/UpdateOrderReviewDTO.java index 66042540f..588ed389c 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/dto/UpdateOrderReviewDTO.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/dto/UpdateOrderReviewDTO.java @@ -30,4 +30,9 @@ public class UpdateOrderReviewDTO { * 结束日期 */ private String endTime; + + /** + * 比率 + */ + private Double ratio; } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/mapper/MemberWalletInfoMapper.java b/jsowell-pile/src/main/java/com/jsowell/pile/mapper/MemberWalletInfoMapper.java index 34faa8443..386913244 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/mapper/MemberWalletInfoMapper.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/mapper/MemberWalletInfoMapper.java @@ -38,6 +38,8 @@ public interface MemberWalletInfoMapper { */ MemberWalletInfo selectByMemberId(@Param("memberId") String memberId, @Param("merchantId") String merchantId); + List selectByMemberIdList(@Param("memberId") String memberId, @Param("merchantId") String merchantId); + List selectByMemberWalletList(@Param("memberId") String memberId); MemberWalletInfo selectByWalletCode(@Param("walletCode") String walletCode); diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/OrderBasicInfoService.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/OrderBasicInfoService.java index 496903511..bbf855cbe 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/OrderBasicInfoService.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/OrderBasicInfoService.java @@ -636,7 +636,7 @@ public interface OrderBasicInfoService{ void checkOrUpdateOrderSplitRecord(AfterSettleOrderDTO afterSettleOrderDTO); - int updateOrderReviewFlagTemp(LocalDateTime start, LocalDateTime end, String stationId); + int updateOrderReviewFlagTemp(LocalDateTime start, LocalDateTime end, String stationId, Double ratio); List queryOrderSplitConfigList(String orderCode); diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/MemberWalletInfoServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/MemberWalletInfoServiceImpl.java index 37201480f..4be888a50 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/MemberWalletInfoServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/MemberWalletInfoServiceImpl.java @@ -46,7 +46,15 @@ public class MemberWalletInfoServiceImpl implements MemberWalletInfoService { @Override public MemberWalletInfo selectByMemberId(String memberId, String merchantId) { - return memberWalletInfoMapper.selectByMemberId(memberId, merchantId); + List list = memberWalletInfoMapper.selectByMemberIdList(memberId, merchantId); + if (CollectionUtils.isEmpty(list)) { + return null; + } + // 优先返回 merchantId 不为空的记录,避免脏数据干扰 + return list.stream() + .filter(w -> w.getMerchantId() != null) + .findFirst() + .orElse(list.get(0)); } @Override diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java index b0f5a2da6..d7e96c06c 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java @@ -1066,7 +1066,8 @@ public class OrderBasicInfoServiceImpl implements OrderBasicInfoService { QueryOrderDTO dto = QueryOrderDTO.builder() .startTime(DateUtils.formatDateTime(start)) .endTime(DateUtils.formatDateTime(end)) - .payMode(OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue()) + // .payMode(OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue()) + .payModeList(Lists.newArrayList(OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue(), OrderPayModeEnum.PAYMENT_OF_ALIPAY.getValue())) .stationId(stationId) .orderStatus(OrderStatusEnum.ORDER_COMPLETE.getValue()) .build(); @@ -6327,17 +6328,21 @@ public class OrderBasicInfoServiceImpl implements OrderBasicInfoService { } @Override - public int updateOrderReviewFlagTemp(LocalDateTime start, LocalDateTime end, String stationId) { + public int updateOrderReviewFlagTemp(LocalDateTime start, LocalDateTime end, String stationId, Double ratio) { + if (ratio == null) { + ratio = 0.1; + logger.info("校验或更新订单分账信息-使用默认比例:{}", ratio); + } if (StringUtils.isBlank(stationId)) { stationId = "1003"; // 目前只有 大坡中学举视超充站 这一个站点使用 + logger.info("校验或更新订单分账信息-使用默认站点id:{}", stationId); } List orderList = this.selectOrderListByDateTime(start, end, stationId); if (CollectionUtils.isEmpty(orderList)) { return 0; } - List orderCodeList = orderList.stream().map(OrderListVO::getOrderCode).collect(Collectors.toList()); UpdateOrderReviewDTO dto = new UpdateOrderReviewDTO(); - dto.setOrderCodeList(MerchantUtils.getRandomNinetyPercent(orderCodeList)); + dto.setOrderCodeList(MerchantUtils.getRandomOrderCodes(orderList, ratio)); dto.setStationId(stationId); return batchUpdateOrderReview(dto); } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/SettleOrderReportServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/SettleOrderReportServiceImpl.java index 0e485d80a..e9f9039fc 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/SettleOrderReportServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/SettleOrderReportServiceImpl.java @@ -676,6 +676,7 @@ public class SettleOrderReportServiceImpl implements SettleOrderReportService { dto.setEndSettleTime(endTime); // 2024年1月30日13点49分 查询订单列表只查对应当前运营商的 dto.setMerchantId(stationInfo.getMerchantId()); + dto.setReviewFlag(Constants.ONE); // 查询结算完成的订单 List orderListVOS = orderBasicInfoMapper.selectOrderBasicInfoList(dto); // 收集订单编号 diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/programlogic/DelayMerchantProgramLogic.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/programlogic/DelayMerchantProgramLogic.java index 2abdd860e..e835a7243 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/programlogic/DelayMerchantProgramLogic.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/programlogic/DelayMerchantProgramLogic.java @@ -1084,9 +1084,11 @@ public class DelayMerchantProgramLogic extends AbstractProgramLogic { // 需要退回本金的金额 BigDecimal returnPrincipal = returnAmountMap.get("returnPrincipal"); + returnPrincipal = returnPrincipal == null ? BigDecimal.ZERO : returnPrincipal; // 需要退回赠送金的金额 BigDecimal returnGift = returnAmountMap.get("returnGift"); + returnGift = returnGift == null ? BigDecimal.ZERO : returnGift; // 更新会员钱包/余额退回到钱包 UpdateMemberBalanceDTO updateMemberBalanceDTO = UpdateMemberBalanceDTO.builder() @@ -1101,17 +1103,22 @@ public class DelayMerchantProgramLogic extends AbstractProgramLogic { // 判断消费金额,如果消费金额 - 折扣金额小于 1 元,则将保险费也进行退回 if (orderBasicInfo.getOrderAmount().subtract(orderBasicInfo.getDiscountAmount()).compareTo(BigDecimal.ONE) < 0) { - // orderBasicInfoService.refundInsurance(orderBasicInfo); // 判断是否需要退保险费用 boolean checkResult = orderBasicInfoService.checkRefundInsuranceAmount(orderBasicInfo); if (checkResult) { - // 退保险, 计算退保金额 + // 退保险, 使用 calculateBalanceRefund 重新计算完整的退款金额(电费退款+保险费退款) + // 注意:不能在 calculateReturnAmount 的基础上叠加保险费,因为 calculateReturnAmount 不感知保险费, + // 算出的退款金额中已包含保险费部分,叠加会导致保险费被重复退还 Map refundMap = calculateBalanceRefund(principalPay, giftPay, orderBasicInfo.getOrderAmount(), orderBasicInfo.getDiscountAmount(), orderBasicInfo.getInsuranceAmount()); + BigDecimal refundPrincipal = refundMap.get("returnPrincipal"); + BigDecimal refundGift = refundMap.get("returnGift"); BigDecimal returnPrincipalForInsurance = refundMap.get("returnPrincipalForInsurance"); BigDecimal returnGiftForInsurance = refundMap.get("returnGiftForInsurance"); + refundPrincipal = refundPrincipal == null ? BigDecimal.ZERO : refundPrincipal; + refundGift = refundGift == null ? BigDecimal.ZERO : refundGift; - updateMemberBalanceDTO.setUpdatePrincipalBalance(returnPrincipal.add(returnPrincipalForInsurance)); - updateMemberBalanceDTO.setUpdateGiftBalance(returnGift.add(returnGiftForInsurance)); + updateMemberBalanceDTO.setUpdatePrincipalBalance(refundPrincipal.add(returnPrincipalForInsurance)); + updateMemberBalanceDTO.setUpdateGiftBalance(refundGift.add(returnGiftForInsurance)); } } // 统一退款 diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/util/MerchantUtils.java b/jsowell-pile/src/main/java/com/jsowell/pile/util/MerchantUtils.java index 505a8a7ab..c86fc8636 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/util/MerchantUtils.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/util/MerchantUtils.java @@ -1,10 +1,12 @@ package com.jsowell.pile.util; import com.jsowell.common.util.StringUtils; +import com.jsowell.pile.vo.web.OrderListVO; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; /** * 运营商工具类 @@ -73,4 +75,18 @@ public class MerchantUtils { return new ArrayList<>(shuffled.subList(0, keepCount)); } + public static List getRandomOrderCodes(List list, double ratio) { + if (list == null || list.isEmpty()) { + return new ArrayList<>(); + } + int total = list.size(); + int removeCount = (int) Math.ceil(total * ratio); + int keepCount = Math.max(1, total - removeCount); + List shuffled = new ArrayList<>(list); + Collections.shuffle(shuffled); + return shuffled.subList(0, keepCount).stream() + .map(OrderListVO::getOrderCode) + .collect(Collectors.toList()); + } + } diff --git a/jsowell-pile/src/main/resources/mapper/pile/MemberWalletInfoMapper.xml b/jsowell-pile/src/main/resources/mapper/pile/MemberWalletInfoMapper.xml index 352b6a218..8f5cc314b 100644 --- a/jsowell-pile/src/main/resources/mapper/pile/MemberWalletInfoMapper.xml +++ b/jsowell-pile/src/main/resources/mapper/pile/MemberWalletInfoMapper.xml @@ -528,6 +528,17 @@ + + diff --git a/jsowell-quartz/src/main/java/com/jsowell/quartz/task/JsowellTask.java b/jsowell-quartz/src/main/java/com/jsowell/quartz/task/JsowellTask.java index e6a0798b5..2bc13e1ee 100644 --- a/jsowell-quartz/src/main/java/com/jsowell/quartz/task/JsowellTask.java +++ b/jsowell-quartz/src/main/java/com/jsowell/quartz/task/JsowellTask.java @@ -1152,7 +1152,7 @@ public class JsowellTask { LocalDateTime start = yesterday.atStartOfDay(); LocalDateTime end = yesterday.atTime(23, 59, 59); - orderBasicInfoService.updateOrderReviewFlagTemp(start, end, null); + orderBasicInfoService.updateOrderReviewFlagTemp(start, end, null, null); }