Sfoglia il codice sorgente

微信扫码支付,订单发货

yjwang 1 settimana fa
parent
commit
4e0e9f412d
17 ha cambiato i file con 743 aggiunte e 167 eliminazioni
  1. 13 3
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreHealthOrderScrmController.java
  2. 42 0
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStorePaymentScrmController.java
  3. 18 18
      fs-service/src/main/java/com/fs/course/dto/FsOrderDeliveryNoteDTO.java
  4. 16 0
      fs-service/src/main/java/com/fs/course/dto/FsPaymentDeliveryNoteDTO.java
  5. 18 0
      fs-service/src/main/java/com/fs/course/dto/OrderOpenIdTransDTO.java
  6. 20 0
      fs-service/src/main/java/com/fs/course/vo/FsStorePaymentUsetVo.java
  7. 1 1
      fs-service/src/main/java/com/fs/hisStore/config/StoreConfig.java
  8. 7 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderScrmMapper.java
  9. 12 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStorePaymentScrmMapper.java
  10. 6 1
      fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderScrmService.java
  11. 7 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsStorePaymentScrmService.java
  12. 168 31
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
  13. 190 109
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStorePaymentScrmServiceImpl.java
  14. 38 0
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderCodeOpenIdVo.java
  15. 4 4
      fs-service/src/main/resources/application-dev-yjb.yml
  16. 159 0
      fs-service/src/main/resources/mapper/hisStore/FsStoreOrderScrmMapper.xml
  17. 24 0
      fs-service/src/main/resources/mapper/hisStore/FsStorePaymentScrmMapper.xml

+ 13 - 3
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreHealthOrderScrmController.java

@@ -333,10 +333,16 @@ public class FsStoreHealthOrderScrmController extends BaseController {
         return util.exportExcel(list, "订单明细数据");
     }
 
-    //订单发货批量导入
+    /**
+     * 订单发货批量导入
+     * @param file 导入文件
+     * @param miniAppId 发货程序
+     * @param shipmentType 发货类型 1线上 2线下自提
+     * @return R
+     * **/
     @Log(title = "发货同步导入", businessType = BusinessType.IMPORT)
     @PostMapping("/importDeliveryNoteExpress")
