zhaoyun 1 month ago
parent
commit
0483231c97
29 changed files with 1410 additions and 184 deletions
  1. 8 0
      ydd_mer_java/crmeb-admin/src/main/java/com/zbkj/admin/controller/publicly/PayCallbackController.java
  2. 3 0
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/constants/PayConstants.java
  3. 4 4
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/model/express/ExpressOrder.java
  4. 15 8
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/model/express/ExpressOrderDetail.java
  5. 1 2
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/request/UserExpressAddressRequest.java
  6. 3 0
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/request/express/CreateExpressOrderRequest.java
  7. 1 3
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/request/express/ExpressOrderFrontListRequest.java
  8. 20 8
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/request/express/PreExpressOrderDetailRequest.java
  9. 2 5
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/request/express/PreExpressOrderRequest.java
  10. 6 11
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/response/express/ExpressOrderFrontDataResponse.java
  11. 86 0
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/response/express/ExpressOrderFrontDetailResponse.java
  12. 14 5
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/response/express/ExpressOrderInfoFrontDataResponse.java
  13. 68 0
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/response/express/PostOrderFrontDetailResponse.java
  14. 3 6
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/response/express/PreExpressOrderResponse.java
  15. 33 0
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/response/express/PrePostOrderInfoResponse.java
  16. 25 20
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/vo/PreExpressOrderInfoDetailVo.java
  17. 5 6
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/vo/PreExpressOrderInfoVo.java
  18. 34 0
      ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/vo/PrePostOrderInfoVo.java
  19. 12 6
      ydd_mer_java/crmeb-front/src/main/java/com/zbkj/front/controller/ExpressOrderController.java
  20. 58 0
      ydd_mer_java/crmeb-front/src/main/java/com/zbkj/front/controller/ExpressPayController.java
  21. 18 4
      ydd_mer_java/crmeb-front/src/main/java/com/zbkj/front/service/FrontExpressOrderService.java
  22. 218 92
      ydd_mer_java/crmeb-front/src/main/java/com/zbkj/front/service/impl/FrontExpressOrderServiceImpl.java
  23. 26 0
      ydd_mer_java/crmeb-service/src/main/java/com/zbkj/service/ExpressOrderService.java
  24. 32 0
      ydd_mer_java/crmeb-service/src/main/java/com/zbkj/service/service/ExpressPayService.java
  25. 7 0
      ydd_mer_java/crmeb-service/src/main/java/com/zbkj/service/service/PayCallbackService.java
  26. 55 3
      ydd_mer_java/crmeb-service/src/main/java/com/zbkj/service/service/impl/ExpressOrderServiceImpl.java
  27. 510 0
      ydd_mer_java/crmeb-service/src/main/java/com/zbkj/service/service/impl/ExpressPayServiceImpl.java
  28. 138 0
      ydd_mer_java/crmeb-service/src/main/java/com/zbkj/service/service/impl/PayCallbackServiceImpl.java
  29. 5 1
      ydd_mer_java/crmeb-service/src/main/resources/mapper/express/ExpressOrderMapper.xml

+ 8 - 0
ydd_mer_java/crmeb-admin/src/main/java/com/zbkj/admin/controller/publicly/PayCallbackController.java

@@ -46,6 +46,14 @@ public class PayCallbackController {
         System.out.println("微信支付回调 response ===> " + response);
         return response;
     }
+    @ApiOperation(value = "快递微信支付回调")
+    @RequestMapping(value = "/exp/wechat", method = RequestMethod.POST)
+    public String expWeChat(@RequestBody String  request) {
+        System.out.println("微信快递支付回调 request ===> " + request);
+        String response = callbackService.wechatExpPayCallback(request);
+        System.out.println("微信快递支付回调 response ===> " + response);
+        return response;
+    }
 
     @ApiOperation(value = "支付宝支付回调 ")
     @RequestMapping(value = "/alipay", method = RequestMethod.POST)

+ 3 - 0
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/constants/PayConstants.java

@@ -68,6 +68,9 @@ public class PayConstants {
     public static final String WX_PAY_ORDER_QUERY_API_URI = "pay/orderquery";
     // 微信支付回调地址
     public static final String WX_PAY_NOTIFY_API_URI = "/api/publicly/payment/callback/wechat";
+
+    // 微信支付回调地址
+    public static final String WX_EXP_PAY_NOTIFY_API_URI = "/api/publicly/payment/callback/exp/wechat";
     // 微信退款回调地址
     public static final String WX_PAY_REFUND_NOTIFY_API_URI = "/api/publicly/payment/callback/wechat/refund";
 

+ 4 - 4
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/model/express/ExpressOrder.java

@@ -36,8 +36,10 @@ public class ExpressOrder implements Serializable {
 
     @ApiModelProperty(value = "订单号")
     private String orderNo;
+    @ApiModelProperty(value = "系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号")
+    private String outTradeNo;
 
-
+    private  String platOrderNo;
     @ApiModelProperty(value = "用户id")
     private Integer uid;
 
@@ -93,9 +95,7 @@ public class ExpressOrder implements Serializable {
     private String userPhone;
 
     @ApiModelProperty(value = "用户地址id")
-    private Integer userAddressId;
-    @ApiModelProperty(value = "驿站地址id")
-    private Integer postAddressId;
+    private String userAddress;
 
     @ApiModelProperty(value = "创建时间")
     private Date createTime;

+ 15 - 8
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/model/express/ExpressOrderDetail.java

@@ -10,6 +10,7 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 
+import javax.validation.constraints.NotEmpty;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.util.Date;
@@ -37,21 +38,27 @@ public class ExpressOrderDetail implements Serializable {
 
     @ApiModelProperty(value = "订单号")
     private String orderNo;
-
     @ApiModelProperty(value = "用户id")
     private Integer uid;
-
-    @ApiModelProperty(value = "快件")
-    private String expressInfo;
-
+    @ApiModelProperty(value = "驿站电话")
+    private String postPhone;
+    @ApiModelProperty(value = "取件码)")
+    private String pickUpCode;
+    @ApiModelProperty(value = "快递公司)")
+    private String expressCompany;
+    @ApiModelProperty(value = "快递单号)")
+    private String expressNo;
     @ApiModelProperty(value = "订单类型")
-    private Integer expressType;
-
+    private Integer type;
+    @ApiModelProperty(value = "驿站名称)")
+    private String postName;
+    @ApiModelProperty(value = "驿站详细地址)")
+    private String postAddress;
     @ApiModelProperty(value = "商品图片")
     private String image;
 
     @ApiModelProperty(value = "商品规格值 ID")
-    private Integer specs;
+    private String spec;
 
     @ApiModelProperty(value = "数量")
     private Integer expNum ;

+ 1 - 2
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/request/UserExpressAddressRequest.java

@@ -42,8 +42,7 @@ public class UserExpressAddressRequest implements Serializable {
     private String expressName;
 
     @ApiModelProperty(value = "驿站电话")
-
-    @Pattern(regexp = RegularConstants.PHONE_TWO, message = "请输入正确的手机号")
+   // @Pattern(regexp = RegularConstants.PHONE_TWO, message = "请输入正确的手机号")
     private String phone;
 
     @ApiModelProperty(value = "收货人所在省")

+ 3 - 0
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/request/express/CreateExpressOrderRequest.java

@@ -12,6 +12,7 @@ import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -37,4 +38,6 @@ public class CreateExpressOrderRequest implements Serializable {
     @ApiModelProperty(value = "预下单订单号", required = true)
     @NotBlank(message = "预下单订单号不能为空")
     private String preOrderNo;
+    @ApiModelProperty(value = "平台小费")
+    private BigDecimal giveTips=BigDecimal.ZERO;
 }

+ 1 - 3
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/request/express/ExpressOrderFrontListRequest.java

@@ -29,13 +29,11 @@ public class ExpressOrderFrontListRequest extends PageParamRequest implements Se
 
     private static final long serialVersionUID = 1L;
 
-    @ApiModelProperty(value = "订单状态(-1:全部,0:待支付,1:待发货,2:部分发货, 3:待核销,4:待收货,5:已收货,6:已完成,9:已取消)")
+    @ApiModelProperty(value = "订单状态(-1:全部,0:待支付,1:待收件,5:已完成)")
    // @NotNull(message = "订单编号不能为空")
     private Integer status;
 
     @ApiModelProperty(value = "搜索关键字")
     private String keywords;
 
-    @ApiModelProperty(value = "订单类型:0-进行中,1-完成")
-    private Integer orderType;
 }

+ 20 - 8
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/request/express/PreExpressOrderDetailRequest.java

@@ -1,11 +1,13 @@
 package com.zbkj.common.request.express;
 
+import com.zbkj.common.annotation.StringContains;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 
+import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 import java.math.BigDecimal;
@@ -27,22 +29,32 @@ import java.math.BigDecimal;
 @Accessors(chain = true)
 @ApiModel(value = "PreExpressOrderDetailRequest对象", description = "预下单快递详情请求对象")
 public class PreExpressOrderDetailRequest {
-    @ApiModelProperty(value = "快递信息)")
-    private String expressInfo;
+    @NotEmpty(message = "取件码不能为空")
+    @ApiModelProperty(value = "取件码)")
+    private String pickUpCode;
+    @NotEmpty(message = "快递公司不能为空")
+    @ApiModelProperty(value = "快递公司)")
+    private String expressCompany;
+    @NotEmpty(message = "快递单号不能为空")
+    @ApiModelProperty(value = "快递单号)")
+    private String expressNo;
     @ApiModelProperty(value = "快递图片")
     private String image;
     @ApiModelProperty(value = "快递规格")
     @NotNull(message = "快递规格不能为空")
-    private Integer sepec;
+    private String  spec;
     @ApiModelProperty(value = "快递数量")
     @NotNull(message = "快递数量不能为空")
-    private Integer expressNum;
+    private Integer expressNum=1;
     @ApiModelProperty(value = "费用")
     private BigDecimal price;
     @ApiModelProperty(value = "备注")
     private String remark;
-    @ApiModelProperty(value = "订单编号")
-    private String orderNo;
-
-
+    @ApiModelProperty(value = "驿站名称")
+    private String postName;
+    @ApiModelProperty(value = "驿站联系电话")
+    private String postPhone;
+    @ApiModelProperty(value = "驿站id")
+    @NotNull(message = "驿站不能为空")
+    private Integer postAddressId;
 }

+ 2 - 5
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/request/express/PreExpressOrderRequest.java

@@ -36,14 +36,11 @@ public class PreExpressOrderRequest {
     @StringContains(limitValues = {"send", "take"}, message = "未知的预下单类型")
     private String preOrderType;
 
-    @ApiModelProperty(value = "小费")
-    private BigDecimal giveTips= BigDecimal.ZERO;
-
     @ApiModelProperty(value = "用户地址id")
     @NotNull(message="用户地址不能为空")
     private Integer userAddressId;
-    @NotNull(message="驿站地址不能为空")
-    private Integer postAddressId;
+    @ApiModelProperty(value = "预订单号")
+    private String preOrderNo;
 
     @ApiModelProperty(value = "下单详情列表", required = true)
     @NotEmpty(message = "下单详情列表不能为空")

+ 6 - 11
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/response/express/ExpressOrderFrontDataResponse.java

@@ -26,7 +26,7 @@ import java.util.List;
 @Data
 @EqualsAndHashCode(callSuper = false)
 @Accessors(chain = true)
-@ApiModel(value="OrderFrontDataResponse对象", description="订单移动端列表数据响应对象")
+@ApiModel(value="ExpressOrderFrontDataResponse对象", description="订单移动端列表数据响应对象")
 public class ExpressOrderFrontDataResponse implements Serializable {
 
     private static final long serialVersionUID = 1387727608277207652L;
@@ -37,8 +37,6 @@ public class ExpressOrderFrontDataResponse implements Serializable {
     @ApiModelProperty(value = "订单号")
     private String orderNo;
 
-    @ApiModelProperty(value = "商户ID")
-    private Integer merId;
 
     @ApiModelProperty(value = "支付状态")
     private Boolean paid;
@@ -65,15 +63,11 @@ public class ExpressOrderFrontDataResponse implements Serializable {
     private BigDecimal totalPrice;
 
     @ApiModelProperty(value = "订单详情对象列表")
-    private List<ExpressOrderInfoFrontDataResponse> orderInfoList;
-
-    @ApiModelProperty(value = "商户名称")
-    private String merName;
+    private List<PostOrderFrontDetailResponse> postOrderInfoList;
 
     @ApiModelProperty(value = "订单类型:0-寄件,1-取件")
     private Integer type;
 
-
     @ApiModelProperty(value = "过期时间")
     private Long cancelTime;
 
@@ -85,9 +79,10 @@ public class ExpressOrderFrontDataResponse implements Serializable {
 
     @ApiModelProperty(value = "过期时间")
     private String expirationTime;
-
-    @ApiModelProperty(value = "驿站地址")
-    private String postAddress;
     @ApiModelProperty(value = "用户地址")
     private String userAddress;
+    @ApiModelProperty(value = "快递员")
+    private String courier;
+    @ApiModelProperty(value = "快递员电话")
+    private String courierPhone;
 }

+ 86 - 0
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/response/express/ExpressOrderFrontDetailResponse.java

@@ -0,0 +1,86 @@
+package com.zbkj.common.response.express;
+
+import com.zbkj.common.response.MerchantOrderFrontDetailResponse;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 订单移动端详情响应对象
+ *  +----------------------------------------------------------------------
+ *  | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ *  +----------------------------------------------------------------------
+ *  | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
+ *  +----------------------------------------------------------------------
+ *  | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ *  +----------------------------------------------------------------------
+ *  | Author: CRMEB Team <admin@crmeb.com>
+ *  +----------------------------------------------------------------------
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="ExpressOrderFrontDetailResponse对象", description="订单移动端详情响应对象")
+public class ExpressOrderFrontDetailResponse implements Serializable {
+
+    private static final long serialVersionUID = -4324222121352855551L;
+
+    @ApiModelProperty(value = "订单ID")
+    private Integer id;
+
+    @ApiModelProperty(value = "订单号")
+    private String orderNo;
+
+    @ApiModelProperty(value = "用户id")
+    private Integer uid;
+
+    @ApiModelProperty(value = "订单商品总数")
+    private Integer totalNum;
+
+    @ApiModelProperty(value = "商品总价")
+    private BigDecimal proTotalPrice;
+
+    @ApiModelProperty(value = "订单总价")
+    private BigDecimal totalPrice;
+    @ApiModelProperty(value = "小费")
+    private BigDecimal giveTips;
+
+    @ApiModelProperty(value = "实际支付金额")
+    private BigDecimal payPrice;
+
+    @ApiModelProperty(value = "用户名称")
+    private String userName;
+    @ApiModelProperty(value = "支付状态")
+    private Boolean paid;
+
+    @ApiModelProperty(value = "支付时间")
+    private Date payTime;
+
+    @ApiModelProperty(value = "支付方式:weixin,alipay,yue")
+    private String payType;
+
+    @ApiModelProperty(value = "订单状态(0:待支付,1:待发货,2:部分发货, 3:待核销,4:待收货,5:已收货,6:已完成,9:已取消)")
+    private Integer status;
+
+    @ApiModelProperty(value = "创建时间")
+    private Date createTime;
+
+    @ApiModelProperty(value = "订单类型:0-取,1-寄")
+    private Integer type;
+
+    @ApiModelProperty(value = "过期时间")
+    private Long cancelTime;
+
+    @ApiModelProperty(value = "退款状态:0 未退款 1 申请中 2 部分退款 3 已退款")
+    private Integer refundStatus;
+
+    @ApiModelProperty(value = "过期时间")
+    private String expirationTime;
+}

+ 14 - 5
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/response/express/ExpressOrderInfoFrontDataResponse.java

@@ -34,14 +34,23 @@ public class ExpressOrderInfoFrontDataResponse implements Serializable {
     @ApiModelProperty(value = "主键")
     private Integer id;
 
-    @ApiModelProperty(value = "快件信息")
-    private String expressInfo;
-
+    @ApiModelProperty(value = "取件码)")
+    private String pickUpCode;
+    @ApiModelProperty(value = "快递公司)")
+    private String expressCompany;
+    @ApiModelProperty(value = "快递单号)")
+    private String expressNo;
+    @ApiModelProperty(value = "驿站名称)")
+    private String postName;
+    @ApiModelProperty(value = "驿站电话")
+    private String postPhone;
+    @ApiModelProperty(value = "驿站详细地址)")
+    private String postAddress;
     @ApiModelProperty(value = "快件图片")
     private String image;
 
-    @ApiModelProperty(value = "格值 ID")
-    private Integer specs;
+    @ApiModelProperty(value = "格值")
+    private String spec;
 
     @ApiModelProperty(value = "单价")
     private BigDecimal price;

+ 68 - 0
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/response/express/PostOrderFrontDetailResponse.java

@@ -0,0 +1,68 @@
+package com.zbkj.common.response.express;
+
+import com.zbkj.common.response.OrderInfoFrontDataResponse;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 订单移动端商户详情响应对象
+ *  +----------------------------------------------------------------------
+ *  | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ *  +----------------------------------------------------------------------
+ *  | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
+ *  +----------------------------------------------------------------------
+ *  | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ *  +----------------------------------------------------------------------
+ *  | Author: CRMEB Team <admin@crmeb.com>
+ *  +----------------------------------------------------------------------
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="PostOrderFrontDetailResponse对象", description="订单移动端商户详情响应对象")
+public class PostOrderFrontDetailResponse implements Serializable {
+
+    private static final long serialVersionUID = -4324222121352855551L;
+
+    @ApiModelProperty(value = "驿站名称")
+    private String postName;
+
+    @ApiModelProperty(value = "驿站id")
+    private Integer postAddressId;
+
+    @ApiModelProperty(value = "驿站详细地址")
+    private String addressDetail;
+
+    @ApiModelProperty(value = "联系电话")
+    private String phone;
+
+    @ApiModelProperty(value = "订单商品总数")
+    private Integer totalNum=0;
+
+    @ApiModelProperty(value = "商品总价")
+    private BigDecimal proTotalPrice;
+
+    @ApiModelProperty(value = "订单总价")
+    private BigDecimal totalPrice;
+
+    @ApiModelProperty(value = "实际支付金额")
+    private BigDecimal payPrice;
+
+
+    @ApiModelProperty(value = "纬度")
+    private String merLatitude;
+
+    @ApiModelProperty(value = "经度")
+    private String merLongitude;
+
+    @ApiModelProperty(value = "订单详情")
+    private List<ExpressOrderInfoFrontDataResponse> orderInfoList;
+
+}

+ 3 - 6
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/response/express/PreExpressOrderResponse.java

@@ -1,6 +1,7 @@
 package com.zbkj.common.response.express;
 
 import com.zbkj.common.vo.PreExpressOrderInfoDetailVo;
+import com.zbkj.common.vo.PrePostOrderInfoVo;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -48,16 +49,12 @@ public class PreExpressOrderResponse implements Serializable {
 
     @ApiModelProperty(value = "用户地址id")
     private Integer userAddressId;
-    @ApiModelProperty(value = "驿站地址id")
-    private Integer expressAddressId;
 
     @ApiModelProperty(value = "订单类型:0-取件,1-寄件")
     private Integer type;
     @ApiModelProperty(value = "用户可用余额")
     private BigDecimal userBalance;
-    @ApiModelProperty(value = "小费")
-    private BigDecimal giveTips= BigDecimal.ZERO;
-    @ApiModelProperty(value = "用户订单数组")
-    private List<PreExpressOrderInfoDetailResponse> userOrderVoList;
+    @ApiModelProperty(value = "驿站快件数组")
+    private List<PrePostOrderInfoResponse> postOrderList;
 
 }

+ 33 - 0
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/response/express/PrePostOrderInfoResponse.java

@@ -0,0 +1,33 @@
+package com.zbkj.common.response.express;
+
+import com.zbkj.common.vo.PreExpressOrderInfoDetailVo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.List;
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value = "PrePostOrderInfoResponse", description = "预下单响应对象")
+public class PrePostOrderInfoResponse implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "驿站id")
+    private Integer postAddressId;
+
+    @ApiModelProperty(value = "驿站名称")
+    private String postName;
+
+    @ApiModelProperty(value = "驿站详细地址")
+    private String addressDetail;
+
+    @ApiModelProperty(value = "联系电话")
+    private String phone;
+
+    @ApiModelProperty(value = "快递详情数组")
+    private List<PreExpressOrderInfoDetailVo> orderInfoList;
+}

+ 25 - 20
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/vo/PreExpressOrderInfoDetailVo.java

@@ -1,11 +1,15 @@
 package com.zbkj.common.vo;
 
+import com.zbkj.common.annotation.StringContains;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
 import java.math.BigDecimal;
 
 /**
@@ -23,28 +27,29 @@ import java.math.BigDecimal;
 @Data
 @EqualsAndHashCode(callSuper = false)
 @Accessors(chain = true)
-@ApiModel(value = "PreOrderInfoDetailVo对象", description = "预下单订单详情Vo对象")
+@ApiModel(value = "PreExpressOrderInfoDetailVo对象", description = "预下单订单详情Vo对象")
 public class PreExpressOrderInfoDetailVo {
-    @ApiModelProperty(value = "快递信息")
-    private String expressInfo;
-
-    @ApiModelProperty(value = "规格")
-    private Integer specId;
-
-    @ApiModelProperty(value = "商品图片")
+    @NotEmpty(message = "取件码不能为空")
+    @ApiModelProperty(value = "取件码")
+    private String pickUpCode;
+    @NotEmpty(message = "快递公司不能为空")
+    @ApiModelProperty(value = "快递公司")
+    private String expressCompany;
+    @NotEmpty(message = "快递单号不能为空")
+    @ApiModelProperty(value = "快递单号")
+    private String expressNo;
+    @ApiModelProperty(value = "快递图片")
     private String image;
-
+    @ApiModelProperty(value = "快递规格")
+    @NotNull(message = "快递规格不能为空")
+    private String spec;
+    @ApiModelProperty(value = "快递数量")
+    @NotNull(message = "快递数量不能为空")
+    private Integer expressNum = 1;
+    @ApiModelProperty(value = "费用")
+    private BigDecimal price;
     @ApiModelProperty(value = "备注")
     private String remark;
-
-    @ApiModelProperty(value = "单价")
-    private BigDecimal price;
-
-    @ApiModelProperty(value = "实际支付金额")
-    private BigDecimal payPrice;
-
-    @ApiModelProperty(value = "数量")
-    private Integer expressNum;
-
-
+    @ApiModelProperty(value = "快递内部标示")
+    private String expressId;
 }

+ 5 - 6
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/vo/PreExpressOrderInfoVo.java

@@ -49,15 +49,14 @@ public class PreExpressOrderInfoVo implements Serializable {
 
     @ApiModelProperty(value = "用户地址id")
     private Integer userAddressId;
-    @ApiModelProperty(value = "驿站地址id")
-    private Integer postAddressId;
 
     @ApiModelProperty(value = "订单类型:0-取件,1-寄件")
     private Integer type;
     @ApiModelProperty(value = "用户可用余额")
     private BigDecimal userBalance;
-    @ApiModelProperty(value = "小费")
-    private BigDecimal giveTips= BigDecimal.ZERO;
-    @ApiModelProperty(value = "用户订单数组")
-    private List<PreExpressOrderInfoDetailVo> userOrderVoList;
+    @ApiModelProperty(value = "预订单号")
+    private String preOrderNo;
+
+    @ApiModelProperty(value = "驿站快件数组")
+    private List<PrePostOrderInfoVo> postOrderList;
 }

+ 34 - 0
ydd_mer_java/crmeb-common/src/main/java/com/zbkj/common/vo/PrePostOrderInfoVo.java

@@ -0,0 +1,34 @@
+package com.zbkj.common.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value = "PrePostOrderInfoVo对象", description = "预下单驿站订单Vo对象")
+public class PrePostOrderInfoVo implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "驿站id")
+    private Integer postAddressId;
+
+    @ApiModelProperty(value = "驿站名称")
+    private String postName;
+
+    @ApiModelProperty(value = "驿站详细地址")
+    private String addressDetail;
+
+    @ApiModelProperty(value = "联系电话")
+    private String phone;
+
+    @ApiModelProperty(value = "快递详情数组")
+    private List<PreExpressOrderInfoDetailVo> orderInfoList;
+}

+ 12 - 6
ydd_mer_java/crmeb-front/src/main/java/com/zbkj/front/controller/ExpressOrderController.java

@@ -4,12 +4,10 @@ import com.zbkj.common.page.CommonPage;
 import com.zbkj.common.request.*;
 import com.zbkj.common.request.express.CreateExpressOrderRequest;
 import com.zbkj.common.request.express.ExpressOrderFrontListRequest;
+import com.zbkj.common.request.express.PreExpressOrderDetailRequest;
 import com.zbkj.common.request.express.PreExpressOrderRequest;
 import com.zbkj.common.response.*;
-import com.zbkj.common.response.express.ExpressOrderFrontDataResponse;
-import com.zbkj.common.response.express.ExpressOrderInfoFrontDataResponse;
-import com.zbkj.common.response.express.ExpressOrderNoResponse;
-import com.zbkj.common.response.express.PreExpressOrderResponse;
+import com.zbkj.common.response.express.*;
 import com.zbkj.common.result.CommonResult;
 import com.zbkj.common.vo.LogisticsResultVo;
 import com.zbkj.front.service.FrontExpressOrderService;
@@ -50,13 +48,16 @@ public class ExpressOrderController {
     public CommonResult<ExpressOrderNoResponse> preOrder(@RequestBody @Validated PreExpressOrderRequest request) {
         return CommonResult.success(expressOrderService.preOrder(request));
     }
-
     @ApiOperation(value = "加载预下单")
     @RequestMapping(value = "load/pre/{preOrderNo}", method = RequestMethod.GET)
     public CommonResult<PreExpressOrderResponse> loadPreOrder(@PathVariable String preOrderNo) {
         return CommonResult.success(expressOrderService.loadPreOrder(preOrderNo));
     }
-
+    @ApiOperation(value = "预下单删除")
+    @RequestMapping(value = "/pre/del/{preOrderNo}", method = RequestMethod.POST)
+    public CommonResult<Boolean> preDel(@PathVariable String preOrderNo,@RequestBody List<String>expRessIdList) {
+        return CommonResult.success(expressOrderService.delPreOrder(preOrderNo,expRessIdList));
+    }
 
     @ApiOperation(value = "创建订单")
     @RequestMapping(value = "/create", method = RequestMethod.POST)
@@ -68,4 +69,9 @@ public class ExpressOrderController {
     public CommonResult<CommonPage<ExpressOrderFrontDataResponse>> orderList(@ModelAttribute @Validated ExpressOrderFrontListRequest request) {
         return CommonResult.success(CommonPage.restPage(expressOrderService.list(request)));
     }
+    @ApiOperation(value = "订单详情")
+    @RequestMapping(value = "/detail/{orderNo}", method = RequestMethod.GET)
+    public CommonResult<ExpressOrderFrontDetailResponse> orderDetail(@PathVariable String orderNo) {
+        return CommonResult.success(expressOrderService.frontDetail(orderNo));
+    }
 }

+ 58 - 0
ydd_mer_java/crmeb-front/src/main/java/com/zbkj/front/controller/ExpressPayController.java

@@ -0,0 +1,58 @@
+package com.zbkj.front.controller;
+
+import com.zbkj.common.request.OrderPayRequest;
+import com.zbkj.common.request.WechatPaymentQueryRequest;
+import com.zbkj.common.response.CashierInfoResponse;
+import com.zbkj.common.response.OrderPayResultResponse;
+import com.zbkj.common.response.PayConfigResponse;
+import com.zbkj.common.result.CommonResult;
+import com.zbkj.service.service.ExpressPayService;
+import com.zbkj.service.service.PayService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 支付控制器
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team <admin@crmeb.com>
+ * +----------------------------------------------------------------------
+ */
+@Slf4j
+@RestController
+@RequestMapping("api/front/pay/express")
+@Api(tags = "快递订单支付管理")
+public class ExpressPayController {
+
+    @Autowired
+    private ExpressPayService payService;
+
+    @ApiOperation(value = "订单支付")
+    @RequestMapping(value = "/payment", method = RequestMethod.POST)
+    public CommonResult<OrderPayResultResponse> payment(@RequestBody @Validated OrderPayRequest orderPayRequest) {
+        return CommonResult.success(payService.payment(orderPayRequest));
+    }
+
+    @ApiOperation(value = "查询订单微信支付结果")
+    @RequestMapping(value = "/query/wechat/pay/result/{orderNo}", method = RequestMethod.GET)
+    public CommonResult<Boolean> queryPayResult(@PathVariable(value = "orderNo") String orderNo) {
+        return CommonResult.success(payService.queryWechatPayResult(orderNo));
+    }
+
+
+
+    @ApiOperation(value = "查询微信支付结果")
+    @RequestMapping(value = "/query/wechat/payment/result", method = RequestMethod.GET)
+    public CommonResult<Boolean> queryWechatPaymentResult(@Validated WechatPaymentQueryRequest request) {
+        return CommonResult.success(payService.queryWechatPaymentResult(request));
+    }
+}

+ 18 - 4
ydd_mer_java/crmeb-front/src/main/java/com/zbkj/front/service/FrontExpressOrderService.java

@@ -6,12 +6,10 @@ import com.zbkj.common.model.user.UserAddress;
 import com.zbkj.common.request.*;
 import com.zbkj.common.request.express.CreateExpressOrderRequest;
 import com.zbkj.common.request.express.ExpressOrderFrontListRequest;
+import com.zbkj.common.request.express.PreExpressOrderDetailRequest;
 import com.zbkj.common.request.express.PreExpressOrderRequest;
 import com.zbkj.common.response.*;
-import com.zbkj.common.response.express.ExpressOrderFrontDataResponse;
-import com.zbkj.common.response.express.ExpressOrderInfoFrontDataResponse;
-import com.zbkj.common.response.express.ExpressOrderNoResponse;
-import com.zbkj.common.response.express.PreExpressOrderResponse;
+import com.zbkj.common.response.express.*;
 import com.zbkj.common.vo.LogisticsResultVo;
 import com.zbkj.common.vo.PreOrderInfoVo;
 
@@ -39,6 +37,15 @@ public interface FrontExpressOrderService {
      */
     ExpressOrderNoResponse preOrder(PreExpressOrderRequest request);
 
+    /**
+     * 预下单
+     * @param expRessIdList 预下单请求参数
+     * @return ExpressOrderResponse
+     */
+    boolean delPreOrder(String preOrderNo,List<String>expRessIdList);
+
+
+
 
     /**
      * 加载预下单信息
@@ -63,5 +70,12 @@ public interface FrontExpressOrderService {
      */
     PageInfo<ExpressOrderFrontDataResponse> list(ExpressOrderFrontListRequest request);
 
+    /**
+     * 移动端订单详情
+     * @param orderNo 订单编号
+     * @return OrderFrontDetailResponse
+     */
+    ExpressOrderFrontDetailResponse frontDetail(String orderNo);
+
 
 }

+ 218 - 92
ydd_mer_java/crmeb-front/src/main/java/com/zbkj/front/service/impl/FrontExpressOrderServiceImpl.java

@@ -62,6 +62,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.support.TransactionTemplate;
 
@@ -98,6 +99,8 @@ public class FrontExpressOrderServiceImpl implements FrontExpressOrderService {
     private UserExpressAddressService userExpressAddressService;
     @Autowired
     private RedisUtil redisUtil;
+    @Autowired
+    private SystemAttachmentService systemAttachmentService;
 
     @Autowired
     private TransactionTemplate transactionTemplate;
@@ -117,16 +120,26 @@ public class FrontExpressOrderServiceImpl implements FrontExpressOrderService {
         User user = userService.getInfo();
         // 校验预下单商品信息
         PreExpressOrderInfoVo preOrderInfoVo = validatePreOrderRequest(request, user);
-        BigDecimal totalPrice = preOrderInfoVo.getUserOrderVoList().stream()
-                    .map(e -> e.getPrice().multiply(new BigDecimal(e.getExpressNum())))
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-        preOrderInfoVo.setProTotalFee(totalPrice);
-        preOrderInfoVo.setOrderProNum(preOrderInfoVo.getUserOrderVoList().stream().mapToInt(PreExpressOrderInfoDetailVo::getExpressNum).sum());
-        // 实际支付金额
-        preOrderInfoVo.setPayFee(preOrderInfoVo.getProTotalFee().add(preOrderInfoVo.getGiveTips()));
-        preOrderInfoVo.setUserBalance(user.getNowMoney());
         return createPreOrderResponse(user.getId(), preOrderInfoVo);
     }
+
+    @Override
+    public boolean delPreOrder(String preOrderNo,List<String> expRessIdList) {
+        if(ObjectUtil.isNotEmpty(preOrderNo)&&redisUtil.exists(OrderConstants.PRE_EXP_ORDER_CACHE_PREFIX + preOrderNo)) {
+            String orderVoString = redisUtil.get(OrderConstants.PRE_EXP_ORDER_CACHE_PREFIX + preOrderNo).toString();
+            PreExpressOrderInfoVo preOrderInfoVo = JSONObject.parseObject(orderVoString, PreExpressOrderInfoVo.class);
+            List<PrePostOrderInfoVo> postOrderVoList = preOrderInfoVo.getPostOrderList();
+            postOrderVoList.forEach(e -> {
+                    for (String expRessId:expRessIdList) {
+                            e.getOrderInfoList().removeIf(item->item.getExpressId().equals(expRessId));
+                    }
+            });
+            redisUtil.set(OrderConstants.PRE_EXP_ORDER_CACHE_PREFIX + preOrderNo, JSONObject.toJSONString(preOrderInfoVo), OrderConstants.PRE_ORDER_CACHE_TIME, TimeUnit.MINUTES);
+           return true;
+        }
+        throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "预下单快递不存在");
+    }
+
     /**
      * 订单列表
      * @param request 搜索参数
@@ -145,15 +158,40 @@ public class FrontExpressOrderServiceImpl implements FrontExpressOrderService {
         for (ExpressOrder order : orderList) {
             ExpressOrderFrontDataResponse infoResponse = new ExpressOrderFrontDataResponse();
             BeanUtils.copyProperties(order, infoResponse);
+            List<PostOrderFrontDetailResponse> postOrderVoList = CollUtil.newArrayList();
             // 订单详情对象列表
             List<ExpressOrderDetail> orderDetailList = orderDetailService.getByOrderNo(order.getOrderNo());
-            List<ExpressOrderInfoFrontDataResponse> infoResponseList = CollUtil.newArrayList();
-            orderDetailList.forEach(e -> {
-                ExpressOrderInfoFrontDataResponse orderInfoResponse = new ExpressOrderInfoFrontDataResponse();
-                BeanUtils.copyProperties(e, orderInfoResponse);
-                infoResponseList.add(orderInfoResponse);
+            Map<String, List<ExpressOrderDetail>> orderDetailMap = orderDetailList.stream().collect(Collectors.groupingBy(ExpressOrderDetail::getPostName));
+            orderDetailMap.forEach((key, value) -> {
+                BigDecimal proTotalFee=BigDecimal.ZERO;
+                Integer orderNum=0;
+                PostOrderFrontDetailResponse   postOrderFrontDetail=new  PostOrderFrontDetailResponse();
+                List<ExpressOrderDetail> detailList = orderDetailMap.get(key);
+                List<ExpressOrderInfoFrontDataResponse> dataResponseList = detailList.stream().map(d -> {
+                    ExpressOrderInfoFrontDataResponse dataResponse = new ExpressOrderInfoFrontDataResponse();
+                    BeanUtils.copyProperties(d, dataResponse);
+                    postOrderFrontDetail.setPostName(d.getPostName());
+                    postOrderFrontDetail.setAddressDetail(d.getPostAddress());
+                    postOrderFrontDetail.setPhone(d.getPostPhone());
+                    return dataResponse;
+                }).collect(Collectors.toList());
+                proTotalFee = detailList.stream()
+                        .map(e -> {
+                            BigDecimal price;
+                            price = e.getPrice().multiply(new BigDecimal(e.getExpNum()));
+                            return price;
+                        }).reduce(BigDecimal.ZERO, BigDecimal::add);
+                orderNum = detailList.stream()
+                        .mapToInt(e -> {
+                            return e.getExpNum()!=null?e.getExpNum():0;
+                        }).sum();
+                postOrderFrontDetail.setOrderInfoList(dataResponseList);
+                postOrderFrontDetail.setTotalNum(orderNum);
+                postOrderFrontDetail.setTotalPrice(proTotalFee);
+                postOrderFrontDetail.setPayPrice(proTotalFee);
+                postOrderVoList.add(postOrderFrontDetail);
             });
-            infoResponse.setOrderInfoList(infoResponseList);
+            infoResponse.setPostOrderInfoList(postOrderVoList);
             if (!order.getPaid()) {
                 cancelTime = DateUtil.offset(order.getCreateTime(), DateField.MINUTE, crmebConfig.getOrderCancelTime());
                 infoResponse.setCancelTime(cancelTime.getTime());
@@ -168,7 +206,48 @@ public class FrontExpressOrderServiceImpl implements FrontExpressOrderService {
         return CommonPage.copyPageInfo(pageInfo, responseList);
     }
     private ExpressOrderNoResponse createPreOrderResponse(Integer userId, PreExpressOrderInfoVo preOrderInfoVo) {
-        String key = userId + CrmebDateUtil.getNowTime().toString() + CrmebUtil.getUuid();
+        String key=preOrderInfoVo.getPreOrderNo();
+        if(ObjectUtil.isNotEmpty(key)&&redisUtil.exists(OrderConstants.PRE_EXP_ORDER_CACHE_PREFIX + key)) {
+            key=preOrderInfoVo.getPreOrderNo();
+            String orderVoString = redisUtil.get(OrderConstants.PRE_EXP_ORDER_CACHE_PREFIX + key).toString();
+            PreExpressOrderInfoVo sourcePreOrderInfoVo = JSONObject.parseObject(orderVoString, PreExpressOrderInfoVo.class);
+            List<PrePostOrderInfoVo> postOrderVoList = preOrderInfoVo.getPostOrderList();
+            if(postOrderVoList==null|| postOrderVoList.size()==0){
+                throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "未找到对应快递驿站");
+            }
+            //sourcePreOrderInfoVo.getPostOrderList().forEach(e -> {
+            PrePostOrderInfoVo  curPostOrderVo=postOrderVoList.get(0);
+            if(sourcePreOrderInfoVo.getPostOrderList().stream().anyMatch(m -> m.getPostAddressId().toString().equals(curPostOrderVo.getPostAddressId().toString()))){
+                for (PrePostOrderInfoVo orderVo : sourcePreOrderInfoVo.getPostOrderList()) {
+                    if (orderVo.getPostAddressId().toString().equals(curPostOrderVo.getPostAddressId().toString())) {
+                        orderVo.getOrderInfoList().addAll(curPostOrderVo.getOrderInfoList());
+                        break;
+                    }
+                }
+            }else {
+                sourcePreOrderInfoVo.getPostOrderList().addAll(preOrderInfoVo.getPostOrderList());
+            }
+            BigDecimal proTotalFee=BigDecimal.ZERO;
+            Integer orderNum=0;
+            for(PrePostOrderInfoVo prePostOrderInfoVo:sourcePreOrderInfoVo.getPostOrderList()) {
+                proTotalFee = proTotalFee.add(prePostOrderInfoVo.getOrderInfoList().stream()
+                        .map(e -> {
+                            BigDecimal price;
+                            price = e.getPrice().multiply(new BigDecimal(e.getExpressNum()));
+                            return price;
+                        }).reduce(BigDecimal.ZERO, BigDecimal::add));
+                 orderNum = orderNum+prePostOrderInfoVo.getOrderInfoList().stream()
+                        .mapToInt(e -> {
+                            return e.getExpressNum()!=null?e.getExpressNum():0;
+                        }).sum();
+            }
+            sourcePreOrderInfoVo.setOrderProNum(orderNum);
+            sourcePreOrderInfoVo.setPayFee(proTotalFee);
+            sourcePreOrderInfoVo.setProTotalFee(proTotalFee);
+            BeanUtils.copyProperties(sourcePreOrderInfoVo,preOrderInfoVo);
+        }else{
+            key = userId + CrmebDateUtil.getNowTime().toString() + CrmebUtil.getUuid();
+        }
         redisUtil.set(OrderConstants.PRE_EXP_ORDER_CACHE_PREFIX + key, JSONObject.toJSONString(preOrderInfoVo), OrderConstants.PRE_ORDER_CACHE_TIME, TimeUnit.MINUTES);
         ExpressOrderNoResponse response = new ExpressOrderNoResponse();
         response.setOrderNo(key);
@@ -185,8 +264,6 @@ public class FrontExpressOrderServiceImpl implements FrontExpressOrderService {
      */
     @Override
     public PreExpressOrderResponse loadPreOrder(String preOrderNo) {
-//        Integer userId = userService.getUserIdException();
-//        User user = userService.getById(userId);
         // 通过缓存获取预下单对象
         String key = OrderConstants.PRE_EXP_ORDER_CACHE_PREFIX + preOrderNo;
         boolean exists = redisUtil.exists(key);
@@ -197,14 +274,14 @@ public class FrontExpressOrderServiceImpl implements FrontExpressOrderService {
         PreExpressOrderInfoVo orderInfoVo = JSONObject.parseObject(orderVoString, PreExpressOrderInfoVo.class);
         PreExpressOrderResponse preOrderResponse = new PreExpressOrderResponse();
         BeanUtils.copyProperties(orderInfoVo, preOrderResponse);
-        List<PreExpressOrderInfoDetailResponse> infoResponseList = new ArrayList<>();
-        List<PreExpressOrderInfoDetailVo> merchantOrderVoList = orderInfoVo.getUserOrderVoList();
-        for (PreExpressOrderInfoDetailVo merchantOrderVo : merchantOrderVoList) {
-            PreExpressOrderInfoDetailResponse infoResponse = new PreExpressOrderInfoDetailResponse();
-            BeanUtils.copyProperties(merchantOrderVo, infoResponse);
+        List<PrePostOrderInfoResponse> infoResponseList = new ArrayList<>();
+        List<PrePostOrderInfoVo> postOrderVoList = orderInfoVo.getPostOrderList();
+        for (PrePostOrderInfoVo postOrderVo : postOrderVoList) {
+            PrePostOrderInfoResponse infoResponse = new PrePostOrderInfoResponse();
+            BeanUtils.copyProperties(postOrderVo, infoResponse);
             infoResponseList.add(infoResponse);
         }
-        preOrderResponse.setUserOrderVoList(infoResponseList);
+        preOrderResponse.setPostOrderList(infoResponseList);
         return preOrderResponse;
 
     }
@@ -226,7 +303,7 @@ public class FrontExpressOrderServiceImpl implements FrontExpressOrderService {
         }
         String orderVoString = redisUtil.get(key).toString();
         PreExpressOrderInfoVo orderInfoVo = JSONObject.parseObject(orderVoString, PreExpressOrderInfoVo.class);
-
+       UserAddress userAddress = userAddressService.getById(orderInfoVo.getUserAddressId());
         // 平台订单
         ExpressOrder order = new ExpressOrder();
         String orderNo = CrmebUtil.getOrderNo(OrderConstants.ORDER_PREFIX_PLATFORM);
@@ -234,34 +311,42 @@ public class FrontExpressOrderServiceImpl implements FrontExpressOrderService {
         order.setUid(user.getId());
         order.setTotalNum(orderInfoVo.getOrderProNum());
         order.setProTotalPrice(orderInfoVo.getProTotalFee());
-        order.setGiveTips(orderInfoVo.getGiveTips());
+        order.setGiveTips(ObjectUtil.isNull(order.getGiveTips())?BigDecimal.ZERO:order.getGiveTips());
         order.setTotalPrice(order.getProTotalPrice().add(order.getGiveTips()));
         order.setPayPrice(order.getTotalPrice());
         order.setPaid(false);
         order.setUserPhone(orderInfoVo.getUserPhone());
-        order.setUserAddressId(orderInfoVo.getUserAddressId());
-        order.setPostAddressId(orderInfoVo.getPostAddressId());
+        String userAddressStr = userAddress.getProvince() + userAddress.getCity() + userAddress.getDistrict() + userAddress.getStreet() + userAddress.getDetail();
+        order.setUserAddress(userAddressStr);
         order.setCancelStatus(OrderConstants.ORDER_CANCEL_STATUS_NORMAL);
         order.setType(orderInfoVo.getType());
         order.setCreateTime(DateUtil.date());
         // 订单明细
         List<ExpressOrderDetail> orderDetailList = new ArrayList<>();
-        for (PreExpressOrderInfoDetailVo userOrderVo : orderInfoVo.getUserOrderVoList()) {
-            ExpressOrderDetail orderDetail = new ExpressOrderDetail();
-            orderDetail.setOrderNo(order.getOrderNo());
-            orderDetail.setUid(user.getId());
-            orderDetail.setExpressType(orderInfoVo.getType());
-            orderDetail.setExpNum(userOrderVo.getExpressNum());
-            orderDetail.setImage(userOrderVo.getImage());
-            orderDetail.setIsReceipt(false);
-            orderDetail.setPrice(userOrderVo.getPrice());
-            orderDetail.setPayPrice(orderDetail.getPrice().multiply(new BigDecimal(orderDetail.getExpNum().toString())));
-            if (orderDetail.getPayPrice().compareTo(BigDecimal.ZERO) < 0) {
-                throw new CrmebException("订单详情价格计算错误,详情价格不能小于0");
+        for(PrePostOrderInfoVo postOrder:orderInfoVo.getPostOrderList()) {
+            for (PreExpressOrderInfoDetailVo userOrderVo : postOrder.getOrderInfoList()) {
+                ExpressOrderDetail orderDetail = new ExpressOrderDetail();
+                orderDetail.setOrderNo(order.getOrderNo());
+                orderDetail.setUid(user.getId());
+                orderDetail.setType(orderInfoVo.getType());
+                orderDetail.setExpNum(userOrderVo.getExpressNum());
+                orderDetail.setImage(userOrderVo.getImage());
+                orderDetail.setIsReceipt(false);
+                orderDetail.setPrice(userOrderVo.getPrice());
+                orderDetail.setPayPrice(orderDetail.getPrice().multiply(new BigDecimal(orderDetail.getExpNum().toString())));
+                if (orderDetail.getPayPrice().compareTo(BigDecimal.ZERO) < 0) {
+                    throw new CrmebException("订单详情价格计算错误,详情价格不能小于0");
+                }
+                orderDetail.setType(orderInfoVo.getType());
+                orderDetail.setPostAddress(postOrder.getAddressDetail());
+                orderDetail.setPostName(postOrder.getPostName());
+                orderDetail.setPostPhone(postOrder.getPhone());
+                orderDetail.setPickUpCode(userOrderVo.getPickUpCode());
+                orderDetail.setExpressNo(userOrderVo.getExpressNo());
+                orderDetail.setExpressCompany(userOrderVo.getExpressCompany());
+                orderDetail.setSpec(userOrderVo.getSpec());
+                orderDetailList.add(orderDetail);
             }
-            orderDetail.setExpressInfo(userOrderVo.getExpressInfo());
-            orderDetail.setSpecs(userOrderVo.getSpecId());
-            orderDetailList.add(orderDetail);
         }
         Boolean execute = transactionTemplate.execute(e -> {
             orderService.save(order);
@@ -289,6 +374,7 @@ public class FrontExpressOrderServiceImpl implements FrontExpressOrderService {
         response.setPayPrice(order.getPayPrice());
         return response;
     }
+
     /**
      * 校验预下单商品信息
      *
@@ -297,83 +383,123 @@ public class FrontExpressOrderServiceImpl implements FrontExpressOrderService {
      */
     private PreExpressOrderInfoVo validatePreOrderRequest(PreExpressOrderRequest request, User user) {
         PreExpressOrderInfoVo preOrderInfoVo = new PreExpressOrderInfoVo();
-        UserAddress userAddress = null;
-        UserExpressAddress userExpressAddress = null;
-        if (ObjectUtil.isNull(request.getUserAddressId())) {
-            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "请选择用户地址");
-        }
-        userAddress = userAddressService.getById(request.getUserAddressId());
-        if (ObjectUtil.isNull(userAddress) || userAddress.getIsDel()) {
-            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "用户地址有误");
-        }
-        if (ObjectUtil.isNull(request.getPostAddressId())) {
-            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "请选择驿站地址");
-        }
-        userExpressAddress = userExpressAddressService.getById(request.getPostAddressId());
-        if (ObjectUtil.isNull(userExpressAddress) || userExpressAddress.getIsDel()) {
-            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "驿站地址有误");
-        }
-        List<PreExpressOrderInfoDetailVo> userOrderVoList = CollUtil.newArrayList();
+        List<PrePostOrderInfoVo> postOrderVoList = CollUtil.newArrayList();
+        postOrderVoList = validatePreOrder(request, user);
         switch (request.getPreOrderType()) {
             case "take":
-                userOrderVoList = validatePreOrder(request, user);
                 preOrderInfoVo.setType(0);
                 break;
             case "send":
-                userOrderVoList = validatePreOrder(request, user);
                 preOrderInfoVo.setType(1);
                 break;
         }
-        if(ObjectUtil.isNull(request.getGiveTips())){
-            request.setGiveTips(BigDecimal.ZERO);
-        }
-        BigDecimal proPrice = userOrderVoList.stream()
-                .map(e -> {
-                    BigDecimal price;
-                    price = e.getPrice().multiply(new BigDecimal(e.getExpressNum()));
-                    return price;
-                })
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
+        UserAddress userAddress=userAddressService.getById(request.getUserAddressId());
         preOrderInfoVo.setUserPhone(userAddress.getPhone());
-        preOrderInfoVo.setProTotalFee(proPrice);
-        preOrderInfoVo.setGiveTips(BigDecimal.ZERO);
-        preOrderInfoVo.setPostAddressId(request.getPostAddressId());
         preOrderInfoVo.setUserAddressId(request.getUserAddressId());
         preOrderInfoVo.setUserId(user.getId());
         preOrderInfoVo.setUserName(user.getRealName());
-        preOrderInfoVo.setUserOrderVoList(userOrderVoList);
+        preOrderInfoVo.setUserBalance(user.getNowMoney());
+        preOrderInfoVo.setPostOrderList(postOrderVoList);
+        BigDecimal proTotalFee=BigDecimal.ZERO;
+        BigDecimal orderNum=BigDecimal.ZERO;
+       for(PrePostOrderInfoVo prePostOrderInfoVo:postOrderVoList) {
+           proTotalFee = prePostOrderInfoVo.getOrderInfoList().stream()
+                   .map(e -> {
+                       BigDecimal price;
+                       price = e.getPrice().multiply(new BigDecimal(e.getExpressNum()));
+                       return price;
+                   }).reduce(BigDecimal.ZERO, BigDecimal::add);
+           orderNum = prePostOrderInfoVo.getOrderInfoList().stream()
+                   .map(e -> {
+                       BigDecimal orderProNum;
+                       orderProNum = new BigDecimal(e.getExpressNum());
+                       return orderProNum;
+                   }).reduce(BigDecimal.ZERO, BigDecimal::add);
+       }
+        preOrderInfoVo.setProTotalFee(proTotalFee);
+        preOrderInfoVo.setPayFee(proTotalFee);
+        preOrderInfoVo.setOrderProNum(orderNum.intValue());
+        preOrderInfoVo.setPreOrderNo(request.getPreOrderNo());
         return preOrderInfoVo;
     }
 
     /**
      * 基础商品校验
      */
-    private PreExpressOrderInfoDetailVo validatePreOrderBase(PreExpressOrderDetailRequest detailRequest) {
-        if (ObjectUtil.isNull(detailRequest.getExpressInfo())) {
-            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "取件信息不能为空");
+    private PrePostOrderInfoVo validatePreOrderBase(PreExpressOrderDetailRequest detailRequest) {
+        if (ObjectUtil.isNull(detailRequest.getPickUpCode())) {
+            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "取件码不能为空");
+        }
+        if (ObjectUtil.isNull(detailRequest.getExpressCompany())) {
+            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "快递公司不能为空");
         }
-        if (ObjectUtil.isNull(detailRequest.getExpressNum())|| detailRequest.getExpressNum()<0) {
-            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "取件数量不能为空");
+        if (ObjectUtil.isNull(detailRequest.getExpressNo())) {
+            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "快递单号不能为空");
         }
-        if (ObjectUtil.isNull(detailRequest.getSepec())) {
+        if (ObjectUtil.isNull(detailRequest.getSpec())) {
             throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "规格不能为空");
         }
          // 构造PreExpressOrderInfoDetailVo对象
-        PreExpressOrderInfoDetailVo orderVo = new PreExpressOrderInfoDetailVo();
-        BigDecimal payPrice = detailRequest.getPrice().multiply(new BigDecimal(detailRequest.getExpressNum()));
-        orderVo.setPayPrice(payPrice);
-        BeanUtils.copyProperties(detailRequest,orderVo);
-        return orderVo;
+        UserExpressAddress  userExpressAddress= userExpressAddressService.getById(detailRequest.getPostAddressId());
+        PrePostOrderInfoVo postOrderVo=new PrePostOrderInfoVo();
+        postOrderVo.setPostAddressId(detailRequest.getPostAddressId());
+        postOrderVo.setPostName(userExpressAddress.getExpressName());
+        postOrderVo.setPhone(userExpressAddress.getPhone());
+        postOrderVo.setAddressDetail(userExpressAddress.getDetail());
+        List<PreExpressOrderInfoDetailVo> infoList = CollUtil.newArrayList();
+        PreExpressOrderInfoDetailVo detailVo = new PreExpressOrderInfoDetailVo();//
+        BeanUtils.copyProperties(detailRequest,detailVo);
+        detailVo.setExpressId("EXP"+CrmebDateUtil.getNowTime().toString()+CrmebUtil.getUuid());
+        detailVo.setImage(systemAttachmentService.clearPrefix(detailRequest.getImage()));
+        infoList.add(detailVo);
+        postOrderVo.setOrderInfoList(infoList);
+        //BigDecimal payPrice = detailRequest.getPrice().multiply(new BigDecimal(detailRequest.getExpressNum()));
+        //orderVo.setPayPrice(payPrice);
+         return postOrderVo;
     }
 
-    private List<PreExpressOrderInfoDetailVo> validatePreOrder(PreExpressOrderRequest request, User user) {
-        List<PreExpressOrderInfoDetailVo> userOrderVoList = CollUtil.newArrayList();
+    private List<PrePostOrderInfoVo> validatePreOrder(PreExpressOrderRequest request, User user) {
+        List<PrePostOrderInfoVo> postOrderVoList = CollUtil.newArrayList();
         request.getOrderDetails().forEach(e -> {
-            PreExpressOrderInfoDetailVo userOrderVo = validatePreOrderBase(e);
-            userOrderVoList.add(userOrderVo);
+            PrePostOrderInfoVo postOrderVo = validatePreOrderBase(e);
+            if (postOrderVoList.stream().anyMatch(m -> m.getPostAddressId().equals(postOrderVo.getPostAddressId()))) {
+                for (PrePostOrderInfoVo orderVo : postOrderVoList) {
+                    if (orderVo.getPostAddressId().toString().equals(postOrderVo.getPostAddressId().toString())) {
+                        orderVo.getOrderInfoList().addAll(postOrderVo.getOrderInfoList());
+                        break;
+                    }
+                }
+            } else {
+                postOrderVoList.add(postOrderVo);
+            }
         });
-        return userOrderVoList;
+        return  postOrderVoList;
     }
 
-
+    /**
+     * 移动端订单详情
+     *
+     * @param orderNo 订单编号
+     * @return OrderFrontDetailResponse
+     */
+    @Override
+    public ExpressOrderFrontDetailResponse frontDetail(String orderNo) {
+        User currentUser = userService.getInfo();
+        ExpressOrder order = orderService.getByOrderNo(orderNo);
+        if (order.getIsUserDel()  || !order.getUid().equals(currentUser.getId())) {
+            throw new CrmebException(OrderResultCode.ORDER_NOT_EXIST);
+        }
+        ExpressOrderFrontDetailResponse response = new ExpressOrderFrontDetailResponse();
+        BeanUtils.copyProperties(order, response);
+        if (!order.getPaid()) {
+            DateTime cancelTime = DateUtil.offset(order.getCreateTime(), DateField.MINUTE, crmebConfig.getOrderCancelTime());
+            response.setCancelTime(cancelTime.getTime());
+            // 返回订单过期时间 2025-02-12
+            if (redisUtil.exists(StrUtil.format(RedisConstants.ORDER_EXPIRE_TIME, order.getOrderNo()))) {
+                String expireTime = redisUtil.get(StrUtil.format(RedisConstants.ORDER_EXPIRE_TIME, order.getOrderNo()));
+                response.setExpirationTime(expireTime);
+            }
+        }
+        return response;
+    }
 }

+ 26 - 0
ydd_mer_java/crmeb-service/src/main/java/com/zbkj/service/ExpressOrderService.java

@@ -7,8 +7,21 @@ import com.zbkj.common.model.order.Order;
 import com.zbkj.common.request.OrderFrontListRequest;
 import com.zbkj.common.request.express.ExpressOrderFrontListRequest;
 
+import java.util.List;
+
 public interface ExpressOrderService extends IService<ExpressOrder> {
+    /**
+     * 根据订单编号获取订单
+     *
+     * @param orderNo 订单编号
+     */
+     ExpressOrder getByOrderNo(String orderNo);
+    /**
+     * 更新支付结果
+     * @param orderNo 订单编号
+     */
 
+    Boolean updatePaid(String orderNo);
     /**
      * 获取用户订单列表
      * @param userId 用户id
@@ -16,4 +29,17 @@ public interface ExpressOrderService extends IService<ExpressOrder> {
      * @return PageInfo
      */
     PageInfo<ExpressOrder> getUserOrderList(Integer userId, ExpressOrderFrontListRequest request);
+
+    /**
+     * 根据订单编号获取订单
+     * @param orderNo
+     * @return
+     */
+    List<ExpressOrder> getByPlatOrderNo(String orderNo);
+
+    /**
+     * 获取订单
+     * @param outTradeNo 商户系统内部的订单号
+     */
+    ExpressOrder getByOutTradeNo(String outTradeNo);
 }

+ 32 - 0
ydd_mer_java/crmeb-service/src/main/java/com/zbkj/service/service/ExpressPayService.java

@@ -0,0 +1,32 @@
+package com.zbkj.service.service;
+
+import com.zbkj.common.request.OrderPayRequest;
+import com.zbkj.common.request.WechatPaymentQueryRequest;
+import com.zbkj.common.response.CashierInfoResponse;
+import com.zbkj.common.response.OrderPayResultResponse;
+
+/**
+ * ExpressPayService 接口
+ *
+ */
+public interface ExpressPayService {
+    /**
+     * 订单支付
+     * @param orderPayRequest 订单支付参数
+     * @return OrderPayResultResponse
+     */
+    OrderPayResultResponse payment(OrderPayRequest orderPayRequest);
+
+    /**
+     * 查询支付结果
+     * @param orderNo
+     * @return
+     */
+    Boolean queryWechatPayResult(String orderNo);
+
+     /**
+     * 查询微信支付结果
+     */
+    Boolean queryWechatPaymentResult(WechatPaymentQueryRequest request);
+
+}

+ 7 - 0
ydd_mer_java/crmeb-service/src/main/java/com/zbkj/service/service/PayCallbackService.java

@@ -23,6 +23,13 @@ public interface PayCallbackService {
     String wechatPayCallback(String xmlInfo);
 
     /**
+     * 快递微信支付回调
+     * @param xmlInfo 微信回调json
+     * @return String
+     */
+    String wechatExpPayCallback(String xmlInfo);
+
+    /**
      * 支付宝支付回调
      */
     String aliPayCallback(HttpServletRequest request);

+ 55 - 3
ydd_mer_java/crmeb-service/src/main/java/com/zbkj/service/service/impl/ExpressOrderServiceImpl.java

@@ -1,19 +1,23 @@
 package com.zbkj.service.service.impl;
 
+import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.URLUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.github.pagehelper.Page;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import com.zbkj.common.constants.OrderConstants;
+import com.zbkj.common.exception.CrmebException;
 import com.zbkj.common.model.express.ExpressOrder;
 import com.zbkj.common.model.order.Order;
 import com.zbkj.common.page.CommonPage;
 import com.zbkj.common.request.express.ExpressOrderFrontListRequest;
+import com.zbkj.common.result.OrderResultCode;
 import com.zbkj.service.ExpressOrderService;
 import com.zbkj.service.dao.ExpressOrderDao;
 import org.slf4j.Logger;
@@ -30,6 +34,33 @@ public class ExpressOrderServiceImpl extends ServiceImpl<ExpressOrderDao, Expres
     @Resource
     private ExpressOrderDao  dao;
     private static final Logger logger = LoggerFactory.getLogger(ExpressOrderServiceImpl.class);
+    /**
+     * 根据订单编号获取订单
+     *
+     * @param orderNo 订单编号
+     */
+    @Override
+    public ExpressOrder getByOrderNo(String orderNo) {
+        LambdaQueryWrapper<ExpressOrder> lqw = Wrappers.lambdaQuery();
+        lqw.eq(ExpressOrder::getOrderNo, orderNo);
+        lqw.last(" limit 1");
+        ExpressOrder order = dao.selectOne(lqw);
+        if (ObjectUtil.isNull(order)) {
+            throw new CrmebException(OrderResultCode.ORDER_NOT_EXIST);
+        }
+        return order;
+    }
+
+    @Override
+    public Boolean updatePaid(String orderNo) {
+        LambdaUpdateWrapper<ExpressOrder> lqw = new LambdaUpdateWrapper<>();
+        lqw.set(ExpressOrder::getPaid, true);
+        lqw.set(ExpressOrder::getPayTime, DateUtil.date());
+        lqw.set(ExpressOrder::getStatus, OrderConstants.ORDER_STATUS_WAIT_SHIPPING);
+        lqw.eq(ExpressOrder::getOrderNo, orderNo);
+        lqw.eq(ExpressOrder::getPaid, false);
+        return update(lqw);
+    }
 
     @Override
     public PageInfo<ExpressOrder> getUserOrderList(Integer userId, ExpressOrderFrontListRequest request) {
@@ -40,9 +71,6 @@ public class ExpressOrderServiceImpl extends ServiceImpl<ExpressOrderDao, Expres
             if (request.getStatus() >= 0) {
                 if (request.getStatus() == 1) {
                     lqw.in(ExpressOrder::getStatus, OrderConstants.ORDER_STATUS_WAIT_SHIPPING, OrderConstants.ORDER_STATUS_PART_SHIPPING);
-                } else if(request.getStatus() == 3) {
-                    lqw.eq(ExpressOrder::getStatus, 3);
-
                 } else {
                     lqw.eq(ExpressOrder::getStatus, request.getStatus());
                 }
@@ -61,4 +89,28 @@ public class ExpressOrderServiceImpl extends ServiceImpl<ExpressOrderDao, Expres
         List<ExpressOrder> orderList = dao.findFrontList(searchMap);
         return CommonPage.copyPageInfo(page, orderList);
     }
+    /**
+     * 通过原始单号获取订单列表
+     *
+     * @param orderNo 原始单号
+     * @return 订单列表
+     */
+    @Override
+    public List<ExpressOrder> getByPlatOrderNo(String orderNo) {
+        LambdaQueryWrapper<ExpressOrder> lqw = Wrappers.lambdaQuery();
+        lqw.eq(ExpressOrder::getPlatOrderNo, orderNo);
+        return dao.selectList(lqw);
+    }
+
+    @Override
+    public ExpressOrder getByOutTradeNo(String outTradeNo) {
+        LambdaQueryWrapper<ExpressOrder> lqw = Wrappers.lambdaQuery();
+        lqw.eq(ExpressOrder::getOutTradeNo, outTradeNo);
+        lqw.last(" limit 1");
+        ExpressOrder order = dao.selectOne(lqw);
+        if (ObjectUtil.isNull(order)) {
+            throw new CrmebException(OrderResultCode.ORDER_NOT_EXIST);
+        }
+        return order;
+    }
 }

+ 510 - 0
ydd_mer_java/crmeb-service/src/main/java/com/zbkj/service/service/impl/ExpressPayServiceImpl.java

@@ -0,0 +1,510 @@
+package com.zbkj.service.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUnit;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.alipay.api.AlipayApiException;
+import com.alipay.api.AlipayClient;
+import com.alipay.api.DefaultAlipayClient;
+import com.alipay.api.domain.AlipayTradeQueryModel;
+import com.alipay.api.request.AlipayTradeQueryRequest;
+import com.alipay.api.response.AlipayTradeQueryResponse;
+import com.zbkj.common.config.CrmebConfig;
+import com.zbkj.common.constants.*;
+import com.zbkj.common.exception.CrmebException;
+import com.zbkj.common.model.admin.SystemAdmin;
+import com.zbkj.common.model.alipay.AliPayInfo;
+import com.zbkj.common.model.bill.Bill;
+import com.zbkj.common.model.bill.MerchantBill;
+import com.zbkj.common.model.coupon.CouponUser;
+import com.zbkj.common.model.express.ExpressOrder;
+import com.zbkj.common.model.member.PaidMemberOrder;
+import com.zbkj.common.model.merchant.Merchant;
+import com.zbkj.common.model.merchant.MerchantBalanceRecord;
+import com.zbkj.common.model.order.*;
+import com.zbkj.common.model.product.ProductCoupon;
+import com.zbkj.common.model.system.SystemNotification;
+import com.zbkj.common.model.user.*;
+import com.zbkj.common.model.wechat.WechatPayInfo;
+import com.zbkj.common.model.wechat.video.PayComponentProduct;
+import com.zbkj.common.request.OrderPayRequest;
+import com.zbkj.common.request.WechatPaymentQueryRequest;
+import com.zbkj.common.response.CashierInfoResponse;
+import com.zbkj.common.response.OrderPayResultResponse;
+import com.zbkj.common.response.PayConfigResponse;
+import com.zbkj.common.result.CommonResultCode;
+import com.zbkj.common.result.MemberResultCode;
+import com.zbkj.common.result.OrderResultCode;
+import com.zbkj.common.result.UserResultCode;
+import com.zbkj.common.utils.*;
+import com.zbkj.common.vo.*;
+import com.zbkj.common.vo.wxvedioshop.ShopOrderAddResultVo;
+import com.zbkj.common.vo.wxvedioshop.order.*;
+import com.zbkj.service.ExpressOrderService;
+import com.zbkj.service.service.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.net.URLDecoder;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static com.zbkj.common.constants.OrderConstants.ORDER_SHIPPING_TYPE_EXPRESS;
+
+/**
+ * PayServiceImpl 接口实现
+ * +----------------------------------------------------------------------
+ * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+ * +----------------------------------------------------------------------
+ * | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
+ * +----------------------------------------------------------------------
+ * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+ * +----------------------------------------------------------------------
+ * | Author: CRMEB Team <admin@crmeb.com>
+ * +----------------------------------------------------------------------
+ */
+@Service
+public class ExpressPayServiceImpl implements ExpressPayService {
+
+    private static final Logger logger = LoggerFactory.getLogger(ExpressPayServiceImpl.class);
+
+    @Autowired
+    private SystemConfigService systemConfigService;
+
+    @Autowired
+    private UserService userService;
+    @Autowired
+    private TransactionTemplate transactionTemplate;
+    @Autowired
+    private UserTokenService userTokenService;
+    @Autowired
+    private WechatService wechatService;
+    @Autowired
+    private WechatPayInfoService wechatPayInfoService;
+
+    @Autowired
+    private UserBalanceRecordService userBalanceRecordService;
+
+    @Autowired
+    private CrmebConfig crmebConfig;
+
+    @Autowired
+    private RedisUtil redisUtil;
+
+    @Autowired
+    private ExpressOrderService orderService;
+
+    /**
+     * 订单支付
+     *
+     * @param orderPayRequest 订单支付参数
+     * @return OrderPayResultResponse
+     */
+    @Override
+    public OrderPayResultResponse payment(OrderPayRequest orderPayRequest) {
+        ExpressOrder order = orderService.getByOrderNo(orderPayRequest.getOrderNo());
+        if (order.getCancelStatus() > OrderConstants.ORDER_CANCEL_STATUS_NORMAL) {
+            throw new CrmebException(OrderResultCode.ORDER_CANCEL);
+        }
+        if (order.getPaid()) {
+            throw new CrmebException(OrderResultCode.ORDER_PAID);
+        }
+        if (order.getStatus() > OrderConstants.ORDER_STATUS_WAIT_PAY) {
+            throw new CrmebException(OrderResultCode.ORDER_STATUS_ABNORMAL);
+        }
+        User user = userService.getInfo();
+        // 根据支付类型进行校验,更换支付类型
+        order.setPayType(orderPayRequest.getPayType());
+        order.setPayChannel(orderPayRequest.getPayChannel());
+        // 获取过期时间 增加redis缓存的判断 2025-02-12
+        DateTime cancelTime;
+        if (redisUtil.exists(redisUtil.get(StrUtil.format(RedisConstants.ORDER_EXPIRE_TIME, order.getOrderNo())))) {
+            String expireTime = redisUtil.get(StrUtil.format(RedisConstants.ORDER_EXPIRE_TIME, order.getOrderNo()));
+            cancelTime = DateUtil.parseDateTime(expireTime);
+        } else {
+            cancelTime = DateUtil.offset(order.getCreateTime(), DateField.MINUTE, crmebConfig.getOrderCancelTime());
+        }
+        long between = DateUtil.between(cancelTime, DateUtil.date(), DateUnit.SECOND, false);
+        if (between > 0) {
+            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "订单已过期");
+        }
+
+        // 余额支付
+        if (orderPayRequest.getPayType().equals(PayConstants.PAY_TYPE_YUE)) {
+            if (user.getNowMoney().compareTo(order.getPayPrice()) < 0) {
+                throw new CrmebException(UserResultCode.USER_BALANCE_INSUFFICIENT);
+            }
+        }
+
+        OrderPayResultResponse response = new OrderPayResultResponse();
+        response.setOrderNo(order.getOrderNo());
+        response.setPayType(order.getPayType());
+        response.setPayChannel(order.getPayChannel());
+        if (order.getPayPrice().compareTo(BigDecimal.ZERO) <= 0) {
+                throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "支付金额不能低于等于0元");
+        }
+
+        // 余额支付
+        if (order.getPayType().equals(PayConstants.PAY_TYPE_YUE) || order.getPayPrice().compareTo(BigDecimal.ZERO) <= 0) {
+            Boolean yueBoolean = yuePay(order, user);
+            response.setStatus(yueBoolean);
+            return response;
+        }
+        // 微信支付,调用微信预下单,返回拉起微信支付需要的信息
+        if (order.getPayType().equals(PayConstants.PAY_TYPE_WE_CHAT)) {
+            WxPayJsResultVo vo = wechatPayment(order);
+            orderService.updateById(order);
+            response.setStatus(true);
+            response.setJsConfig(vo);
+            return response;
+        }
+        response.setStatus(false);
+        return response;
+    }
+
+    /**
+     * 查询支付结果
+     *
+     * @param orderNo 订单编号
+     */
+    @Override
+    public Boolean queryWechatPayResult(String orderNo) {
+        ExpressOrder order = orderService.getByOrderNo(orderNo);
+        if (ObjectUtil.isNull(order)) {
+            throw new CrmebException(OrderResultCode.ORDER_NOT_EXIST);
+        }
+        if (order.getCancelStatus() > OrderConstants.ORDER_CANCEL_STATUS_NORMAL) {
+            throw new CrmebException(OrderResultCode.ORDER_CANCEL);
+        }
+        if (!order.getPayType().equals(PayConstants.PAY_TYPE_WE_CHAT)) {
+            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "不是微信支付类型订单");
+        }
+        if (order.getPaid()) {
+            return Boolean.TRUE;
+        }
+        WechatPayInfo wechatPayInfo = wechatPayInfoService.getByNo(order.getOutTradeNo());
+        if (ObjectUtil.isNull(wechatPayInfo)) {
+            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "未找到对应微信订单");
+        }
+        Map<String, String> payVo = getWechatQueryPayVo(order.getOutTradeNo(), order.getPayChannel());
+        MyRecord myRecord = wechatService.payOrderQuery(payVo);
+        if (myRecord.getInt("payStatus") < 1) {
+            return Boolean.FALSE;
+        }
+        wechatPayInfo.setIsSubscribe(myRecord.getStr("is_subscribe"));
+        wechatPayInfo.setTradeState(myRecord.getStr("trade_state"));
+        wechatPayInfo.setBankType(myRecord.getStr("bank_type"));
+        wechatPayInfo.setCashFee(myRecord.getInt("cash_fee"));
+        wechatPayInfo.setCouponFee(myRecord.getInt("coupon_fee"));
+        wechatPayInfo.setTransactionId(myRecord.getStr("transaction_id"));
+        wechatPayInfo.setTimeEnd(myRecord.getStr("time_end"));
+        wechatPayInfo.setTradeStateDesc(myRecord.getStr("trade_state_desc"));
+        Boolean updatePaid = transactionTemplate.execute(e -> {
+            orderService.updatePaid(orderNo);
+            wechatPayInfoService.updateById(wechatPayInfo);
+            return Boolean.TRUE;
+        });
+        if (!updatePaid) {
+            throw new CrmebException("支付成功更新订单失败");
+        }
+        // 添加支付成功task
+        redisUtil.lPush(TaskConstants.ORDER_TASK_PAY_SUCCESS_AFTER, orderNo);
+        return Boolean.TRUE;
+    }
+
+
+    /**
+     * 查询微信支付结果
+     */
+    @Override
+    public Boolean queryWechatPaymentResult(WechatPaymentQueryRequest request) {
+        if (request.getOrderType().equals(PayConstants.PAY_SERVICE_TYPE_ORDER)) {
+            return queryWechatPayResult(request.getOrderNo());
+        }
+        throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "不是微信支付类型订单");
+    }
+    private Map<String, String> getWechatQueryPayVo(String outTradeNo, String payChannel) {
+        // 获取appid、mch_id
+        // 微信签名key
+        String appId = "";
+        String mchId = "";
+        String signKey = "";
+        String tempPayChannel = payChannel;
+        if (tempPayChannel.equals(PayConstants.PAY_CHANNEL_H5) || tempPayChannel.equals(PayConstants.PAY_CHANNEL_WECHAT_NATIVE)) {
+            String source = systemConfigService.getValueByKey(SysConfigConstants.WECHAT_PAY_SOURCE_H5_PC);
+            if (StrUtil.isNotBlank(source) && source.equals(PayConstants.WECHAT_PAY_SOURCE_MINI)) {
+                tempPayChannel = PayConstants.PAY_CHANNEL_WECHAT_MINI;
+            } else {
+                tempPayChannel = PayConstants.PAY_CHANNEL_WECHAT_PUBLIC;
+            }
+        }
+        switch (tempPayChannel) {
+            case PayConstants.PAY_CHANNEL_WECHAT_PUBLIC:
+                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PUBLIC_APPID);
+                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_PUBLIC_MCHID);
+                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_PUBLIC_KEY);
+                break;
+            case PayConstants.PAY_CHANNEL_WECHAT_MINI:
+            case PayConstants.PAY_CHANNEL_WECHAT_MINI_VIDEO:
+                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_MINI_APPID);
+                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_MINI_MCHID);
+                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_MINI_KEY);
+                break;
+            case PayConstants.PAY_CHANNEL_WECHAT_APP_IOS:
+            case PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID:
+                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_APP_APPID);
+                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_APP_MCHID);
+                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_APP_KEY);
+                break;
+        }
+
+        // 生成查询订单对象
+        Map<String, String> map = CollUtil.newHashMap();
+        map.put("appid", appId);
+        map.put("mch_id", mchId);
+        map.put("out_trade_no", outTradeNo);
+        map.put("nonce_str", WxPayUtil.getNonceStr());
+        map.put("sign_type", PayConstants.WX_PAY_SIGN_TYPE_MD5);
+        map.put("sign", WxPayUtil.getSign(map, signKey));
+        return map;
+    }
+
+    /**
+     * 微信支付
+     *
+     * @param order 订单
+     * @return WxPayJsResultVo
+     */
+    private WxPayJsResultVo wechatPayment(ExpressOrder order) {
+        // 预下单
+        Map<String, String> unifiedorder = unifiedorder(order);
+        WxPayJsResultVo vo = new WxPayJsResultVo();
+        vo.setAppId(unifiedorder.get("appId"));
+        vo.setNonceStr(unifiedorder.get("nonceStr"));
+        vo.setPackages(unifiedorder.get("package"));
+        vo.setSignType(unifiedorder.get("signType"));
+        vo.setTimeStamp(unifiedorder.get("timeStamp"));
+        vo.setPaySign(unifiedorder.get("paySign"));
+        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_H5)) {
+            vo.setMwebUrl(unifiedorder.get("mweb_url"));
+        }
+        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_IOS) ||
+                order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID)) {// App
+            vo.setPartnerid(unifiedorder.get("partnerid"));
+        }
+        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_NATIVE)) {
+            vo.setMwebUrl(unifiedorder.get("code_url"));
+        }
+        // 更新商户订单号
+        order.setOutTradeNo(unifiedorder.get("outTradeNo"));
+        return vo;
+    }
+
+    /**
+     * 余额支付
+     *
+     * @param order 订单
+     * @return Boolean Boolean
+     */
+    private Boolean yuePay(ExpressOrder order, User user) {
+        // 用户余额扣除
+        Boolean execute = transactionTemplate.execute(e -> {
+            Boolean update = Boolean.TRUE;
+            // 订单修改
+            order.setPaid(true);
+            order.setPayTime(DateUtil.date());
+            order.setStatus(OrderConstants.ORDER_STATUS_WAIT_SHIPPING);
+            order.setPayType(PayConstants.PAY_TYPE_YUE);
+            order.setPayChannel(PayConstants.PAY_CHANNEL_YUE);
+            orderService.updateById(order);
+            // 这里只扣除金额,账单记录在task中处理
+            if (order.getPayPrice().compareTo(BigDecimal.ZERO) > 0) {
+                update = userService.updateNowMoney(order.getUid(), order.getPayPrice(), Constants.OPERATION_TYPE_SUBTRACT);
+                if (!update) {
+                    logger.error("余额支付,扣除用户余额失败,orderNo = {}", order.getOrderNo());
+                    e.setRollbackOnly();
+                    return update;
+                }
+                // 用户余额记录
+                UserBalanceRecord userBalanceRecord = new UserBalanceRecord();
+                userBalanceRecord.setUid(user.getId());
+                userBalanceRecord.setLinkId(order.getOrderNo());
+                userBalanceRecord.setLinkType(BalanceRecordConstants.BALANCE_RECORD_LINK_TYPE_ORDER);
+                userBalanceRecord.setType(BalanceRecordConstants.BALANCE_RECORD_TYPE_SUB);
+                userBalanceRecord.setAmount(order.getPayPrice());
+                userBalanceRecord.setBalance(user.getNowMoney().subtract(order.getPayPrice()));
+                userBalanceRecord.setRemark(StrUtil.format(BalanceRecordConstants.BALANCE_RECORD_REMARK_ORDER, order.getPayPrice()));
+                userBalanceRecordService.save(userBalanceRecord);
+            }
+            return update;
+        });
+        if (!execute) throw new CrmebException("余额支付订单失败");
+        return true;
+    }
+
+    /**
+     * 预下单
+     *
+     * @param order 订单
+     * @return 预下单返回对象
+     */
+    private Map<String, String> unifiedorder(ExpressOrder order) {
+        // 获取用户openId
+        // 根据订单支付类型来判断获取公众号openId还是小程序openId
+        UserToken userToken = new UserToken();
+        userToken.setToken("");
+        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_PUBLIC)) {// 公众号
+            userToken = userTokenService.getTokenByUserId(order.getUid(), UserConstants.USER_TOKEN_TYPE_WECHAT);
+        }
+        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_MINI)
+                || order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_MINI_VIDEO)) {// 小程序
+            userToken = userTokenService.getTokenByUserId(order.getUid(), UserConstants.USER_TOKEN_TYPE_ROUTINE);
+        }
+
+        // 获取appid、mch_id、微信签名key
+        String appId = "";
+        String mchId = "";
+        String signKey = "";
+        // 从config表中获取H5/PC支付使用的是公众号还是小程序的
+        String payChannel = order.getPayChannel();
+        if (payChannel.equals(PayConstants.PAY_CHANNEL_H5) || payChannel.equals(PayConstants.PAY_CHANNEL_WECHAT_NATIVE)) {
+            String source = systemConfigService.getValueByKey(SysConfigConstants.WECHAT_PAY_SOURCE_H5_PC);
+            if (StrUtil.isNotBlank(source) && source.equals(PayConstants.WECHAT_PAY_SOURCE_MINI)) {
+                payChannel = PayConstants.PAY_CHANNEL_WECHAT_MINI;
+            } else {
+                payChannel = PayConstants.PAY_CHANNEL_WECHAT_PUBLIC;
+            }
+        }
+        switch (payChannel) {
+            case PayConstants.PAY_CHANNEL_WECHAT_PUBLIC:
+                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PUBLIC_APPID);
+                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_PUBLIC_MCHID);
+                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_PUBLIC_KEY);
+                break;
+            case PayConstants.PAY_CHANNEL_WECHAT_MINI:
+            case PayConstants.PAY_CHANNEL_WECHAT_MINI_VIDEO:
+                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_MINI_APPID);
+                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_MINI_MCHID);
+                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_MINI_KEY);
+                break;
+            case PayConstants.PAY_CHANNEL_WECHAT_APP_IOS:
+            case PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID:
+                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_APP_APPID);
+                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_APP_MCHID);
+                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_APP_KEY);
+                break;
+        }
+        // 获取微信预下单对象
+        CreateOrderRequestVo unifiedorderVo = getUnifiedorderVo(order, userToken.getToken(), appId, mchId, signKey);
+
+        // 预下单(统一下单)
+        CreateOrderResponseVo responseVo = wechatService.payUnifiedorder(unifiedorderVo);
+        // 组装前端预下单参数
+        Map<String, String> map = new HashMap<>();
+        map.put("appId", unifiedorderVo.getAppid());
+        map.put("nonceStr", unifiedorderVo.getAppid());
+        map.put("package", "prepay_id=".concat(responseVo.getPrepayId()));
+        map.put("signType", unifiedorderVo.getSign_type());
+        Long currentTimestamp = WxPayUtil.getCurrentTimestamp();
+        map.put("timeStamp", Long.toString(currentTimestamp));
+        String paySign = WxPayUtil.getSign(map, signKey);
+        map.put("paySign", paySign);
+        map.put("prepayId", responseVo.getPrepayId());
+        map.put("prepayTime", CrmebDateUtil.nowDateTimeStr());
+        map.put("outTradeNo", unifiedorderVo.getOut_trade_no());
+        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_H5)) {
+            map.put("mweb_url", responseVo.getMWebUrl());
+        }
+        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_IOS) ||
+                order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID)) {// App
+            map.put("partnerid", mchId);
+            map.put("package", responseVo.getPrepayId());
+            Map<String, Object> appMap = new HashMap<>();
+            appMap.put("appid", unifiedorderVo.getAppid());
+            appMap.put("partnerid", mchId);
+            appMap.put("prepayid", responseVo.getPrepayId());
+            appMap.put("package", "Sign=WXPay");
+            appMap.put("noncestr", unifiedorderVo.getAppid());
+            appMap.put("timestamp", currentTimestamp);
+            String sign = WxPayUtil.getSignObject(appMap, signKey);
+            map.put("paySign", sign);
+        }
+        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_NATIVE)) {
+            map.put("code_url", responseVo.getCodeUrl());
+        }
+        return map;
+    }
+
+    /**
+     * 获取微信预下单对象
+     *
+     * @return 微信预下单对象
+     */
+    private CreateOrderRequestVo getUnifiedorderVo(ExpressOrder order, String openid, String appId, String mchId, String signKey) {
+        // 获取域名
+        String domain = systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_SITE_URL);
+        String apiDomain = systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_API_URL);
+
+        AttachVo attachVo = new AttachVo(PayConstants.PAY_SERVICE_TYPE_ORDER, order.getUid());
+
+        CreateOrderRequestVo vo = new CreateOrderRequestVo();
+        vo.setAppid(appId);
+        vo.setMch_id(mchId);
+        vo.setNonce_str(WxPayUtil.getNonceStr());
+        vo.setSign_type(PayConstants.WX_PAY_SIGN_TYPE_MD5);
+        String siteName = systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_SITE_NAME);
+        // 因商品名称在微信侧超长更换为网站名称
+        vo.setBody(siteName);
+        vo.setAttach(JSONObject.toJSONString(attachVo));
+        vo.setOut_trade_no(CrmebUtil.getOrderNo(OrderConstants.ORDER_PREFIX_WECHAT));
+        // 订单中使用的是BigDecimal,这里要转为Integer类型
+        vo.setTotal_fee(order.getPayPrice().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue());
+        vo.setSpbill_create_ip(RequestUtil.getClientIp());
+        vo.setNotify_url(apiDomain + PayConstants.WX_EXP_PAY_NOTIFY_API_URI);
+        switch (order.getPayChannel()) {
+            case PayConstants.PAY_CHANNEL_H5:
+                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_H5);
+                vo.setOpenid(null);
+                break;
+            case PayConstants.PAY_CHANNEL_WECHAT_APP_IOS:
+            case PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID:
+                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_APP);
+                vo.setOpenid(null);
+                break;
+            case PayConstants.PAY_CHANNEL_WECHAT_NATIVE:
+                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_NATIVE);
+                vo.setProduct_id(order.getOrderNo());
+                vo.setOpenid(null);
+                break;
+            default:
+                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_JS);
+                vo.setOpenid(openid);
+        }
+        CreateOrderH5SceneInfoVo createOrderH5SceneInfoVo = new CreateOrderH5SceneInfoVo(
+                new CreateOrderH5SceneInfoDetailVo(
+                        domain,
+                        systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_SITE_NAME)
+                )
+        );
+        vo.setScene_info(JSONObject.toJSONString(createOrderH5SceneInfoVo));
+
+        vo.setTime_start(DateUtil.date().toString(DateConstants.DATE_TIME_FORMAT_NUM));
+        DateTime cancelTime = DateUtil.offset(order.getCreateTime(), DateField.MINUTE, crmebConfig.getOrderCancelTime());
+        String cancelStr = cancelTime.toString(DateConstants.DATE_TIME_FORMAT_NUM);
+        vo.setTime_expire(cancelStr);
+        String sign = WxPayUtil.getSign(vo, signKey);
+        vo.setSign(sign);
+        return vo;
+    }
+}
+