-    public R importDeliveryNoteExpress(@RequestParam("file") MultipartFile file) {
+    public R importDeliveryNoteExpress(@RequestParam("file") MultipartFile file,@RequestParam("miniAppId") String miniAppId,@RequestParam("shipmentType") Integer shipmentType) {
         // 1. 检查文件是否为空
         if (file.isEmpty()) {
             return R.error("上传的文件不能为空");
@@ -355,7 +361,10 @@ public class FsStoreHealthOrderScrmController extends BaseController {
         try {
             List<FsOrderDeliveryNoteDTO> dtoList = util.importExcel(file.getInputStream());
             if(!dtoList.isEmpty()){
-               return fsStoreOrderService.importDeliveryNoteExpress(dtoList);
+                if(dtoList.size() > 200){
+                    R.error("操作失败,导入数据不能大于200条!");
+                }
+                return fsStoreOrderService.importDeliveryNoteExpress(dtoList,miniAppId,shipmentType);
             }else {
                 R.error("操作失败,导入数据不能小于1条!");
             }
@@ -365,6 +374,7 @@ public class FsStoreHealthOrderScrmController extends BaseController {
         return R.ok();
     }
 
+
     @GetMapping("/importDeliveryNoteExpressTemplate")
     public AjaxResult importTemplate() {
         ExcelUtil<FsOrderDeliveryNoteDTO> util = new ExcelUtil<>(FsOrderDeliveryNoteDTO.class);

+ 42 - 0
fs-admin/src/main/java/com/fs/hisStore/controller/FsStorePaymentScrmController.java

@@ -17,6 +17,8 @@ import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.spring.SpringUtils;
 import com.fs.company.service.ICompanyService;
 import com.fs.config.cloud.CloudHostProper;
+import com.fs.course.dto.FsOrderDeliveryNoteDTO;
+import com.fs.course.dto.FsPaymentDeliveryNoteDTO;
 import com.fs.his.domain.FsHfpayConfig;
 import com.fs.his.mapper.FsHfpayConfigMapper;
 import com.fs.hisStore.domain.FsPayConfigScrm;
@@ -40,6 +42,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
 import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
@@ -74,6 +77,13 @@ public class FsStorePaymentScrmController extends BaseController
     private CloudHostProper cloudHostProper;
     @Autowired
     private ISysConfigService configService;
+
+    // 允许的文件扩展名
+    private static final String[] ALLOWED_EXCEL_EXTENSIONS = {".xlsx", ".xls"};
+
+    // 最大文件大小(5MB)
+    private static final long MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
+
     /**
      * 查询支付明细列表
      */
@@ -323,4 +333,36 @@ public class FsStorePaymentScrmController extends BaseController
     {
         return toAjax(fsStorePaymentService.deleteFsStorePaymentByIds(paymentIds));
     }
+
+    /**
+     * 一键发货
+     * @return R
+     * **/
+    @Log(title = "发货同步导入", businessType = BusinessType.IMPORT)
+    @PostMapping("/oneClickShipping")
+    public R oneClickShipping() {
+
+        try {
+            return fsStorePaymentService.oneClickShipping();
+        }catch (Exception e){
+            e.getStackTrace();
+        }
+        return R.ok();
+    }
+
+    @GetMapping("/importDeliveryNoteExpressTemplate")
+    public AjaxResult importTemplate() {
+        ExcelUtil<FsPaymentDeliveryNoteDTO> util = new ExcelUtil<>(FsPaymentDeliveryNoteDTO.class);
+        return util.importTemplateExcel("扫码订单发货模板");
+    }
+
+    // 检查文件是否为有效的Excel文件
+    private boolean isValidExcelFile(String fileName) {
+        for (String ext : ALLOWED_EXCEL_EXTENSIONS) {
+            if (fileName.toLowerCase().endsWith(ext)) {
+                return true;
+            }
+        }
+        return false;
+    }
 }

+ 18 - 18
fs-service/src/main/java/com/fs/course/dto/FsOrderDeliveryNoteDTO.java

@@ -21,26 +21,26 @@ public class FsOrderDeliveryNoteDTO {
 
     private String deliveryName;
 
-    @Excel(name = "快递单号(必填)",width = 20,sort = 3)
+    @Excel(name = "快递单号",width = 20,sort = 3)
     private String deliveryId;
 
-    @Excel(name = "物流状态(0:暂无信息、1:已揽收、2:在途中、3:签收、4:问题件)",width = 40,sort = 4)
-    private Integer deliveryStatus;
-
-    @Excel(name = "物流结算费用",width = 20,sort = 5)
-    private BigDecimal deliveryPayMoney;
-
-    @Excel(name = "物流跟踪状态(311:快递柜或驿站签收、304:派件异常后最终签收、301:正常签收、211:已放入快递柜或驿站、202:派件中、201:到达派件城市、401:发货无信息、412:快递柜或驿站超时未取、407:退货未签收)",width = 40,sort = 6)
-    private Integer deliveryType;
-
-    @Excel(name = "物流结算状态(1:已结算、2:冻结、3:解冻、4:退回运费、5.调账)",width = 20,sort = 7)
-    private Integer deliveryPayStatus;
-
-    @Excel(name = "快递账单日期",width = 20,sort = 8)
-    private String deliveryTime;
-
-    @Excel(name = "快递结算日期",width = 20,sort = 9)
-    private String deliveryPayTime;
+//    @Excel(name = "物流状态(0:暂无信息、1:已揽收、2:在途中、3:签收、4:问题件)",width = 40,sort = 4)
+//    private Integer deliveryStatus;
+//
+//    @Excel(name = "物流结算费用",width = 20,sort = 5)
+//    private BigDecimal deliveryPayMoney;
+//
+//    @Excel(name = "物流跟踪状态(311:快递柜或驿站签收、304:派件异常后最终签收、301:正常签收、211:已放入快递柜或驿站、202:派件中、201:到达派件城市、401:发货无信息、412:快递柜或驿站超时未取、407:退货未签收)",width = 40,sort = 6)
+//    private Integer deliveryType;
+//
+//    @Excel(name = "物流结算状态(1:已结算、2:冻结、3:解冻、4:退回运费、5.调账)",width = 20,sort = 7)
+//    private Integer deliveryPayStatus;
+//
+//    @Excel(name = "快递账单日期",width = 20,sort = 8)
+//    private String deliveryTime;
+//
+//    @Excel(name = "快递结算日期",width = 20,sort = 9)
+//    private String deliveryPayTime;
 
 //    /**
 //     * 发货状态

+ 16 - 0
fs-service/src/main/java/com/fs/course/dto/FsPaymentDeliveryNoteDTO.java

@@ -0,0 +1,16 @@
+package com.fs.course.dto;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+/**
+ * 订单发货下载模板
+ * **/
+@Data
+public class FsPaymentDeliveryNoteDTO {
+    /**
+     * 系统订单号
+     * **/
+    @Excel(name = "交易订单号(必填)",width = 20,sort = 1)
+    private String upOrderId;
+}

+ 18 - 0
fs-service/src/main/java/com/fs/course/dto/OrderOpenIdTransDTO.java

@@ -0,0 +1,18 @@
+package com.fs.course.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class OrderOpenIdTransDTO implements Serializable {
+    /**
+     * 用户微信openId
+     * **/
+    private String openId;
+
+    /**
+     * 交易单号
+     * **/
+    private String transactionId;
+}

+ 20 - 0
fs-service/src/main/java/com/fs/course/vo/FsStorePaymentUsetVo.java

@@ -0,0 +1,20 @@
+package com.fs.course.vo;
+
+import lombok.Data;
+
+@Data
+public class FsStorePaymentUsetVo {
+    //交易订单号
+    private String bankTransactionId;
+
+    //openId
+    private String openId;
+
+    //手机号
+    private String phone;
+
+    /**
+     * appId
+     * **/
+    private String appId;
+}

+ 1 - 1
fs-service/src/main/java/com/fs/hisStore/config/StoreConfig.java

@@ -24,5 +24,5 @@ public class StoreConfig implements Serializable {
     private Integer auditSwitch; // 订单审核开关
     private Integer createSalesOrderType; // 订单改价方式 1 商品改价 2总价改价
     private Boolean isBrushOrders;//是否开启刷单按钮
-
+    private Boolean isWeChatShipping;//是否开启微信发货
 }

+ 7 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderScrmMapper.java

@@ -1407,4 +1407,11 @@ public interface FsStoreOrderScrmMapper
      * @param orderIds 订单数组
      * **/
     void batchUpdateOrderStatusById(@Param("orderIds") List<Long> orderIds,@Param("status") String status);
+
+    /**
+     * 获取订单用户信息
+     * @param list 订单号
+     * @return lsit
+     * **/
+    List<FsStoreOrderCodeOpenIdVo> selectOrderCodeOpenIdInOrderCode(@Param("list") List<String> list);
 }

+ 12 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsStorePaymentScrmMapper.java

@@ -4,6 +4,7 @@ import java.util.List;
 import java.util.Map;
 
 import com.alibaba.fastjson.JSONObject;
+import com.fs.course.vo.FsStorePaymentUsetVo;
 import com.fs.his.domain.FsStorePayment;
 import com.fs.hisStore.domain.FsStorePaymentScrm;
 import com.fs.hisStore.param.FsStorePaymentParam;
@@ -355,4 +356,15 @@ public interface FsStorePaymentScrmMapper
 
     @Select("select * from fs_store_payment_scrm where pay_code=#{payCode}")
     List<FsStorePaymentScrm> selectFsStorePaymentByPaymentCodeList(String payCode);
+
+    /**
+     * 获取查询用户支付信息
+     * @return list
+     **/
+    List<FsStorePaymentUsetVo> getPaymentUsetInfoList();
+
+    /**
+     * 批量更新发货状态
+     * **/
+    void batchUpadte(@Param("list") List<String> list);
 }

+ 6 - 1
fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderScrmService.java

@@ -283,7 +283,12 @@ public interface IFsStoreOrderScrmService
      * 批量导入更新微信订单发货状态
      * @param dtoList 订单数据
      * **/
-    R importDeliveryNoteExpress(List<FsOrderDeliveryNoteDTO> dtoList);
+    /**
+     * 批量导入更新微信订单发货状态
+     * @param dtoList 订单数据
+     * @param appId 小程序ID
+     * **/
+    R importDeliveryNoteExpress(List<FsOrderDeliveryNoteDTO> dtoList,String appId,Integer shipmentType);
 
     R createOrderMultiStore(long userId, FsStoreOrderCreateParam param);
 

+ 7 - 0
fs-service/src/main/java/com/fs/hisStore/service/IFsStorePaymentScrmService.java

@@ -5,6 +5,8 @@ import java.util.Map;
 
 import com.alibaba.fastjson.JSONObject;
 import com.fs.common.core.domain.R;
+import com.fs.course.dto.FsOrderDeliveryNoteDTO;
+import com.fs.course.dto.FsPaymentDeliveryNoteDTO;
 import com.fs.hisStore.domain.FsStorePaymentScrm;
 import com.fs.hisStore.param.*;
 import com.fs.hisStore.vo.FsStorePaymentStatisticsVO;
@@ -120,4 +122,9 @@ public interface IFsStorePaymentScrmService
     List<FsStorePaymentScrm> selectFsStorePaymentByPaymentCode(String payCode);
 
     String payConfirmMultiStore(String payCode,String tradeNo,String bankTransactionId,String bankSerialNo);
+
+    /**
+     * 批量导入更新微信订单发货状态
+     * **/
+    R oneClickShipping();
 }

+ 168 - 31
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java

@@ -1,6 +1,7 @@
 package com.fs.hisStore.service.impl;
 
 import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
+import cn.binarywang.wx.miniapp.bean.shop.request.shipping.*;
 import cn.hutool.core.date.DateTime;
 import cn.binarywang.wx.miniapp.api.WxMaService;
 import cn.hutool.core.net.URLDecoder;
@@ -49,6 +50,7 @@ import com.fs.core.config.WxMaConfiguration;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.course.dto.FsOrderDeliveryNoteDTO;
+import com.fs.course.dto.OrderOpenIdTransDTO;
 import com.fs.erp.domain.*;
 import com.fs.erp.dto.*;
 import com.fs.erp.dto.df.*;
@@ -3837,50 +3839,120 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public R importDeliveryNoteExpress(List<FsOrderDeliveryNoteDTO> dtoList) {
+    public R importDeliveryNoteExpress(List<FsOrderDeliveryNoteDTO> dtoList, String appId,Integer shipmentType) {
         try {
-            // 检查必填字段
-            List<FsOrderDeliveryNoteDTO> list = new LinkedList<>();
+            StringBuilder builder = new StringBuilder();
+            //获取商城配置
+            String json = configService.selectConfigByKey("store.config");
+            StoreConfig config = JSONUtil.toBean(json, StoreConfig.class);
+
+            List<FsOrderDeliveryNoteDTO> successList = new ArrayList<>(dtoList.size());
+            //提前获取所有必要数据
             Map<String, String> expressDeliveryMap = buildExpressDeliveryMap();
-            for (FsOrderDeliveryNoteDTO dto : dtoList) {
+            //提取所有有效订单号
+            List<String> orderCodeList = new ArrayList<>(dtoList.size());
+            for (int i = 0; i < dtoList.size(); i++) {
+                FsOrderDeliveryNoteDTO dto = dtoList.get(i);
                 if (StringUtils.isEmpty(dto.getOrderNumber())) {
-                    return R.error("导入失败,系统订单不能为空!");
-                } else if (StringUtils.isEmpty(dto.getDeliveryId())) {
-                    return R.error("导入失败,快递单号不能为空!");
-                } else if (StringUtils.isEmpty(dto.getDeliverySn())) {
-                    return R.error("导入失败,快递公司编号不能为空!");
+                    builder.append("数据第").append(i + 2).append("行系统订单为空!").append(System.lineSeparator());
+                } else {
+                    orderCodeList.add(dto.getOrderNumber());
                 }
-                if (dto.getDeliveryStatus() == null) {
-                    dto.setDeliveryStatus(0);
+            }
+
+            //批量查询订单信息
+            if (orderCodeList.isEmpty()) {
+                return R.ok(builder.toString());
+            }
+            List<FsStoreOrderCodeOpenIdVo> orderCodeOpenIdVoList = fsStoreOrderMapper.selectOrderCodeOpenIdInOrderCode(orderCodeList);
+            Map<String, OrderOpenIdTransDTO> orderMap = new HashMap<>(orderCodeOpenIdVoList.size());
+            Map<String, List<FsStoreOrderCodeOpenIdVo>> orderDetailsMap = new HashMap<>(orderCodeOpenIdVoList.size());
+
+            for (FsStoreOrderCodeOpenIdVo vo : orderCodeOpenIdVoList) {
+                orderMap.computeIfAbsent(vo.getId(), k -> {
+                    OrderOpenIdTransDTO dto = new OrderOpenIdTransDTO();
+                    dto.setOpenId(vo.getOpenId());
+                    dto.setTransactionId(vo.getOutTransId());
+                    return dto;
+                });
+
+                orderDetailsMap
+                        .computeIfAbsent(vo.getId(), k -> new ArrayList<>())
+                        .add(vo);
+            }
+            final WxMaService wxService = WxMaConfiguration.getMaService(appId);
+            String uploadTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"))
+                    .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+
+            for (int i = 0; i < dtoList.size(); i++) {
+                FsOrderDeliveryNoteDTO dto = dtoList.get(i);
+                int rowNum = i + 2;
+                if (StringUtils.isEmpty(dto.getOrderNumber())) {
+                    continue;
                 }
-                if (ObjectUtil.isNotNull(dto.getDeliveryTime())) {
-                    dto.setDeliveryTime(parseCstToDateOnlyString(dto.getDeliveryTime()));
+//                if (StringUtils.isEmpty(dto.getDeliveryId())) {
+//                    builder.append("数据第").append(rowNum).append("行快递单号为空!")
+//                            .append(System.lineSeparator());
+//                    continue;
+//                }
+
+//                if (StringUtils.isEmpty(dto.getLogisticsCompany())) {
+//                    builder.append("数据第").append(rowNum).append("行快递公司编号为空!")
+//                            .append(System.lineSeparator());
+//                    continue;
+//                }
+//                if (dto.getDeliveryStatus() == null) {
+//                    dto.setDeliveryStatus(0);
+//                }
+//                if (ObjectUtil.isNotNull(dto.getDeliveryTime())) {
+//                    dto.setDeliveryTime(parseCstToDateOnlyString(dto.getDeliveryTime()));
+//                }
+//
+//                if (ObjectUtil.isNotNull(dto.getDeliveryPayTime()) &&
+//                        !dto.getDeliveryPayTime().isEmpty()) {
+//                    dto.setDeliveryPayTime(parseCstToDateOnlyString(dto.getDeliveryPayTime()));
+//                }
+                 //验证快递公司
+                String deliveryName = expressDeliveryMap.get(dto.getDeliverySn());
+                if (deliveryName == null) {
+                    builder.append("数据第").append(rowNum).append("行订单号为")
+                            .append(dto.getOrderNumber()).append("物流公司名称异常")
+                            .append(System.lineSeparator());
+                    continue;
                 }
-                if (ObjectUtil.isNotNull(dto.getDeliveryPayTime()) && !dto.getDeliveryPayTime().equals("")) {
-                    dto.setDeliveryPayTime(parseCstToDateOnlyString(dto.getDeliveryPayTime()));
+                dto.setDeliveryName(deliveryName);
+
+                // 检查订单是否存在
+                String orderNumber = dto.getOrderNumber();
+                OrderOpenIdTransDTO orderInfo = orderMap.get(orderNumber);
+                if (orderInfo == null) {
+                    builder.append("数据第").append(rowNum).append("行订单号")
+                            .append(orderNumber).append("不存在").append(System.lineSeparator());
+                    continue;
                 }
-                if (expressDeliveryMap.containsKey(dto.getDeliverySn())) {
-                    dto.setDeliveryName(expressDeliveryMap.get(dto.getDeliverySn()));
+                //验证是否开启微信发货
+                if (config.getIsWeChatShipping() != null && config.getIsWeChatShipping()) {
+                    // 上传物流信息到微信
+                    List<FsStoreOrderCodeOpenIdVo> orderDetails = orderDetailsMap.get(orderNumber);
+                    if (uploadShippingInfoToWechat(wxService, orderInfo, orderDetails, dto, uploadTime,shipmentType)) {
+                        successList.add(dto);
+                    } else {
+                        builder.append("数据第").append(rowNum).append("行订单号为")
+                                .append(orderNumber).append("上传微信失败").append(System.lineSeparator());
+                    }
                 } else {
-                    return R.error("导入失败,订单号为" + dto.getOrderNumber() + "物流编码异常,请核对后再导入!");
+                    successList.add(dto);
                 }
-                list.add(dto);
             }
 
-            //分批次处理
-            int batchSize = 500;
-            int total = list.size();
-            int batches = (total + batchSize - 1) / batchSize;
-            for (int i = 0; i < batches; i++) {
-                int start = i * batchSize;
-                int end = Math.min(start + batchSize, total);
-                List<FsOrderDeliveryNoteDTO> subList = list.subList(start, end);
-                fsStoreOrderMapper.batchUpdateInOrderCode(subList);
+            //批量更新数据
+            if (!successList.isEmpty()) {
+                batchUpdateDeliveryNotes(successList,shipmentType);
             }
-            return R.ok("导入成功,共更新 " + total + " 条记录");
+
+            return R.ok(builder.toString().equals("") ? "操作成功!" : builder.toString());
         } catch (Exception e) {
-            // 处理其他异常
-            log.error("导入物流信息异常", e);
+            log.error("导入发货单快递信息失败", e);
             return R.error("导入失败:" + e.getMessage());
         }
     }
@@ -5546,4 +5618,69 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     public FsStoreOrderAmountScrmStatsVo selectFsStoreOrderAmountScrmStats(FsStoreOrderAmountScrmStatsQueryDto queryDto) {
         return fsStoreOrderMapper.selectFsStoreOrderAmountScrmStats(queryDto);
     }
+
+    private void batchUpdateDeliveryNotes(List<FsOrderDeliveryNoteDTO> list,Integer shipmentType) {
+        int batchSize = 500;
+        int total = list.size();
+        int batches = (total + batchSize - 1) / batchSize;
+        for (int i = 0; i < batches; i++) {
+            int start = i * batchSize;
+            int end = Math.min(start + batchSize, total);
+            List<FsOrderDeliveryNoteDTO> subList = list.subList(start, end);
+            fsStoreOrderMapper.batchUpdateInOrderCode(subList);
+        }
+    }
+
+    private boolean uploadShippingInfoToWechat(WxMaService wxService,
+                                               OrderOpenIdTransDTO orderInfo,
+                                               List<FsStoreOrderCodeOpenIdVo> orderDetails,
+                                               FsOrderDeliveryNoteDTO dto,
+                                               String uploadTime,Integer shipmentType) {
+        try {
+            WxMaOrderShippingInfoUploadRequest request = new WxMaOrderShippingInfoUploadRequest();
+            OrderKeyBean orderKeyBean = new OrderKeyBean();
+            orderKeyBean.setOrderNumberType(2);
+            orderKeyBean.setTransactionId(orderInfo.getTransactionId());
+            request.setOrderKey(orderKeyBean);
+            request.setDeliveryMode(1);
+            if(shipmentType == 1){//线上
+                request.setLogisticsType(1);
+            }else {//用户自提
+                request.setLogisticsType(4);
+            }
+
+            List<ShippingListBean> shippingList = new ArrayList<>(orderDetails.size());
+            ShippingListBean shippingListBean = null;
+            for (FsStoreOrderCodeOpenIdVo detail : orderDetails) {
+                if (shippingListBean == null) {
+                    shippingListBean = new ShippingListBean();
+                    shippingListBean.setTrackingNo(dto.getDeliveryId());
+                    shippingListBean.setExpressCompany(dto.getDeliverySn());
+                    JSONObject js = JSON.parseObject(detail.getJsonInfo());
+                    shippingListBean.setItemDesc(js.getString("productName"));
+                    ContactBean contactBean = new ContactBean();
+                    contactBean.setReceiverContact(detail.getPhone());
+                    shippingListBean.setContact(contactBean);
+                } else {
+                    //拼接
+//                    JSONObject js = JSON.parseObject(detail.getJsonInfo());
+//                    shippingListBean.setItemDesc(shippingListBean.getItemDesc()+"-"+js.getString("productName"));
+                    break;
+                }
+            }
+            shippingList.add(shippingListBean);
+            request.setShippingList(shippingList);
+            request.setUploadTime(uploadTime);
+            // 设置支付者信息
+            PayerBean payerBean = new PayerBean();
+            payerBean.setOpenid(orderInfo.getOpenId());
+            request.setPayer(payerBean);
+
+            // 上传物流信息
+            return wxService.getWxMaOrderShippingService().upload(request).getErrCode() == 0;
+        } catch (Exception e) {
+            log.error("上传物流信息到微信失败,订单号: {}", dto.getOrderNumber(), e);
+            return false;
+        }
+    }
 }

+ 190 - 109
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStorePaymentScrmServiceImpl.java

@@ -3,11 +3,16 @@ package com.fs.hisStore.service.impl;
 
 import java.math.BigDecimal;
 
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.stream.Collectors;
 
 
 import cn.binarywang.wx.miniapp.api.WxMaService;
 import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
+import cn.binarywang.wx.miniapp.bean.shop.request.shipping.*;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
@@ -28,27 +33,31 @@ import com.fs.core.config.WxMaConfiguration;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.course.config.RedPacketConfig;
 import com.fs.course.domain.FsCourseRedPacketLog;
+import com.fs.course.dto.FsOrderDeliveryNoteDTO;
+import com.fs.course.dto.FsPaymentDeliveryNoteDTO;
+import com.fs.course.dto.OrderOpenIdTransDTO;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.course.service.IFsCourseRedPacketLogService;
-import com.fs.his.config.FsSysConfig;
+import com.fs.course.vo.FsStorePaymentUsetVo;
 import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUserWx;
 import com.fs.his.service.IFsUserService;
 import com.fs.his.service.IFsUserWxService;
 import com.fs.his.utils.ConfigUtil;
-import com.fs.his.utils.HttpUtil;
+import com.fs.hisStore.config.StoreConfig;
 import com.fs.hisStore.enums.SysConfigEnum;
 import com.fs.hisStore.param.*;
+import com.fs.hisStore.vo.FsStoreOrderCodeOpenIdVo;
 import com.fs.huifuPay.domain.HuiFuCreateOrder;
 import com.fs.huifuPay.domain.HuifuCreateOrderResult;
 import com.fs.huifuPay.sdk.opps.core.utils.HuiFuUtils;
 import com.fs.huifuPay.service.HuiFuService;
-import com.fs.pay.pay.config.PayConfig;
 import com.fs.pay.pay.dto.WxJspayDTO;
 import com.fs.hisStore.vo.FsStorePaymentStatisticsVO;
 import com.fs.system.oss.CloudStorageService;
 import com.fs.system.oss.OSSFactory;
 import com.fs.system.service.ISysConfigService;
+import com.fs.utils.TwelveDigitSnowflake;
 import com.fs.wx.miniapp.config.WxMaProperties;
 import com.fs.hisStore.domain.FsUserScrm;
 import com.fs.hisStore.service.IFsUserScrmService;
@@ -65,9 +74,7 @@ import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.TransferService;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
-import com.google.common.reflect.TypeToken;
-import com.google.gson.Gson;
-import lombok.Synchronized;
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxErrorException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -88,8 +95,8 @@ import javax.servlet.http.HttpServletRequest;
  * @date 2022-06-20
  */
 @Service
-public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
-{
+@Slf4j
+public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService {
     Logger logger = LoggerFactory.getLogger(getClass());
     @Autowired
     private WxMaProperties properties;
@@ -132,8 +139,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
      * @return 支付明细
      */
     @Override
-    public FsStorePaymentScrm selectFsStorePaymentById(Long paymentId)
-    {
+    public FsStorePaymentScrm selectFsStorePaymentById(Long paymentId) {
         return fsStorePaymentMapper.selectFsStorePaymentById(paymentId);
     }
 
@@ -144,8 +150,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
      * @return 支付明细
      */
     @Override
-    public List<FsStorePaymentScrm> selectFsStorePaymentList(FsStorePaymentScrm fsStorePayment)
-    {
+    public List<FsStorePaymentScrm> selectFsStorePaymentList(FsStorePaymentScrm fsStorePayment) {
         return fsStorePaymentMapper.selectFsStorePaymentList(fsStorePayment);
     }
 
@@ -156,8 +161,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
      * @return 结果
      */
     @Override
-    public int insertFsStorePayment(FsStorePaymentScrm fsStorePayment)
-    {
+    public int insertFsStorePayment(FsStorePaymentScrm fsStorePayment) {
         fsStorePayment.setCreateTime(DateUtils.getNowDate());
         return fsStorePaymentMapper.insertFsStorePayment(fsStorePayment);
     }
@@ -169,8 +173,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
      * @return 结果
      */
     @Override
-    public int updateFsStorePayment(FsStorePaymentScrm fsStorePayment)
-    {
+    public int updateFsStorePayment(FsStorePaymentScrm fsStorePayment) {
         return fsStorePaymentMapper.updateFsStorePayment(fsStorePayment);
     }
 
@@ -181,8 +184,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
      * @return 结果
      */
     @Override
-    public int deleteFsStorePaymentByIds(Long[] paymentIds)
-    {
+    public int deleteFsStorePaymentByIds(Long[] paymentIds) {
         return fsStorePaymentMapper.deleteFsStorePaymentByIds(paymentIds);
     }
 
@@ -193,15 +195,14 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
      * @return 结果
      */
     @Override
-    public int deleteFsStorePaymentById(Long paymentId)
-    {
+    public int deleteFsStorePaymentById(Long paymentId) {
         return fsStorePaymentMapper.deleteFsStorePaymentById(paymentId);
     }
 
     @Override
     @Transactional
     public R payment(FsStorePaymentPayParam payment) {
-        if(payment.getPayMoney().compareTo(new BigDecimal(0.0))<1){
+        if (payment.getPayMoney().compareTo(new BigDecimal(0.0)) < 1) {
             return R.error("支付金额必须大于0");
         }
         // //获取OPENID
@@ -213,8 +214,8 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
         // } catch (WxErrorException e) {
         //     e.printStackTrace();
         // }
-        CompanyUser companyUser=companyUserService.selectCompanyUserById(payment.getCompanyUserId());
-        FsUserScrm user=userService.selectFsUserById(payment.getUserId());
+        CompanyUser companyUser = companyUserService.selectCompanyUserById(payment.getCompanyUserId());
+        FsUserScrm user = userService.selectFsUserById(payment.getUserId());
         // if(user==null){
         //     //写入
         //     user=new FsUser();
@@ -227,7 +228,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
         //     user.setIsWeixinAuth(0);
         //     userService.insertFsUser(user);
         // }
-        FsStorePaymentScrm storePayment=new FsStorePaymentScrm();
+        FsStorePaymentScrm storePayment = new FsStorePaymentScrm();
         storePayment.setCompanyId(payment.getCompanyId());
         storePayment.setCompanyUserId(payment.getCompanyUserId());
         storePayment.setStatus(0);
@@ -239,7 +240,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
         storePayment.setRemark(payment.getRemark());
         storePayment.setOpenId(user.getMaOpenId());
         storePayment.setUserId(user.getUserId());
-        if(companyUser==null){
+        if (companyUser == null) {
             return R.error("销售帐号不存在");
         }
         storePayment.setDeptId(companyUser.getDeptId());
@@ -249,7 +250,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
         WxJspayDTO p = new WxJspayDTO();
         // 使用setter方法为对象赋值
         p.setPayMoney(storePayment.getPayMoney().toString());
-        p.setLowOrderId("payment-"+storePayment.getPayCode());
+        p.setLowOrderId("payment-" + storePayment.getPayCode());
         p.setBody("超重/肥胖/气血/代谢/美乳/慢病医学管理方案服务");
         p.setIsMinipg("1");
         //p.setReturnUrl(PayConfig.notifyUrl);
@@ -258,14 +259,13 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
         p.setAttach("");
         p.setStoreid("0");
         CreateWxOrderResult wxOrder = ybPayService.createWxOrder(p);
-        if(wxOrder.getStatus().equals("100")){
-            FsStorePaymentScrm ment=new FsStorePaymentScrm();
+        if (wxOrder.getStatus().equals("100")) {
+            FsStorePaymentScrm ment = new FsStorePaymentScrm();
             ment.setPaymentId(storePayment.getPaymentId());
             ment.setTradeNo(wxOrder.getUpOrderId());
             fsStorePaymentMapper.updateFsStorePayment(ment);
-            return R.ok().put("result",wxOrder.getPay_info());
-        }
-        else{
+            return R.ok().put("result", wxOrder.getPay_info());
+        } else {
             return R.error(wxOrder.getMessage());
         }
         //小雨点支付
@@ -308,7 +308,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
     }
 
     @Override
-    @DataScope(deptAlias = "cu",userAlias = "cu")
+    @DataScope(deptAlias = "cu", userAlias = "cu")
     public List<FsStorePaymentVO> selectFsStorePaymentListQueryVO(FsStorePaymentParam fsStorePayment) {
         return fsStorePaymentMapper.selectFsStorePaymentListQueryVO(fsStorePayment);
     }
@@ -324,16 +324,16 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
     }
 
     @Override
-    public Long selectFsStorePaymentCount(int type,Long companyId,Long companyUserId) {
-        return fsStorePaymentMapper.selectFsStorePaymentCount(type,companyId,companyUserId);
+    public Long selectFsStorePaymentCount(int type, Long companyId, Long companyUserId) {
+        return fsStorePaymentMapper.selectFsStorePaymentCount(type, companyId, companyUserId);
     }
 
     @Override
     @Transactional
-    public String payConfirm(String payCode,String tradeNo,String bankTransactionId,String bankSerialNo) {
+    public String payConfirm(String payCode, String tradeNo, String bankTransactionId, String bankSerialNo) {
         //更新订单状态
-        FsStorePaymentScrm storePayment=fsStorePaymentMapper.selectFsStorePaymentByCode(payCode);
-        if(!storePayment.getStatus().equals(0)){
+        FsStorePaymentScrm storePayment = fsStorePaymentMapper.selectFsStorePaymentByCode(payCode);
+        if (!storePayment.getStatus().equals(0)) {
             return "";
         }
         storePayment.setStatus(1);
@@ -352,12 +352,12 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
     @Override
     @Transactional
     public String refund(String orderCode) {
-        FsStorePaymentScrm payment=fsStorePaymentMapper.selectFsStorePaymentByCode(orderCode);
+        FsStorePaymentScrm payment = fsStorePaymentMapper.selectFsStorePaymentByCode(orderCode);
         payment.setStatus(-1);
         payment.setRefundTime(new Date());
         fsStorePaymentMapper.updateFsStorePayment(payment);
         //收款 减去所有
-        if(payment.getCompanyId()!=null&&payment.getCompanyId()>0){
+        if (payment.getCompanyId() != null && payment.getCompanyId() > 0) {
             companyService.subCompanyPaymentMoney(payment);
         }
         return "success";
@@ -389,7 +389,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
         String json;
         RedPacketConfig config = new RedPacketConfig();
         // 根据红包模式获取配置
-        switch (param.getRedPacketMode()){
+        switch (param.getRedPacketMode()) {
             case 1:
                 json = configService.selectConfigByKey("redPacket.config");
                 config = JSONUtil.toBean(json, RedPacketConfig.class);
@@ -400,7 +400,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
                 break;
         }
         //H5的用公众号的appid发,小程序的用小程序的appid来发
-        if (param.getSource()==2){
+        if (param.getSource() == 2) {
             config.setAppId(param.getAppId());
         }
         //组合返回参数
@@ -409,13 +409,13 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
         if (config.getIsNew() != null && config.getIsNew() == 1) {
             result = sendRedPacketV3Internal(param, config);
         } else {
-            result= sendRedPacketLegacyInternal(param, config);
+            result = sendRedPacketLegacyInternal(param, config);
         }
-        result.put("isNew",config.getIsNew());
+        result.put("isNew", config.getIsNew());
 //        result.put("mchId",config.getMchId());
 
-        result.put("mchId",config.getMchId());
-        System.out.println("发红包返回"+result);
+        result.put("mchId", config.getMchId());
+        System.out.println("发红包返回" + result);
         return result;
     }
 
@@ -429,12 +429,12 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
 
         TransferBillsRequest request = new TransferBillsRequest();
         request.setAppid(config.getAppId());
-        System.out.println("appid:"+config.getAppId());
+        System.out.println("appid:" + config.getAppId());
         request.setOpenid(param.getOpenId());
 
 //        String code = String.valueOf(IdUtil.getSnowflake(0, 0).nextId());
-        String code =  OrderCodeUtils.getOrderSn();
-        if(StringUtils.isEmpty(code)){
+        String code = OrderCodeUtils.getOrderSn();
+        if (StringUtils.isEmpty(code)) {
             return R.error("红包单号生成失败,请重试");
         }
         request.setOutBillNo("fsCourse" + code);
@@ -481,8 +481,8 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
         TransferBatchesRequest request = new TransferBatchesRequest();
         request.setAppid(config.getAppId());
 //        String code = IdUtil.getSnowflake(0, 0).nextIdStr();
-        String code =  OrderCodeUtils.getOrderSn();
-        if(StringUtils.isEmpty(code)){
+        String code = OrderCodeUtils.getOrderSn();
+        if (StringUtils.isEmpty(code)) {
             return R.error("红包单号生成失败,请重试");
         }
         request.setOutBatchNo("fsCourse" + code);
@@ -499,17 +499,17 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
 
         String openId;
         //临时方法,有code的时候获取一下客户的openId
-        if (StringUtils.isNotEmpty(param.getCode())){
+        if (StringUtils.isNotEmpty(param.getCode())) {
             WxMaService wxService = WxMaConfiguration.getMaService(param.getAppId());
             try {
                 WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(param.getCode());
                 openId = session.getOpenid();
-                logger.info("修改或新增openId:{},userId:{},appId:{}",session.getOpenid(),param.getUser().getUserId(),param.getAppId());
-                handleFsUserWx(param.getUser(),param.getAppId(),session);
-            } catch (WxErrorException e){
+                logger.info("修改或新增openId:{},userId:{},appId:{}", session.getOpenid(), param.getUser().getUserId(), param.getAppId());
+                handleFsUserWx(param.getUser(), param.getAppId(), session);
+            } catch (WxErrorException e) {
                 return R.error("openId获取失败," + e.getMessage());
             }
-        }else {
+        } else {
             openId = param.getOpenId();
         }
 
@@ -552,7 +552,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
 //        }
         boolean updated = fsUserWxService.lambdaUpdate()
                 .eq(FsUserWx::getFsUserId, user.getUserId())
-                .eq(FsUserWx::getAppId,appId )
+                .eq(FsUserWx::getAppId, appId)
                 .eq(FsUserWx::getOpenId, session.getOpenid())
                 .set(FsUserWx::getUnionId, session.getUnionid() == null ? "" : session.getUnionid())
                 .set(FsUserWx::getUpdateTime, new Date())
@@ -579,7 +579,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
         RedPacketConfig config = new RedPacketConfig();
         // 根据红包模式获取配置
 
-        String  json = configService.selectConfigByKey("redPacket.config");
+        String json = configService.selectConfigByKey("redPacket.config");
         config = JSONUtil.toBean(json, RedPacketConfig.class);
 
         param.setSource(2);
@@ -645,15 +645,15 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
 
     @Override
     public String transferNotify(String notifyData, HttpServletRequest request) {
-        logger.info("zyp \n【收到转账回调】:{}",notifyData);
+        logger.info("zyp \n【收到转账回调】:{}", notifyData);
         try {
             String json = configService.selectConfigByKey("redPacket.config");
             RedPacketConfig config = JSONUtil.toBean(json, RedPacketConfig.class);
             //创建微信订单
             WxPayConfig payConfig = new WxPayConfig();
-            BeanUtils.copyProperties(config,payConfig);
+            BeanUtils.copyProperties(config, payConfig);
             System.out.println(payConfig);
-            logger.info("到零钱回调:{}",payConfig);
+            logger.info("到零钱回调:{}", payConfig);
             WxPayService wxPayService = new WxPayServiceImpl();
             wxPayService.setConfig(payConfig);
             SignatureHeader signatureHeader = new SignatureHeader();
@@ -661,17 +661,17 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
             signatureHeader.setNonce(request.getHeader("Wechatpay-Nonce"));
             signatureHeader.setSerial(request.getHeader("Wechatpay-Serial"));
             signatureHeader.setSignature(request.getHeader("Wechatpay-Signature"));
-            WxPayTransferBatchesNotifyV3Result result = wxPayService.parseTransferBatchesNotifyV3Result(notifyData,signatureHeader);
-            logger.info("到零钱回调:{}",result.getResult());
-            if (result.getResult().getBatchStatus().equals("FINISHED") && result.getResult().getFailNum()==0) {
-                R r = redPacketLogService.syncRedPacket(result.getResult().getOutBatchNo(),result.getResult().getBatchId());
-                logger.info("result:{}",r);
-                if (r.get("code").equals(200)){
+            WxPayTransferBatchesNotifyV3Result result = wxPayService.parseTransferBatchesNotifyV3Result(notifyData, signatureHeader);
+            logger.info("到零钱回调:{}", result.getResult());
+            if (result.getResult().getBatchStatus().equals("FINISHED") && result.getResult().getFailNum() == 0) {
+                R r = redPacketLogService.syncRedPacket(result.getResult().getOutBatchNo(), result.getResult().getBatchId());
+                logger.info("result:{}", r);
+                if (r.get("code").equals(200)) {
                     return WxPayNotifyResponse.success("处理成功");
-                }else {
+                } else {
                     return WxPayNotifyResponse.fail("");
                 }
-            }else {
+            } else {
                 return WxPayNotifyResponse.fail("");
             }
         } catch (WxPayException e) {
@@ -682,13 +682,13 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
 
     @Override
     public String v3TransferNotify(String notifyData, HttpServletRequest request) {
-        logger.info("zyp \n【收到转账回调】:{}",notifyData);
+        logger.info("zyp \n【收到转账回调】:{}", notifyData);
         try {
             String json = configService.selectConfigByKey("redPacket.config");
             RedPacketConfig config = JSONUtil.toBean(json, RedPacketConfig.class);
             //创建微信订单
             WxPayConfig payConfig = new WxPayConfig();
-            BeanUtils.copyProperties(config,payConfig);
+            BeanUtils.copyProperties(config, payConfig);
             WxPayService wxPayService = new WxPayServiceImpl();
             wxPayService.setConfig(payConfig);
             SignatureHeader signatureHeader = new SignatureHeader();
@@ -696,21 +696,21 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
             signatureHeader.setNonce(request.getHeader("Wechatpay-Nonce"));
             signatureHeader.setSerial(request.getHeader("Wechatpay-Serial"));
             signatureHeader.setSignature(request.getHeader("Wechatpay-Signature"));
-            TransferBillsNotifyResult result = wxPayService.parseTransferBillsNotifyV3Result(notifyData,signatureHeader);
-            logger.info("到零钱回调:{}",result.getResult());
+            TransferBillsNotifyResult result = wxPayService.parseTransferBillsNotifyV3Result(notifyData, signatureHeader);
+            logger.info("到零钱回调:{}", result.getResult());
             if (result.getResult().getState().equals("SUCCESS")) {
-                R r = redPacketLogService.syncRedPacket(result.getResult().getOutBillNo(),result.getResult().getTransferBillNo());
-                logger.info("result:{}",r);
-                if (r.get("code").equals(200)){
+                R r = redPacketLogService.syncRedPacket(result.getResult().getOutBillNo(), result.getResult().getTransferBillNo());
+                logger.info("result:{}", r);
+                if (r.get("code").equals(200)) {
                     return WxPayNotifyResponse.success("处理成功");
-                }else {
+                } else {
                     return WxPayNotifyResponse.fail("");
                 }
-            }else {
+            } else {
                 return WxPayNotifyResponse.fail("");
             }
         } catch (WxPayException e) {
-            logger.error("zyp \n【转账回调异常】:{}", e.getReturnMsg(),e);
+            logger.error("zyp \n【转账回调异常】:{}", e.getReturnMsg(), e);
             return WxPayNotifyResponse.fail(e.getMessage());
         }
     }
@@ -724,21 +724,21 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
 //        RedPacketConfig config = JSONUtil.toBean(json, RedPacketConfig.class);
         List<FsCourseRedPacketLog> logs = redPacketLogMapper.selectFailAll();
         String appId = "wx414427b10866c04e";
-        for (FsCourseRedPacketLog log : logs){
+        for (FsCourseRedPacketLog log : logs) {
             FsUserScrm user = userService.selectFsUserById(log.getUserId());
             WxSendRedPacketParam param = new WxSendRedPacketParam();
             param.setAppId(appId);
-            if (user==null || user.getMaOpenId()==null){
+            if (user == null || user.getMaOpenId() == null) {
                 continue;
             }
             param.setOpenId(user.getMaOpenId());
             param.setAmount(log.getAmount());
             R r = this.sendRedPacketTest(param);
-            if (r.get("code").equals(200)){
+            if (r.get("code").equals(200)) {
                 log.setOutBatchNo(r.get("orderCode").toString());
                 log.setBatchId(r.get("batchId").toString());
                 redPacketLogMapper.updateFsCourseRedPacketLog(log);
-                logger.info("更新完成:{}",log.getLogId());
+                logger.info("更新完成:{}", log.getLogId());
             }
 
         }
@@ -788,24 +788,24 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
             }
         }
         return R.ok();
-        }
+    }
 
 
     @Override
-    public R getWxaCodeByPayment(FsStorePaymentGetWxaCodeParam param)  {
+    public R getWxaCodeByPayment(FsStorePaymentGetWxaCodeParam param) {
         final WxMaService wxMaService = WxMaConfiguration.getMaService(param.getAppId());
         String scene;
         //判断销售id
-        if (param.getCompanyUserId() == null){
-            scene = "companyId="+ param.getCompanyId();
-        }else {
-            scene = "companyId="+ param.getCompanyId()+"&"+"companyUserId="+ param.getCompanyUserId();
+        if (param.getCompanyUserId() == null) {
+            scene = "companyId=" + param.getCompanyId();
+        } else {
+            scene = "companyId=" + param.getCompanyId() + "&" + "companyUserId=" + param.getCompanyUserId();
         }
         byte[] file;
         try {
 
             file = wxMaService.getQrcodeService().createWxaCodeBytes(
-                    "pages_user/user/pay?companyId="+param.getCompanyId(),
+                    "pages_user/user/pay?companyId=" + param.getCompanyId(),
                     "release",
                     430,
                     true,
@@ -827,14 +827,14 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
             String url;
             try {
                 url = storage.uploadSuffix(file, suffix);
-            }  catch (Exception e) {
+            } catch (Exception e) {
                 // 记录错误日志
-                logger.error("生成图片失败:{}",e.getMessage(),e);
+                logger.error("生成图片失败:{}", e.getMessage(), e);
                 return R.error("生成图片失败");
             }
-            redisCache.setCacheObject("company-wxa-code:"+param.getCompanyId()+":"+param.getAppId(),url);
+            redisCache.setCacheObject("company-wxa-code:" + param.getCompanyId() + ":" + param.getAppId(), url);
             // 返回成功信息
-            return R.ok().put("url",url);
+            return R.ok().put("url", url);
 
         } catch (WxErrorException e) {
             logger.error(e.getMessage(), e);
@@ -849,29 +849,29 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
     @Override
     public R paymentByWxaCode(FsStorePaymentPayParam param) {
         FsUser user = fsUserService.selectFsUserById(param.getUserId());
-        if (user==null){
+        if (user == null) {
             return R.error("用户不存在!");
         }
         Company company = companyService.selectCompanyById(param.getCompanyId());
-        if (company==null || company.getStatus()==0){
+        if (company == null || company.getStatus() == 0) {
             return R.error("服务商不存在,或已被停用!");
         }
-        if(param.getPayMoney().compareTo(new BigDecimal(0.0))<1){
+        if (param.getPayMoney().compareTo(new BigDecimal(0.0)) < 1) {
             return R.error("支付金额必须大于0");
         }
-        if (param.getCompanyUserId()!=null){
+        if (param.getCompanyUserId() != null) {
             CompanyUser companyUser = companyUserService.selectCompanyUserById(param.getCompanyUserId());
-            if(companyUser == null || companyUser.getStatus().equals("1")){
+            if (companyUser == null || companyUser.getStatus().equals("1")) {
                 return R.error("注册失败客服已停用,或不存在!");
             }
         }
 
         //生成支付流水
         String orderSn = IdUtil.getSnowflake(0, 0).nextIdStr();
-        FsStorePaymentScrm storePayment=new FsStorePaymentScrm();
+        FsStorePaymentScrm storePayment = new FsStorePaymentScrm();
         storePayment.setCompanyId(param.getCompanyId());
         //判断销售是否存在
-        if (param.getCompanyUserId()!=null){
+        if (param.getCompanyUserId() != null) {
             storePayment.setCompanyUserId(param.getCompanyUserId());
         }
         storePayment.setStatus(0);
@@ -891,30 +891,30 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
         HuiFuCreateOrder o = new HuiFuCreateOrder();
         o.setTradeType("T_MINIAPP");
         o.setOpenid(user.getMaOpenId());
-        o.setReqSeqId("payment-"+storePayment.getPayCode());
+        o.setReqSeqId("payment-" + storePayment.getPayCode());
         o.setTransAmt(storePayment.getPayMoney().toString());
         o.setGoodsDesc("商城订单支付");
         o.setAppId(param.getAppId());
         //公司分账
         try {
-            HuiFuUtils.doDiv(o,company.getCompanyId());
+            HuiFuUtils.doDiv(o, company.getCompanyId());
             //存储分账明细
             HuiFuUtils.saveDivItem(o, storePayment.getPayCode(), storePayment.getPayCode());
         } catch (Exception e) {
             logger.error("-------------微信收款分账出错:{}", e.getMessage());
         }
         HuifuCreateOrderResult result = huiFuService.createOrder(o);
-        if(result.getResp_code()!=null&&(result.getResp_code().equals("00000000")||result.getResp_code().equals("00000100"))){
-            FsStorePaymentScrm mt=new FsStorePaymentScrm();
+        if (result.getResp_code() != null && (result.getResp_code().equals("00000000") || result.getResp_code().equals("00000100"))) {
+            FsStorePaymentScrm mt = new FsStorePaymentScrm();
             mt.setPaymentId(storePayment.getPaymentId());
             mt.setTradeNo(result.getHf_seq_id());
             fsStorePaymentMapper.updateFsStorePayment(mt);
-            Map<String, Object> resultMap = JSON.parseObject(result.getPay_info(), new TypeReference<Map<String, Object>>() {});
+            Map<String, Object> resultMap = JSON.parseObject(result.getPay_info(), new TypeReference<Map<String, Object>>() {
+            });
             String s = (String) resultMap.get("package");
-            resultMap.put("packageValue",s);
-            return R.ok().put("result",resultMap);
-        }
-        else{
+            resultMap.put("packageValue", s);
+            return R.ok().put("result", resultMap);
+        } else {
             return R.error(result.getResp_desc());
         }
     }
@@ -948,4 +948,85 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
         }
         return "success";
     }
+
+    @Override
+    public R oneClickShipping() {
+        try {
+            StringBuilder builder = new StringBuilder();
+            //获取商城配置
+            String json = configService.selectConfigByKey("store.config");
+            StoreConfig config = JSONUtil.toBean(json, StoreConfig.class);
+            //验证是否开启微信发货
+            if (config.getIsWeChatShipping() != null && config.getIsWeChatShipping()) {
+                //获取支付信息
+                List<FsStorePaymentUsetVo> paymentList = fsStorePaymentMapper.getPaymentUsetInfoList();
+                if (paymentList.isEmpty()) {
+                    return R.ok("操作成功,暂无同步订单信息!");
+                }
+                String uploadTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"))
+                        .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+                Map<String, List<FsStorePaymentUsetVo>> paymentUsetVoMap = paymentList.stream().collect(Collectors.groupingBy(FsStorePaymentUsetVo::getAppId));
+                for (Map.Entry<String, List<FsStorePaymentUsetVo>> entry : paymentUsetVoMap.entrySet()) {
+                    List<String> successList = new ArrayList<>();
+                    String appId = entry.getKey();
+                    List<FsStorePaymentUsetVo> userPayments = entry.getValue();
+                    final WxMaService wxService = WxMaConfiguration.getMaService(appId);
+                    if (!userPayments.isEmpty()) {
+                        for (FsStorePaymentUsetVo v : userPayments) {
+                            // 上传物流信息到微信
+                            if (uploadShippingInfoToWechat(wxService, v, uploadTime)) {
+                                successList.add(v.getBankTransactionId());
+                            }
+                        }
+                        //批量更新数据
+                        if (!successList.isEmpty()) {
+                            fsStorePaymentMapper.batchUpadte(successList);
+                        }
+                    }
+                }
+            }
+
+
+            return R.ok(builder.toString().equals("") ? "操作成功!" : builder.toString());
+        } catch (Exception e) {
+            log.error("导入发货单快递信息失败", e);
+            return R.error("导入失败:" + e.getMessage());
+        }
+    }
+
+    private boolean uploadShippingInfoToWechat(WxMaService wxService,
+                                               FsStorePaymentUsetVo dto,
+                                               String uploadTime) {
+        try {
+            WxMaOrderShippingInfoUploadRequest request = new WxMaOrderShippingInfoUploadRequest();
+            OrderKeyBean orderKeyBean = new OrderKeyBean();
+            orderKeyBean.setOrderNumberType(2);
+            orderKeyBean.setTransactionId(dto.getBankTransactionId());//交易订单号ID
+            request.setOrderKey(orderKeyBean);
+            request.setDeliveryMode(1);
+            request.setLogisticsType(4);
+            List<ShippingListBean> shippingList = new ArrayList<>();
+            ShippingListBean shippingListBean = new ShippingListBean();
+            //默认物品信息
+            shippingListBean.setTrackingNo(String.valueOf(new TwelveDigitSnowflake(1).nextId()));
+            shippingListBean.setExpressCompany("FS");
+            shippingListBean.setItemDesc("默认商品");
+            ContactBean contactBean = new ContactBean();
+            contactBean.setReceiverContact(dto.getPhone());
+            shippingListBean.setContact(contactBean);
+
+            shippingList.add(shippingListBean);
+            request.setShippingList(shippingList);
+            request.setUploadTime(uploadTime);
+            // 设置支付者信息
+            PayerBean payerBean = new PayerBean();
+            payerBean.setOpenid(dto.getOpenId());
+            request.setPayer(payerBean);
+            // 上传物流信息
+            return wxService.getWxMaOrderShippingService().upload(request).getErrCode() == 0;
+        } catch (Exception e) {
+            log.error("上传物流信息到微信失败,订单号: {}", dto.getBankTransactionId(), e);
+            return false;
+        }
+    }
 }

+ 38 - 0
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderCodeOpenIdVo.java

@@ -0,0 +1,38 @@
+package com.fs.hisStore.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class FsStoreOrderCodeOpenIdVo implements Serializable {
+//    /**
+//     * 订单编码
+//     * **/
+//    private String orderCode;
+
+    /**
+     * 订单id
+     * **/
+    private String id;
+
+    /**
+     * 用户openId
+     * **/
+    private String openId;
+
+    /**
+     * 用户手机号
+     * **/
+    private String phone;
+
+    /**
+     * 商品详情信息
+     * **/
+    private String jsonInfo;
+
+    /**
+     * 交易单号
+     * **/
+    private String outTransId;
+}

+ 4 - 4
fs-service/src/main/resources/application-dev-yjb.yml

@@ -33,9 +33,9 @@ spring:
             druid:
                 # 主库数据源
                 master:
-                    url: jdbc:mysql://nj-cdb-22nvjajz.sql.tencentcdb.com:29237/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
-                    username: root
-                    password: Ylrz147..
+                    url: jdbc:mysql://139.186.77.83:3306/yjb_his_scrm_test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: Rtroot
+                    password: Rtroot
                 # 初始连接数
                 initialSize: 5
                 # 最小连接池数量
@@ -81,7 +81,7 @@ spring:
             druid:
                 # 主库数据源
                 master:
-                  url: jdbc:mysql://nj-cdb-22nvjajz.sql.tencentcdb.com:29237/fs_his_sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                  url: jdbc:mysql://nj-cdb-6306xy90.sql.tencentcdb.com:27077/fs_his_sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
                   username: root
                   password: Ylrz147..
                 # 初始连接数

+ 159 - 0
fs-service/src/main/resources/mapper/hisStore/FsStoreOrderScrmMapper.xml

@@ -1974,4 +1974,163 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         update fs_store_order_scrm SET  status = #{status} WHERE
                                                                id IN <foreach collection="orderIds" item="item" index="index" open="(" separator="," close=")">#{item}</foreach>
     </update>
+
+    <select id="selectFsStoreOrderListVOByErpAccount" resultType="com.fs.hisStore.vo.FsStoreOrderVO">
+        select o.*,u.phone,u.register_code,u.register_date,u.source, c.company_name ,cu.nick_name as company_user_nick_name ,cu.phonenumber as company_usere_phonenumber,,df.login_account as erp_account,
+        from fs_store_order_scrm o
+        left join fs_user u on o.user_id=u.user_id
+        left join company c on c.company_id=o.company_id
+        left join company_user cu on cu.user_id=o.company_user_id
+        LEFT JOIN fs_store_order_df df on df.order_id=o.id
+        <if test = "maps.productName != null and  maps.productName !=  '' ">
+            left join fs_store_order_item_scrm oi on o.id = oi.order_id
+            left join fs_store_product_scrm fsp on fsp.product_id = oi.product_id
+        </if>
+        LEFT JOIN (
+        SELECT
+        sp.*,
+        ROW_NUMBER() OVER (PARTITION BY sp.business_code ORDER BY sp.create_time DESC) as rn
+        FROM fs_store_payment_scrm sp
+        ) sp_latest ON sp_latest.business_code = o.order_code AND sp_latest.rn = 1
+        LEFT JOIN fs_course_play_source_config csc ON csc.appid = sp_latest.app_id
+        <where>
+            <if test="maps.coursePlaySourceConfigId != null">
+                and csc.id = #{maps.coursePlaySourceConfigId}
+            </if>
+            <if test="maps.orderCodes != null  and maps.orderCodes.size > 0">
+                and o.order_code in
+                <foreach collection="maps.orderCodes" item="orderCode" open="(" close=")" separator=",">
+                    #{orderCode}
+                </foreach>
+            </if>
+            <if test="maps.orderCode != null and  maps.orderCode !=''">
+                and o.order_code like CONCAT('%',#{maps.orderCode},'%')
+            </if>
+            <if test="maps.isPayRemain != null">
+                and o.is_pay_remain =#{maps.isPayRemain}
+            </if>
+            <if test="maps.userId != null">
+                and o.user_id =#{maps.userId}
+            </if>
+            <if test="maps.deliveryId != null and  maps.deliveryId !=''">
+                and o.delivery_id =#{maps.deliveryId}
+            </if>
+            <if test="maps.nickname != null and  maps.nickname !=''">
+                and u.nickname like CONCAT('%',#{maps.nickname},'%')
+            </if>
+            <if test="maps.realName != null and  maps.realName !=''">
+                and o.real_name like CONCAT('%',#{maps.realName},'%')
+            </if>
+            <if test="maps.phone != null and  maps.phone !=''">
+                and u.phone like CONCAT('%',#{maps.phone},'%')
+            </if>
+            <if test="maps.userPhone != null and  maps.userPhone !=''">
+                and o.user_phone like CONCAT('%',#{maps.userPhone},'%')
+            </if>
+
+            <if test="maps.status != null and maps.status != 6">
+                and o.status = #{maps.status}
+            </if>
+            <if test="maps.status == 6">
+                and o.`status`= 2
+
+                and  (o.extend_order_id is null or  o.extend_order_id like '')
+            </if>
+            <if test="maps.isUpload != null and maps.isUpload == 0    ">
+                and o.certificates is null
+            </if>
+            <if test="maps.isUpload != null and maps.isUpload == 1    ">
+                and o.certificates is not null
+            </if>
+            <if test="maps.deliveryStatus != null     ">
+                and o.delivery_status =#{maps.deliveryStatus}
+            </if>
+            <if test="maps.deliveryPayStatus != null  ">
+                and o.delivery_pay_status =#{maps.deliveryPayStatus}
+            </if>
+            <if test="maps.companyId != null   ">
+                and o.company_id =#{maps.companyId}
+            </if>
+            <if test="maps.isHealth != null and maps.isHealth !=  ''   ">
+                and o.company_id is null
+            </if>
+            <if test="maps.notHealth != null  ">
+                and o.company_id is not null
+            </if>
+            <if test="maps.companyUserId != null  ">
+                and o.company_user_id =#{maps.companyUserId}
+            </if>
+            <if test="maps.companyUserNickName != null and  maps.companyUserNickName !=  '' ">
+                and cu.nick_name like concat('%', #{maps.companyUserNickName}, '%')
+            </if>
+            <if test="maps.productName != null and  maps.productName !=  '' ">
+                and fsp.product_name like concat('%', #{maps.productName}, '%')
+            </if>
+            <if test="maps.orderType != null    ">
+                and o.order_type =#{maps.orderType}
+            </if>
+            <if test="maps.payType != null    ">
+                and o.pay_type =#{maps.payType}
+            </if>
+            <if test="maps.scheduleId != null    ">
+                and o.schedule_id =#{maps.scheduleId}
+            </if>
+            <if test="maps.createTimeList != null    ">
+                AND date_format(o.create_time,'%y%m%d') &gt;= date_format(#{maps.createTimeList[0]},'%y%m%d')
+                AND date_format(o.create_time,'%y%m%d') &lt;= date_format(#{maps.createTimeList[1]},'%y%m%d')
+            </if>
+            <if test="maps.deliverySendTimeList != null    ">
+                AND date_format(o.delivery_send_time,'%y%m%d') &gt;= date_format(#{maps.deliverySendTimeList[0]},'%y%m%d')
+                AND date_format(o.delivery_send_time,'%y%m%d') &lt;= date_format(#{maps.deliverySendTimeList[1]},'%y%m%d')
+            </if>
+            <if test="maps.paidStatus != null    ">
+                and o.paid =#{maps.paidStatus}
+            </if>
+            <if test="maps.payTimeList != null     ">
+                AND date_format(o.pay_time,'%y%m%d') &gt;= date_format(#{maps.payTimeList[0]},'%y%m%d')
+                AND date_format(o.pay_time,'%y%m%d') &lt;= date_format(#{maps.payTimeList[1]},'%y%m%d')
+            </if>
+            <if test="maps.deliveryImportTimeList != null     ">
+                AND date_format(o.delivery_import_time,'%y%m%d') &gt;= date_format(#{maps.deliveryImportTimeList[0]},'%y%m%d')
+                AND date_format(o.delivery_import_time,'%y%m%d') &lt;= date_format(#{maps.deliveryImportTimeList[1]},'%y%m%d')
+            </if>
+            <if test="maps.deptId != null     ">
+                AND (o.dept_id = #{maps.deptId} OR o.dept_id IN ( SELECT t.dept_id FROM company_dept t WHERE find_in_set(#{maps.deptId}, ancestors) ))
+            </if>
+            <if test="maps.erpPhoneNumber != null and maps.erpPhoneNumber != ''">
+                and o.erp_phone like concat(#{maps.erpPhoneNumber},'%')
+            </if>
+            <if test="maps.erpAccount != null and maps.erpAccount != '未分拣' and maps.erpAccount != ''">
+                and df.login_account like #{maps.erpAccount}
+            </if>
+            <if test="maps.erpAccount == '未分拣'">
+                and ( df.login_account is null or df.login_account like '')
+            </if>
+        </where>
+        ${maps.params.dataScope}
+        <if test="maps.productName != null and  maps.productName !=  ''   ">
+            group by o.id
+        </if>
+        ORDER BY
+
+        <if test="maps.sortField == 'companyUserName'">
+            cu.nick_name
+        </if>
+        <if test="maps.sortField == 'packageName'">
+            o.package_name
+        </if>
+        <if test="maps.sortField == 'payPrice'">
+            o.pay_price
+        </if>
+        <if test="maps.sortField == 'payMoney'">
+            o.pay_money
+        </if>
+        <if test="maps.sortOrder != null and maps.sortOrder != ''">
+            ${maps.sortOrder}
+        </if>
+        <if test="maps.sortField == null or maps.sortField == ''">
+            o.id desc
+        </if>
+
+    </select>
 </mapper>

+ 24 - 0
fs-service/src/main/resources/mapper/hisStore/FsStorePaymentScrmMapper.xml

@@ -196,5 +196,29 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </if>
     </select>
 
+        <select id="getPaymentUsetInfoList" resultType="com.fs.course.vo.FsStorePaymentUsetVo">
+            SELECT
+                sp.bank_transaction_id,
+                sp.open_id,
+                sp.app_id,
+                CASE
+                    WHEN TRIM(fu.phone) IS NOT NULL AND TRIM(fu.phone) != '' THEN fu.phone
+                    ELSE CONCAT(
+                            ELT(FLOOR(1 + RAND() * 6), '13', '14', '15', '17', '18', '19'),
+                            LPAD(FLOOR(RAND() * 1000000000), 9, '0')
+                        )
+                    END AS phone
+            FROM
+                fs_store_payment_scrm sp
+                    LEFT JOIN fs_user fu ON sp.user_id = fu.user_id
+            WHERE
+               sp.status = 1 and sp.is_shipment = 0 and sp.business_type = 1 AND sp.pay_time > '2025-11-27 00:00:00' LIMIT 500
+        </select>
 
+    <update id="batchUpadte">
+        update fs_store_payment_scrm set is_shipment = 1 where bank_transaction_id in
+        <foreach item="bankTransactionId" collection="list" open="(" separator="," close=")">
+            #{bankTransactionId}
+        </foreach>
+    </update>
 </mapper>