+ 138 - 0
ydd_mer_java/crmeb-service/src/main/java/com/zbkj/service/service/impl/PayCallbackServiceImpl.java

@@ -12,6 +12,7 @@ import com.alipay.api.internal.util.AlipaySignature;
 import com.zbkj.common.constants.*;
 import com.zbkj.common.exception.CrmebException;
 import com.zbkj.common.model.alipay.AliPayCallback;
+import com.zbkj.common.model.express.ExpressOrder;
 import com.zbkj.common.model.member.PaidMemberOrder;
 import com.zbkj.common.model.order.Order;
 import com.zbkj.common.model.order.RechargeOrder;
@@ -25,6 +26,7 @@ import com.zbkj.common.utils.WxPayUtil;
 import com.zbkj.common.vo.AttachVo;
 import com.zbkj.common.vo.MyRecord;
 import com.zbkj.common.vo.WechatPayCallbackVo;
+import com.zbkj.service.ExpressOrderService;
 import com.zbkj.service.service.*;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.slf4j.Logger;
@@ -64,6 +66,8 @@ public class PayCallbackServiceImpl implements PayCallbackService {
     @Autowired
     private OrderService orderService;
     @Autowired
+    private ExpressOrderService expressOrderService;
+    @Autowired
     private UserService userService;
     @Autowired
     private RedisUtil redisUtil;
@@ -353,6 +357,140 @@ public class PayCallbackServiceImpl implements PayCallbackService {
         return sb.toString();
     }
 
+    @Override
+    public String wechatExpPayCallback(String xmlInfo) {
+        StringBuffer sb = new StringBuffer();
+        sb.append("<xml>");
+        if (StrUtil.isBlank(xmlInfo)) {
+            sb.append("<return_code><![CDATA[FAIL]]></return_code>");
+            sb.append("<return_msg><![CDATA[xmlInfo is blank]]></return_msg>");
+            sb.append("</xml>");
+            logger.error("wechat callback error : " + sb);
+            return sb.toString();
+        }
+
+        try {
+            HashMap<String, Object> map = WxPayUtil.processResponseXml(xmlInfo);
+            // 通信是否成功
+            String returnCode = (String) map.get("return_code");
+            if (!returnCode.equals(Constants.SUCCESS)) {
+                sb.append("<return_code><![CDATA[SUCCESS]]></return_code>");
+                sb.append("<return_msg><![CDATA[OK]]></return_msg>");
+                sb.append("</xml>");
+                logger.error("wechat callback error : wx pay return code is fail returnMsg : " + map.get("return_msg"));
+                return sb.toString();
+            }
+            // 交易是否成功
+            String resultCode = (String) map.get("result_code");
+            if (!resultCode.equals(Constants.SUCCESS)) {
+                sb.append("<return_code><![CDATA[SUCCESS]]></return_code>");
+                sb.append("<return_msg><![CDATA[OK]]></return_msg>");
+                sb.append("</xml>");
+                logger.error("wechat callback error : wx pay result code is fail");
+                return sb.toString();
+            }
+
+            //解析xml
+            WechatPayCallbackVo callbackVo = CrmebUtil.mapToObj(map, WechatPayCallbackVo.class);
+            AttachVo attachVo = JSONObject.toJavaObject(JSONObject.parseObject(callbackVo.getAttach()), AttachVo.class);
+
+            //判断openid
+            User user = userService.getById(attachVo.getUserId());
+            if (ObjectUtil.isNull(user)) {
+                //用户信息错误
+                throw new CrmebException("用户信息错误!");
+            }
+
+            //根据类型判断是订单或者充值
+            if (!PayConstants.PAY_SERVICE_TYPE_ORDER.equals(attachVo.getType())) {
+                logger.error("wechat pay err : 未知的支付类型==》" + callbackVo.getOutTradeNo());
+                throw new CrmebException("未知的支付类型!");
+            }
+            // 订单
+            if (PayConstants.PAY_SERVICE_TYPE_ORDER.equals(attachVo.getType())) {
+                ExpressOrder order = expressOrderService.getByOutTradeNo(callbackVo.getOutTradeNo());
+                if (ObjectUtil.isNull(order) || !order.getUid().equals(attachVo.getUserId())) {
+                    logger.error("wechat pay error : 订单信息不存在==》" + callbackVo.getOutTradeNo());
+                    throw new CrmebException("wechat pay error : 订单信息不存在==》" + callbackVo.getOutTradeNo());
+                }
+                if (order.getPaid()) {
+                    sb.append("<return_code><![CDATA[SUCCESS]]></return_code>");
+                    sb.append("<return_msg><![CDATA[OK]]></return_msg>");
+                    sb.append("</xml>");
+                    return sb.toString();
+                }
+
+                String signKey = "";
+                String payChannel = order.getPayChannel();
+                if (payChannel.equals(PayConstants.PAY_CHANNEL_H5) || payChannel.equals(PayConstants.PAY_CHANNEL_WECHAT_NATIVE)) {
+                    String source = systemConfigService.getValueByKey(SysConfigConstants.WECHAT_PAY_SOURCE_H5_PC);
+                    if (StrUtil.isNotBlank(source) && source.equals(PayConstants.WECHAT_PAY_SOURCE_MINI)) {
+                        payChannel = PayConstants.PAY_CHANNEL_WECHAT_MINI;
+                    } else {
+                        payChannel = PayConstants.PAY_CHANNEL_WECHAT_PUBLIC;
+                    }
+                }
+                switch (payChannel) {
+                    case PayConstants.PAY_CHANNEL_WECHAT_PUBLIC:
+                        signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_PUBLIC_KEY);
+                        break;
+                    case PayConstants.PAY_CHANNEL_WECHAT_MINI:
+                    case PayConstants.PAY_CHANNEL_WECHAT_MINI_VIDEO:
+                        signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_MINI_KEY);
+                        break;
+                    case PayConstants.PAY_CHANNEL_WECHAT_APP_IOS:
+                    case PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID:
+                        signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_APP_KEY);
+                        break;
+                }
+                Map<String, String> stringMap = WxPayUtil.xmlToMap(xmlInfo);
+                String sign = WxPayUtil.getSign(stringMap, signKey);
+                if (!sign.equals(stringMap.get(PayConstants.FIELD_SIGN))) {
+                    logger.error("wechat pay error : 微信订单回调验签失败 ==> {}", xmlInfo);
+                    throw new CrmebException(StrUtil.format("wechat pay error : 微信订单回调验签失败 ==> {}", xmlInfo));
+                }
+
+                WechatPayInfo wechatPayInfo = wechatPayInfoService.getByNo(order.getOutTradeNo());
+                if (ObjectUtil.isNull(wechatPayInfo)) {
+                    logger.error("wechat pay error : 微信订单信息不存在==》" + callbackVo.getOutTradeNo());
+                    throw new CrmebException("wechat pay error : 微信订单信息不存在==》" + callbackVo.getOutTradeNo());
+                }
+                wechatPayInfo.setIsSubscribe(callbackVo.getIsSubscribe());
+                wechatPayInfo.setBankType(callbackVo.getBankType());
+                wechatPayInfo.setCashFee(callbackVo.getCashFee());
+                wechatPayInfo.setCouponFee(callbackVo.getCouponFee());
+                wechatPayInfo.setTransactionId(callbackVo.getTransactionId());
+                wechatPayInfo.setTimeEnd(callbackVo.getTimeEnd());
+
+                // 添加支付成功redis队列
+                Boolean execute = transactionTemplate.execute(e -> {
+                    order.setPaid(true);
+                    order.setPayTime(CrmebDateUtil.nowDateTime());
+                    order.setStatus(OrderConstants.ORDER_STATUS_WAIT_SHIPPING);
+                    expressOrderService.updateById(order);
+                    wechatPayInfoService.updateById(wechatPayInfo);
+                    return Boolean.TRUE;
+                });
+                if (!execute) {
+                    logger.error("wechat pay error : 订单更新失败==》" + callbackVo.getOutTradeNo());
+                    sb.append("<return_code><![CDATA[SUCCESS]]></return_code>");
+                    sb.append("<return_msg><![CDATA[OK]]></return_msg>");
+                    sb.append("</xml>");
+                    return sb.toString();
+                }
+                redisUtil.lPush(TaskConstants.ORDER_TASK_PAY_SUCCESS_AFTER, order.getOrderNo());
+            }
+            sb.append("<return_code><![CDATA[SUCCESS]]></return_code>");
+            sb.append("<return_msg><![CDATA[OK]]></return_msg>");
+        } catch (Exception e) {
+            sb.append("<return_code><![CDATA[FAIL]]></return_code>");
+            sb.append("<return_msg><![CDATA[").append(e.getMessage()).append("]]></return_msg>");
+            logger.error("wechat pay error : 业务异常==》" + e.getMessage());
+        }
+        sb.append("</xml>");
+        return sb.toString();
+    }
+
     /**
      * 支付宝支付回调
      */

+ 5 - 1
ydd_mer_java/crmeb-service/src/main/resources/mapper/express/ExpressOrderMapper.xml

@@ -26,7 +26,11 @@
         <if test="keywords != null and keywords !='' ">
             and (order_no like CONCAT('%',#{keywords},'%')
                 or
-                order_no in (select order_no from eb_express_order_detail where express_info like CONCAT('%',#{keywords},'%')))
+                order_no in (select order_no from eb_express_order_detail where (pick_up_code like CONCAT('%',#{keywords},'%')
+                    or express_no like CONCAT('%',#{keywords},'%')
+                    or express_company like CONCAT('%',#{keywords},'%')
+                    or post_name like CONCAT('%',#{keywords},'%')
+                    )  ))
         </if>
         order by id desc
     </select>