From 2e351ce1ff002cf2ae826d15556e754c536c4d5b Mon Sep 17 00:00:00 2001 From: Damonny <826010988@qq.com> Date: Wed, 19 Feb 2025 14:02:31 +0800 Subject: [PATCH] =?UTF-8?q?create:=20=E6=96=B0=E5=A2=9E=E6=8A=96=E5=BA=97?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E6=8E=A8=E9=80=81=EF=BC=8C=E6=8A=93=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../haoka/enums/ErrorCodeConstants.java | 2 + .../orderCatch/OrderCatchController.java | 47 ++ .../admin/orderCatch/po/Message.java | 39 ++ .../admin/orderCatch/vo/OrderCatchRepVO.java | 21 + .../admin/orders/vo/OrdersRespVO.java | 31 +- .../admin/orders/vo/OrdersSaveReqVO.java | 30 + .../ordersource/vo/OrderSourceRespVO.java | 4 + .../ordersynclog/OrderSyncLogController.java | 95 +++ .../vo/OrderSyncLogPageReqVO.java | 36 + .../ordersynclog/vo/OrderSyncLogRespVO.java | 42 ++ .../vo/OrderSyncLogSaveReqVO.java | 27 + .../haoka/dal/dataobject/orders/OrdersDO.java | 24 + .../ordersynclog/OrderSyncLogDO.java | 49 ++ .../ordersynclog/OrderSyncLogMapper.java | 30 + .../schedule/DouDianOrderCatchSchdule.java | 109 +++ .../DouDianOrderCatchServiceImpl.java | 651 ++++++++++++++++++ .../service/orderCatch/orderCatchService.java | 16 + .../service/orders/OrdersServiceImpl.java | 2 +- .../ordersynclog/OrderSyncLogService.java | 55 ++ .../ordersynclog/OrderSyncLogServiceImpl.java | 74 ++ .../module/haoka/utils/GroupListUtil.java | 28 + .../ordersynclog/OrderSyncLogMapper.xml | 12 + .../DouDianOrderCatchServiceImplTest.java | 55 ++ .../OrderSyncLogServiceImplTest.java | 146 ++++ .../V5.0.17__order_update_table_add_shop.sql | 9 + .../db/migration/V6.0.1__order_catch_log.sql | 70 ++ 26 files changed, 1702 insertions(+), 2 deletions(-) create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orderCatch/OrderCatchController.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orderCatch/po/Message.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orderCatch/vo/OrderCatchRepVO.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/OrderSyncLogController.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/vo/OrderSyncLogPageReqVO.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/vo/OrderSyncLogRespVO.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/vo/OrderSyncLogSaveReqVO.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/dal/dataobject/ordersynclog/OrderSyncLogDO.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/dal/mysql/ordersynclog/OrderSyncLogMapper.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/schedule/DouDianOrderCatchSchdule.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/orderCatch/DouDianOrderCatchServiceImpl.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/orderCatch/orderCatchService.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/ordersynclog/OrderSyncLogService.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/ordersynclog/OrderSyncLogServiceImpl.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/utils/GroupListUtil.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/main/resources/mapper/ordersynclog/OrderSyncLogMapper.xml create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/test/java/cn/iocoder/yudao/module/haoka/service/orderCatch/DouDianOrderCatchServiceImplTest.java create mode 100644 yudao-module-haoka/yudao-module-haoka-biz/src/test/java/cn/iocoder/yudao/module/haoka/service/ordersynclog/OrderSyncLogServiceImplTest.java create mode 100644 yudao-server/src/main/resources/db/migration/V5.0.17__order_update_table_add_shop.sql create mode 100644 yudao-server/src/main/resources/db/migration/V6.0.1__order_catch_log.sql diff --git a/yudao-module-haoka/yudao-module-haoka-api/src/main/java/cn/iocoder/yudao/module/haoka/enums/ErrorCodeConstants.java b/yudao-module-haoka/yudao-module-haoka-api/src/main/java/cn/iocoder/yudao/module/haoka/enums/ErrorCodeConstants.java index a4d9b3263a..4c266ee56b 100644 --- a/yudao-module-haoka/yudao-module-haoka-api/src/main/java/cn/iocoder/yudao/module/haoka/enums/ErrorCodeConstants.java +++ b/yudao-module-haoka/yudao-module-haoka-api/src/main/java/cn/iocoder/yudao/module/haoka/enums/ErrorCodeConstants.java @@ -48,4 +48,6 @@ public interface ErrorCodeConstants { ErrorCode BLACK_LIST_NOT_EXISTS = new ErrorCode(1_824_003_005, "黑名单不存在"); ErrorCode SMS_TASK_NOT_EXISTS = new ErrorCode(1_824_123_005, "短信任务不存在"); ErrorCode ORDER_OPERATE_LOG_NOT_EXISTS = new ErrorCode(1_826_001_001, "订单操作日志不存在"); + + ErrorCode ORDER_SYNC_LOG_NOT_EXISTS = new ErrorCode(1_827_001_001, "抓单记录不存在"); } diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orderCatch/OrderCatchController.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orderCatch/OrderCatchController.java new file mode 100644 index 0000000000..7a93dcb5c4 --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orderCatch/OrderCatchController.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.haoka.controller.admin.orderCatch; + + +import cn.iocoder.yudao.module.haoka.controller.admin.orderCatch.po.Message; +import cn.iocoder.yudao.module.haoka.controller.admin.orderCatch.vo.OrderCatchRepVO; +import cn.iocoder.yudao.module.haoka.service.orderCatch.OrderCatchService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.annotation.security.PermitAll; +import jakarta.validation.Valid; +import org.springframework.scheduling.annotation.Async; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Tag(name = "抓取订单") +@RestController +@RequestMapping("/haoka/orderCatch") +@Validated +@PermitAll +public class OrderCatchController { + + @Resource + private OrderCatchService orderCatchService; + + @PermitAll + @RequestMapping("/catch") + @Operation(summary = "抓取订单") + public String catchOrders(@Valid @RequestBody List messages) { + // 异步处理订单数据 + execCatchOrders(messages); + // 立即返回推送所需的响应数据 + return "{\"code\":0,\"msg\":\"success\"}"; + } + + /** + * 异步处理订单数据 + * @param messages + */ + @Async + public void execCatchOrders(List messages) { + orderCatchService.catchOrders(messages); + } + +} diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orderCatch/po/Message.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orderCatch/po/Message.java new file mode 100644 index 0000000000..e63f8cd00a --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orderCatch/po/Message.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.haoka.controller.admin.orderCatch.po; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Message { + @JsonProperty("tag") + private String tag; + + @JsonProperty("msg_id") + private String msgId; + + @JsonProperty("data") + private T data; + + // Getters and Setters + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public String getMsgId() { + return msgId; + } + + public void setMsgId(String msgId) { + this.msgId = msgId; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } +} \ No newline at end of file diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orderCatch/vo/OrderCatchRepVO.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orderCatch/vo/OrderCatchRepVO.java new file mode 100644 index 0000000000..d6012890b2 --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orderCatch/vo/OrderCatchRepVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.haoka.controller.admin.orderCatch.vo; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "抖音消息推送接收实体") +@Data +@EqualsAndHashCode(callSuper = false) +@ToString(callSuper = true) +public class OrderCatchRepVO { + @Schema(description = "消息", example = "success") + private String tag; + @Schema(description = "消息", example = "success") + private String msg_id; + @Schema(description = "消息", example = "success") + private String data; + +} \ No newline at end of file diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orders/vo/OrdersRespVO.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orders/vo/OrdersRespVO.java index 85eeaebf47..6831406d19 100644 --- a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orders/vo/OrdersRespVO.java +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orders/vo/OrdersRespVO.java @@ -294,5 +294,34 @@ public class OrdersRespVO { */ @Schema(description = "身份证人脸") private String face; - + /** + * 店铺ID + */ + @Schema(description = "店铺ID") + private String shopId; + /** + * 店铺名称 + */ + @Schema(description = "店铺名称") + private String shopName; + /** + * 直播间ID + */ + @Schema(description = "直播间ID") + private String roomId; + /** + * 直播间名称 + */ + @Schema(description = "直播间名称") + private String roomName; + /** + * 销售归属 + */ + @Schema(description = "销售归属") + private String salesAttribution; + /** + * 销售归属名称 + */ + @Schema(description = "销售归属名称") + private String salesAttributionName; } diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orders/vo/OrdersSaveReqVO.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orders/vo/OrdersSaveReqVO.java index 7a69879132..43c1e69b7e 100644 --- a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orders/vo/OrdersSaveReqVO.java +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/orders/vo/OrdersSaveReqVO.java @@ -223,4 +223,34 @@ public class OrdersSaveReqVO { */ @Schema(description = "上游订单状态") private Integer upstreamOrderStatus; + /** + * 店铺ID + */ + @Schema(description = "店铺ID") + private String shopId; + /** + * 店铺名称 + */ + @Schema(description = "店铺名称") + private String shopName; + /** + * 直播间ID + */ + @Schema(description = "直播间ID") + private String roomId; + /** + * 直播间名称 + */ + @Schema(description = "直播间名称") + private String roomName; + /** + * 销售归属 + */ + @Schema(description = "销售归属") + private String salesAttribution; + /** + * 销售归属名称 + */ + @Schema(description = "销售归属名称") + private String salesAttributionName; } diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersource/vo/OrderSourceRespVO.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersource/vo/OrderSourceRespVO.java index 9714e8b78f..a4c4d7631a 100644 --- a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersource/vo/OrderSourceRespVO.java +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersource/vo/OrderSourceRespVO.java @@ -27,6 +27,10 @@ public class OrderSourceRespVO { @DictFormat("haoka_order_channel") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 private Long channel; + @Schema(description = "店铺ID", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty(value = "店铺ID") + private Long shopId; + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") private LocalDateTime createTime; diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/OrderSyncLogController.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/OrderSyncLogController.java new file mode 100644 index 0000000000..dba3071446 --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/OrderSyncLogController.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.haoka.controller.admin.ordersynclog; + +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.constraints.*; +import jakarta.validation.*; +import jakarta.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.haoka.controller.admin.ordersynclog.vo.*; +import cn.iocoder.yudao.module.haoka.dal.dataobject.ordersynclog.OrderSyncLogDO; +import cn.iocoder.yudao.module.haoka.service.ordersynclog.OrderSyncLogService; + +@Tag(name = "管理后台 - 抓单记录") +@RestController +@RequestMapping("/haoka/order-sync-log") +@Validated +public class OrderSyncLogController { + + @Resource + private OrderSyncLogService orderSyncLogService; + + @PostMapping("/create") + @Operation(summary = "创建抓单记录") + @PreAuthorize("@ss.hasPermission('haoka:order-sync-log:create')") + public CommonResult createOrderSyncLog(@Valid @RequestBody OrderSyncLogSaveReqVO createReqVO) { + return success(orderSyncLogService.createOrderSyncLog(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新抓单记录") + @PreAuthorize("@ss.hasPermission('haoka:order-sync-log:update')") + public CommonResult updateOrderSyncLog(@Valid @RequestBody OrderSyncLogSaveReqVO updateReqVO) { + orderSyncLogService.updateOrderSyncLog(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除抓单记录") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('haoka:order-sync-log:delete')") + public CommonResult deleteOrderSyncLog(@RequestParam("id") Long id) { + orderSyncLogService.deleteOrderSyncLog(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得抓单记录") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('haoka:order-sync-log:query')") + public CommonResult getOrderSyncLog(@RequestParam("id") Long id) { + OrderSyncLogDO orderSyncLog = orderSyncLogService.getOrderSyncLog(id); + return success(BeanUtils.toBean(orderSyncLog, OrderSyncLogRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得抓单记录分页") + @PreAuthorize("@ss.hasPermission('haoka:order-sync-log:query')") + public CommonResult> getOrderSyncLogPage(@Valid OrderSyncLogPageReqVO pageReqVO) { + PageResult pageResult = orderSyncLogService.getOrderSyncLogPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, OrderSyncLogRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出抓单记录 Excel") + @PreAuthorize("@ss.hasPermission('haoka:order-sync-log:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportOrderSyncLogExcel(@Valid OrderSyncLogPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = orderSyncLogService.getOrderSyncLogPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "抓单记录.xls", "数据", OrderSyncLogRespVO.class, + BeanUtils.toBean(list, OrderSyncLogRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/vo/OrderSyncLogPageReqVO.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/vo/OrderSyncLogPageReqVO.java new file mode 100644 index 0000000000..9fcad06b09 --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/vo/OrderSyncLogPageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.haoka.controller.admin.ordersynclog.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 抓单记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class OrderSyncLogPageReqVO extends PageParam { + + @Schema(description = "同步类型(电商渠道)", example = "1") + private String syncType; + + @Schema(description = "同步店铺ID", example = "13239") + private String syncShopId; + + @Schema(description = "同步结束时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Long[] syncEndTime; + + @Schema(description = "同步开始时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Long[] syncCreateTime; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/vo/OrderSyncLogRespVO.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/vo/OrderSyncLogRespVO.java new file mode 100644 index 0000000000..57b4a220bf --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/vo/OrderSyncLogRespVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.haoka.controller.admin.ordersynclog.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; + +@Schema(description = "管理后台 - 抓单记录 Response VO") +@Data +@ExcelIgnoreUnannotated +public class OrderSyncLogRespVO { + + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "28786") + @ExcelProperty("主键ID") + private Long id; + + @Schema(description = "同步类型(电商渠道)", example = "1") + @ExcelProperty(value = "同步类型(电商渠道)", converter = DictConvert.class) + @DictFormat("haoka_order_channel") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中 + private String syncType; + + @Schema(description = "同步店铺ID", example = "13239") + @ExcelProperty("同步店铺ID") + private String syncShopId; + + @Schema(description = "同步结束时间") + @ExcelProperty("同步结束时间") + private Long syncEndTime; + + @Schema(description = "同步开始时间") + @ExcelProperty("同步开始时间") + private Long syncCreateTime; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/vo/OrderSyncLogSaveReqVO.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/vo/OrderSyncLogSaveReqVO.java new file mode 100644 index 0000000000..5d862e884e --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/controller/admin/ordersynclog/vo/OrderSyncLogSaveReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.haoka.controller.admin.ordersynclog.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; + +@Schema(description = "管理后台 - 抓单记录新增/修改 Request VO") +@Data +public class OrderSyncLogSaveReqVO { + + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "28786") + private Long id; + + @Schema(description = "同步类型(电商渠道)", example = "1") + private String syncType; + + @Schema(description = "同步店铺ID", example = "13239") + private String syncShopId; + + @Schema(description = "同步结束时间") + private Long syncEndTime; + + @Schema(description = "同步开始时间") + private Long syncCreateTime; + +} \ No newline at end of file diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/dal/dataobject/orders/OrdersDO.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/dal/dataobject/orders/OrdersDO.java index b6f61a75a1..3744a7cd3d 100644 --- a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/dal/dataobject/orders/OrdersDO.java +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/dal/dataobject/orders/OrdersDO.java @@ -326,5 +326,29 @@ public class OrdersDO extends BaseDO { * 是否加急 0或空 不加急 1 加急 */ private Integer isUrgent; + /** + * 店铺ID + */ + private String shopId; + /** + * 店铺名称 + */ + private String shopName; + /** + * 直播间ID + */ + private String roomId; + /** + * 直播间名称 + */ + private String roomName; + /** + * 销售归属 + */ + private String salesAttribution; + /** + * 销售归属名称 + */ + private String salesAttributionName; } diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/dal/dataobject/ordersynclog/OrderSyncLogDO.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/dal/dataobject/ordersynclog/OrderSyncLogDO.java new file mode 100644 index 0000000000..db491d4453 --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/dal/dataobject/ordersynclog/OrderSyncLogDO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.haoka.dal.dataobject.ordersynclog; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 抓单记录 DO + * + * @author 超级管理员 + */ +@TableName("haoka_order_sync_log") +@KeySequence("haoka_order_sync_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrderSyncLogDO extends BaseDO { + + /** + * 主键ID + */ + @TableId(type = IdType.ASSIGN_ID) + private Long id; + /** + * 同步类型(电商渠道) + * + * 枚举 {@link TODO haoka_order_channel 对应的类} + */ + private String syncType; + /** + * 同步店铺ID + */ + private String syncShopId; + /** + * 同步结束时间 + */ + private Long syncEndTime; + /** + * 同步开始时间 + */ + private Long syncCreateTime; + +} \ No newline at end of file diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/dal/mysql/ordersynclog/OrderSyncLogMapper.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/dal/mysql/ordersynclog/OrderSyncLogMapper.java new file mode 100644 index 0000000000..81962cf97d --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/dal/mysql/ordersynclog/OrderSyncLogMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.haoka.dal.mysql.ordersynclog; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.haoka.dal.dataobject.ordersynclog.OrderSyncLogDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.haoka.controller.admin.ordersynclog.vo.*; + +/** + * 抓单记录 Mapper + * + * @author 超级管理员 + */ +@Mapper +public interface OrderSyncLogMapper extends BaseMapperX { + + default PageResult selectPage(OrderSyncLogPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(OrderSyncLogDO::getSyncType, reqVO.getSyncType()) + .eqIfPresent(OrderSyncLogDO::getSyncShopId, reqVO.getSyncShopId()) + .betweenIfPresent(OrderSyncLogDO::getSyncEndTime, reqVO.getSyncEndTime()) + .betweenIfPresent(OrderSyncLogDO::getSyncCreateTime, reqVO.getSyncCreateTime()) + .betweenIfPresent(OrderSyncLogDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(OrderSyncLogDO::getCreateTime)); + } + +} \ No newline at end of file diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/schedule/DouDianOrderCatchSchdule.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/schedule/DouDianOrderCatchSchdule.java new file mode 100644 index 0000000000..57361fa825 --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/schedule/DouDianOrderCatchSchdule.java @@ -0,0 +1,109 @@ +package cn.iocoder.yudao.module.haoka.schedule; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.haoka.controller.admin.ordersynclog.vo.OrderSyncLogPageReqVO; +import cn.iocoder.yudao.module.haoka.controller.admin.ordersynclog.vo.OrderSyncLogSaveReqVO; +import cn.iocoder.yudao.module.haoka.dal.dataobject.ordersynclog.OrderSyncLogDO; +import cn.iocoder.yudao.module.haoka.service.orderCatch.OrderCatchService; +import cn.iocoder.yudao.module.haoka.service.ordersynclog.OrderSyncLogService; +import com.doudian.open.core.AccessToken; +import com.doudian.open.core.AccessTokenBuilder; +import com.doudian.open.core.GlobalConfig; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; + +/** + * 抖音抓单 + */ +@Slf4j +@Component +public class DouDianOrderCatchSchdule { + + private static final String SYNC_APP_KEY = "7381306825771091495"; // initAppKey + private static final String SYNC_APP_SECRET = "09c06553-b77c-4712-aed9-84cbfe16ca13"; // initAppSecret + /** + * 天猫 0 + * 快手 1 + * 抖音 2 + * 拼多多 3 + * 京东 4 + */ + private static final String SYNC_TYPE = "2"; // 同步类型 抖音 + private static final Long SYNC_SHOP_ID = 20811777L; // 抖店店铺id + @Resource + OrderCatchService orderCatchService; + + @Resource + private OrderSyncLogService orderSyncLogService; + /** + * 每20分钟执行一次 + */ +// @Scheduled(cron = "0 */20 * * * ?") + public void catchOrder() { + // refreshToken(); + GlobalConfig.initAppKey(SYNC_APP_KEY); + GlobalConfig.initAppSecret(SYNC_APP_SECRET); +//入参为code + AccessToken accessToken= AccessTokenBuilder.build(SYNC_SHOP_ID); + // 从数据库获取上一次同步的结束时间 + Long lastSyncTime = getLatestSyncTime(); + + // 获取当前时间 + LocalDateTime now = LocalDateTime.now(); + long currentTimestamp = now.atZone(ZoneId.systemDefault()).toEpochSecond(); + + // 如果没有同步记录,初始化为1天前 + LocalDateTime startDateTime; + if (lastSyncTime == null) { + startDateTime = now.minus(1, ChronoUnit.DAYS); + } else { + startDateTime = Instant.ofEpochSecond(lastSyncTime).atZone(ZoneId.systemDefault()).toLocalDateTime(); + } + + // 将LocalDateTime转换为秒级时间戳 + long createTimeStart = startDateTime.atZone(ZoneId.systemDefault()).toEpochSecond(); + long createTimeEnd = currentTimestamp; + orderCatchService.syncOrder(accessToken, createTimeStart, createTimeEnd); + log.info("结束-----------抖音--更新订单结束--------------------"); + } + + /** + * 从数据库获取上一次同步的结束时间 + * + * @return 上一次同步的结束时间戳 + */ + private Long getLatestSyncTime() { + // 示例代码,实际需要通过你的数据库操作类获取 + OrderSyncLogPageReqVO orderSyncLogPageReqVO = new OrderSyncLogPageReqVO(); + orderSyncLogPageReqVO.setSyncType(SYNC_TYPE); + orderSyncLogPageReqVO.setSyncShopId(String.valueOf(SYNC_SHOP_ID)); + PageResult orderSyncLogPage = orderSyncLogService.getOrderSyncLogPage(orderSyncLogPageReqVO); + Long total = orderSyncLogPage.getTotal(); + if(total>0){ + return orderSyncLogPage.getList().get(0).getSyncEndTime(); + } + return null; + } + + /** + * 保存同步记录到数据库 + * + * @param createTimeEnd 同步结束时间 + * @param createTimeStart 同步开始时间 + */ + private void saveSyncLog(long createTimeEnd,long createTimeStart) { + OrderSyncLogSaveReqVO saveReqVO = new OrderSyncLogSaveReqVO(); + saveReqVO.setSyncType(SYNC_TYPE); + saveReqVO.setSyncEndTime(createTimeEnd); + saveReqVO.setSyncCreateTime(createTimeStart); // 当前时间戳 + orderSyncLogService.createOrderSyncLog(saveReqVO); // 插入同步记录 + } +} diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/orderCatch/DouDianOrderCatchServiceImpl.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/orderCatch/DouDianOrderCatchServiceImpl.java new file mode 100644 index 0000000000..9b0f8595fa --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/orderCatch/DouDianOrderCatchServiceImpl.java @@ -0,0 +1,651 @@ +package cn.iocoder.yudao.module.haoka.service.orderCatch; + +import cn.hutool.core.collection.CollectionUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.haoka.controller.admin.onsaleproduct.vo.OnSaleProductPreOrderRespVO; +import cn.iocoder.yudao.module.haoka.controller.admin.orderCatch.po.Message; +import cn.iocoder.yudao.module.haoka.controller.admin.orderCatch.vo.OrderCatchRepVO; +import cn.iocoder.yudao.module.haoka.controller.admin.ordersynclog.vo.OrderSyncLogPageReqVO; +import cn.iocoder.yudao.module.haoka.controller.admin.ordersynclog.vo.OrderSyncLogSaveReqVO; +import cn.iocoder.yudao.module.haoka.dal.dataobject.onsaleproduct.OnSaleProductDO; +import cn.iocoder.yudao.module.haoka.dal.dataobject.orders.OrdersDO; +import cn.iocoder.yudao.module.haoka.dal.dataobject.ordersynclog.OrderSyncLogDO; +import cn.iocoder.yudao.module.haoka.dal.mysql.onsaleproduct.OnSaleProductMapper; +import cn.iocoder.yudao.module.haoka.dal.mysql.orders.OrdersMapper; +import cn.iocoder.yudao.module.haoka.service.onsaleproduct.OnSaleProductService; +import cn.iocoder.yudao.module.haoka.service.ordersynclog.OrderSyncLogService; +import cn.iocoder.yudao.module.haoka.service.ordersynclog.OrderSyncLogServiceImpl; +import cn.iocoder.yudao.module.haoka.utils.GroupListUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.doudian.open.api.order_batchDecrypt.OrderBatchDecryptRequest; +import com.doudian.open.api.order_batchDecrypt.OrderBatchDecryptResponse; +import com.doudian.open.api.order_batchDecrypt.data.DecryptInfosItem; +import com.doudian.open.api.order_batchDecrypt.data.OrderBatchDecryptData; +import com.doudian.open.api.order_batchDecrypt.param.CipherInfosItem; +import com.doudian.open.api.order_batchDecrypt.param.OrderBatchDecryptParam; +import com.doudian.open.api.order_orderDetail.OrderOrderDetailRequest; +import com.doudian.open.api.order_orderDetail.OrderOrderDetailResponse; +import com.doudian.open.api.order_orderDetail.data.OrderOrderDetailData; +import com.doudian.open.api.order_orderDetail.data.ShopOrderDetail; +import com.doudian.open.api.order_orderDetail.param.OrderOrderDetailParam; +import com.doudian.open.api.order_searchList.OrderSearchListRequest; +import com.doudian.open.api.order_searchList.OrderSearchListResponse; +import com.doudian.open.api.order_searchList.data.*; +import com.doudian.open.api.order_searchList.param.OrderSearchListParam; +import com.doudian.open.api.token_refresh.TokenRefreshRequest; +import com.doudian.open.api.token_refresh.TokenRefreshResponse; +import com.doudian.open.api.token_refresh.param.TokenRefreshParam; +import com.doudian.open.core.AccessToken; +import com.doudian.open.core.AccessTokenBuilder; +import com.doudian.open.core.GlobalConfig; +import com.doudian.open.gson.Gson; +import com.doudian.open.msg.refund_RefundAgreed.param.RefundRefundAgreedParam; +import com.doudian.open.msg.refund_RefundCreated.param.RefundRefundCreatedParam; +import com.doudian.open.msg.refund_ReturnApplyAgreed.param.RefundReturnApplyAgreedParam; +import com.doudian.open.msg.trade_TradeCanceled.param.TradeTradeCanceledParam; +import com.doudian.open.msg.trade_TradePaid.param.TradeTradePaidParam; +import com.doudian.open.msg.trade_TradePending.param.TradeTradePendingParam; +import jakarta.annotation.Resource; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Service +@Validated +public class DouDianOrderCatchServiceImpl implements OrderCatchService { + + + private static final String SYNC_APP_KEY = "7381306825771091495"; // initAppKey + private static final String SYNC_APP_SECRET = "09c06553-b77c-4712-aed9-84cbfe16ca13"; // initAppSecret + private static final String SYNC_TYPE = "2"; // 同步类型 抖店 + private static final Long SYNC_SHOP_ID = 20811777L; // 抖店店铺id + + @Resource + private OrdersMapper ordersMapper; + @Resource + private OnSaleProductMapper onSaleProductMapper; + @Resource + private OnSaleProductService onSaleProductService; + @Resource + private OrderSyncLogService orderSyncLogService; + @Override + public void syncOrder(AccessToken accessToken, long createTimeStart, long createTimeEnd) { + // 分页查询订单 + List allOrders = fetchOrders(accessToken, createTimeStart, createTimeEnd); + // 将获取的订单插入到数据库 + insertOrdersToDatabase(allOrders); + } + + /** + * 抖音消息推送订单,抓取/更新 订单 + * @param catchRepVO + */ + @Override + public void catchOrders(List catchRepVO) { + // 插入日志 + Gson gson = new Gson(); + for (Message message : catchRepVO) { + String tag = message.getTag(); + String msgId = message.getMsgId(); + Object data = message.getData(); + // 插入日志 + if("doudian_refund_RefundCreated".equals(tag)){ + // 买家发起售后申请消息 + RefundRefundCreatedParam refundRefundCreatedParam = gson.fromJson(message.getData()+"", RefundRefundCreatedParam.class); + } else if("doudian_refund_RefundAgreed".equals(tag)) { + // 同意退款消息 + RefundRefundAgreedParam refundRefundAgreedParam = gson.fromJson(message.getData()+"", RefundRefundAgreedParam.class); + } else if("doudian_refund_ReturnApplyAgreed".equals(tag)) { + // 同意退货申请消息 + RefundReturnApplyAgreedParam refundReturnApplyAgreedParam = gson.fromJson(message.getData()+"", RefundReturnApplyAgreedParam.class); + } else if("doudian_trade_TradePaid".equals(tag)) { + // 订单支付/确认消息 抓取订单 + TradeTradePaidParam tradeTradePaidParam = gson.fromJson(message.getData()+"", TradeTradePaidParam.class); + // 订单id + Long pId = tradeTradePaidParam.getPId(); +// 根据订单id查询订单详情 + OrderOrderDetailData orderDetail = orderDetail(String.valueOf(pId)); + ShopOrderDetail order = orderDetail.getShopOrderDetail(); + // 所有的订单数据 + List skuOrderList = order.getSkuOrderList(); + // 店铺信息 + Long shopId = order.getShopId(); + String shopName = order.getShopName(); + // 物流信息 + List logisticsInfo = order.getLogisticsInfo(); + /** + * 需判断订单是否存在 + * 1.不存在 --- 新增 + * 2.存在 --- 更新 + * 2.1 需更新的数据: 订单状态 退款状态 + */ + // 所有在售商品 + List onSaleProductDOS = onSaleProductMapper.selectList(new QueryWrapper().eq("deleted", 0).eq("onSale", true)); + // 所有在售商品sku + List skuList = onSaleProductDOS.stream().map(OnSaleProductDO::getSku).toList(); + // 买家备注 + String buyerWords = order.getBuyerWords(); + // 收件人电话 +// String postTel = order.getPostTel(); + String encryptPostTel = order.getEncryptPostTel(); + // 收件人姓名 +// String postReceiver = order.getPostReceiver(); + String encryptPostReceiver = order.getEncryptPostReceiver(); + // 收件人地址 + com.doudian.open.api.order_orderDetail.data.PostAddr postAddr = order.getPostAddr(); + // 省 + com.doudian.open.api.order_orderDetail.data.Province province = postAddr.getProvince(); + // 市 + com.doudian.open.api.order_orderDetail.data.City city = postAddr.getCity(); + // 区 + com.doudian.open.api.order_orderDetail.data.Town town = postAddr.getTown(); + // 街道/镇 + com.doudian.open.api.order_orderDetail.data.Street street = postAddr.getStreet(); +// String detail = postAddr.getDetail(); + String encryptDetail = postAddr.getEncryptDetail(); + //用户信息 + com.doudian.open.api.order_orderDetail.data.UserIdInfo userIdInfo = order.getUserIdInfo(); +// String idCardNo = userIdInfo.getIdCardNo(); + String encryptIdCardNo = userIdInfo.getEncryptIdCardNo(); +// String idCardName = userIdInfo.getIdCardName(); + String encryptIdCardName = userIdInfo.getEncryptIdCardName(); + List orderList = new ArrayList<>(); + List orderListAll = new ArrayList<>(); + for (com.doudian.open.api.order_orderDetail.data.SkuOrderListItem skuOrderListItem : skuOrderList) { + String orderId = skuOrderListItem.getOrderId(); + OrdersDO ordersDO = new OrdersDO(); + // 售后信息 + com.doudian.open.api.order_orderDetail.data.AfterSaleInfo afterSaleInfo = skuOrderListItem.getAfterSaleInfo(); + // 售后状态 0-售后初始化, 6-售后申请, 7-售后退货中, 27-拒绝售后申请, 12-售后成功, 28-售后失败, 11-售后已发货, 29-退货后拒绝退款, 13-售后换货商家发货, 14-售后换货用户收货, 51-取消成功, 53-逆向交易完成 + Long afterSaleStatus = afterSaleInfo.getAfterSaleStatus(); +// 1-待退款;3-退款成功; 4-退款失败;当买家发起售后后又主动取消售后,此时after_sale_status=28并且refund_status=1的状态不变,不会流转至4状态; + Long refundStatus = afterSaleInfo.getRefundStatus(); + // 商品sku 判断是否抓单 + String code = skuOrderListItem.getCode(); + if(skuList.contains(code)){ + for (OnSaleProductDO onSaleProductDO : onSaleProductDOS) { + if(onSaleProductDO.getSku().equals(code)){ + // 注入产品生产方式 记录初始产品+接口相关信息 + OnSaleProductPreOrderRespVO onSaleProductPreOrder = onSaleProductService.getOnSaleProductPreOrder(onSaleProductDO.getId()); + ordersDO.setAutoType(onSaleProductPreOrder.getParentProduct().getAutoType()); + ordersDO.setOnSaleProductId(onSaleProductPreOrder.getId()); + ordersDO.setProductId(onSaleProductPreOrder.getParentProduct().getId()); + ordersDO.setSuperiorProductConfigId(onSaleProductPreOrder.getSuperiorProductConfigRespVO().getId()); + ordersDO.setSuperiorApiId(onSaleProductPreOrder.getSuperiorApiRespVO().getId()); + } + } + // 在售商品 + ordersDO.setSupplierProductSku(code); + Long orderStatus = skuOrderListItem.getOrderStatus(); + // 1 待确认/待支付-订单创建完毕;105-已支付; 2-备货中; 101-部分发货; 3-已发货(全部发货);4- 已取消;5 已完成(已收货); + Long HaokaOrderStatus;// 号卡订单状态 + Long HaokaOrderRefundStatus;// 号卡订单退款状态 +// 解析订单状态 + if(orderStatus == 105L){ + HaokaOrderStatus = 100L; + ordersDO.setStatus(HaokaOrderStatus); + }else if(orderStatus == 101L || orderStatus == 3L){ + HaokaOrderStatus = 500L; + ordersDO.setStatus(HaokaOrderStatus); + }else { + // 更新订单退款状态 订单状态不变 + } + ordersDO.setStatusName(skuOrderListItem.getOrderStatusDesc()); + // 解析售后状态 + if(0L == afterSaleStatus){ + // 未进入售后 + HaokaOrderRefundStatus = 800L; + } else if(afterSaleStatus == 28L || refundStatus == 1L){ + // 未进入售后 + HaokaOrderRefundStatus = 800L; + } else if(refundStatus == 3L){ + // 进入售后 + HaokaOrderRefundStatus = 300L; + } else { + // 进入售后 + HaokaOrderRefundStatus = 200L; + } + ordersDO.setRefundStatus(String.valueOf(HaokaOrderRefundStatus)); + // 获取计划手机号 + for (com.doudian.open.api.order_orderDetail.data.LogisticsInfoItem logisticsInfoItem : logisticsInfo) { + for (com.doudian.open.api.order_orderDetail.data.ProductInfoItem productInfoItem : logisticsInfoItem.getProductInfo()) { + String skuOrderId = productInfoItem.getSkuOrderId(); + if(skuOrderId.equals(orderId)){ + String productName = productInfoItem.getProductName(); + ordersDO.setSupplierProductName(productName); + List skuSpecs = productInfoItem.getSkuSpecs(); + for (com.doudian.open.api.order_orderDetail.data.SkuSpecsItem skuSpec : skuSpecs) { + String name = skuSpec.getName(); + String planMobile = getPlanMobile(name); + if(planMobile != null){ + ordersDO.setPlanMobile(planMobile); + } + } + } + } + } + // 查询订单是否存在 不存在则新增,存在则更新 + List ordersDOS = ordersMapper.selectList(new QueryWrapper().eq("real_source_id", orderId).eq("deleted", 0)); + if(CollectionUtil.isNotEmpty(ordersDOS)){ + // 更新订单 + OrdersDO ordersDO1 = ordersDOS.get(0); + ordersDO1.setRefundStatus(String.valueOf(HaokaOrderRefundStatus)); + ordersMapper.updateById(ordersDO1); + }else { + // 新增订单 + ordersDO.setShopId(String.valueOf(shopId)); + ordersDO.setShopName(shopName); + ordersDO.setRoomId(skuOrderListItem.getRoomIdStr()); + // 真实订单 + ordersDO.setRealSourceId(orderId); + ordersDO.setSourceId(orderId); + // 买家备注 + ordersDO.setBuyerMemo(buyerWords); + //证件信息 + // ordersDO.setIdCardNum(idCardNo); + ordersDO.setEncryptIdCardNum(encryptIdCardNo); + // ordersDO.setIdCardName(idCardName); + ordersDO.setEncryptIdCardName(encryptIdCardName); + // 收件人信息 + // ordersDO.setAddressMobile(postTel); + ordersDO.setEncryptAddressMobile(encryptPostTel); + // ordersDO.setAddressName(postReceiver); + ordersDO.setEncryptAddressName(encryptPostReceiver); + // 收件人地址 省 + ordersDO.setAddressProvince(province.getName()); + ordersDO.setAddressProvinceCode(province.getId()); + // 市 + ordersDO.setAddressCity(city.getName()); + ordersDO.setAddressCityCode(city.getId()); + // 区 + ordersDO.setAddressDistrict(town.getName()); + ordersDO.setAddressDistrictCode(town.getId()); + // 街道/镇 + ordersDO.setTown(street.getName()); + // 详细地址 + // ordersDO.setAddress(detail); + ordersDO.setEncryptAddress(encryptDetail); + orderList.add(ordersDO); + } + + } + } + orderListAll.addAll(orderList); + ordersMapper.insertBatch(orderList); + // 执行解密,解密后更新数据库 + for (List ordersDOS : GroupListUtil.groupList(orderListAll, 50)) { + batchDecryptOrderAndUpdate(ordersDOS); + } + } else if("doudian_trade_TradeCanceled".equals(tag)) { + // 订单取消消息 + TradeTradeCanceledParam tradeTradeCanceledParam = gson.fromJson(message.getData()+"", TradeTradeCanceledParam.class); + } else if("doudian_trade_TradePending".equals(tag)) { + // 订单已支付待处理 + TradeTradePendingParam tradeTradePendingParam = gson.fromJson(message.getData()+"", TradeTradePendingParam.class); + } else { + // 未接入的消息类型 + } + } + + } + + + /** + * 将订单数据插入到数据库 + * @param orders 订单数据 + */ + private void insertOrdersToDatabase(List orders) { + // 所有在售商品 + List onSaleProductDOS = onSaleProductMapper.selectList(new QueryWrapper().eq("deleted", 0).eq("onSale", true)); + // 所有在售商品sku + List skuList = onSaleProductDOS.stream().map(OnSaleProductDO::getSku).toList(); + //数据分片处理 分片理由 每次最多徐解密50条数据,一条订单解密5个数据,10个订单解密50条 + List orderListAll = new ArrayList<>(); + List> orderGroupList = GroupListUtil.groupList(orders, 10); +// orderGroupList 的 size 最大为10 + for (List orderListItems : orderGroupList) { + List orderList = new ArrayList<>(); + for (ShopOrderListItem order : orderListItems) { + // 抖音订单id +// String orderId = order.getOrderId(); + // 买家备注 + String buyerWords = order.getBuyerWords(); + // 店铺id + Long shopId = order.getShopId(); + // 店铺名称 + String shopName = order.getShopName(); + // 收件人电话 +// String postTel = order.getPostTel(); + String encryptPostTel = order.getEncryptPostTel(); + // 收件人姓名 +// String postReceiver = order.getPostReceiver(); + String encryptPostReceiver = order.getEncryptPostReceiver(); + // 收件人地址 + PostAddr postAddr = order.getPostAddr(); + // 省 + Province province = postAddr.getProvince(); + // 市 + City city = postAddr.getCity(); + // 区 + Town town = postAddr.getTown(); + // 街道/镇 + Street street = postAddr.getStreet(); +// String detail = postAddr.getDetail(); + String encryptDetail = postAddr.getEncryptDetail(); + //用户信息 + UserIdInfo userIdInfo = order.getUserIdInfo(); +// String idCardNo = userIdInfo.getIdCardNo(); + String encryptIdCardNo = userIdInfo.getEncryptIdCardNo(); +// String idCardName = userIdInfo.getIdCardName(); + String encryptIdCardName = userIdInfo.getEncryptIdCardName(); + // 商品信息 + List skuOrderList = order.getSkuOrderList(); + List logisticsInfo = order.getLogisticsInfo(); + + for (SkuOrderListItem skuOrderListItem : skuOrderList) { + String orderId = skuOrderListItem.getOrderId(); + OrdersDO ordersDO = new OrdersDO(); + // 售后信息 + AfterSaleInfo afterSaleInfo = skuOrderListItem.getAfterSaleInfo(); + // 售后状态 0-售后初始化, 6-售后申请, 7-售后退货中, 27-拒绝售后申请, 12-售后成功, 28-售后失败, 11-售后已发货, 29-退货后拒绝退款, 13-售后换货商家发货, 14-售后换货用户收货, 51-取消成功, 53-逆向交易完成 + Long afterSaleStatus = afterSaleInfo.getAfterSaleStatus(); +// 1-待退款;3-退款成功; 4-退款失败;当买家发起售后后又主动取消售后,此时after_sale_status=28并且refund_status=1的状态不变,不会流转至4状态; + Long refundStatus = afterSaleInfo.getRefundStatus(); + // 商品sku 判断是否抓单 + String code = skuOrderListItem.getCode(); + if(skuList.contains(code)){ + for (OnSaleProductDO onSaleProductDO : onSaleProductDOS) { + if(onSaleProductDO.getSku().equals(code)){ + // 注入产品生产方式 记录初始产品+接口相关信息 + OnSaleProductPreOrderRespVO onSaleProductPreOrder = onSaleProductService.getOnSaleProductPreOrder(onSaleProductDO.getId()); + ordersDO.setAutoType(onSaleProductPreOrder.getParentProduct().getAutoType()); + ordersDO.setOnSaleProductId(onSaleProductPreOrder.getId()); + ordersDO.setProductId(onSaleProductPreOrder.getParentProduct().getId()); + ordersDO.setSuperiorProductConfigId(onSaleProductPreOrder.getSuperiorProductConfigRespVO().getId()); + ordersDO.setSuperiorApiId(onSaleProductPreOrder.getSuperiorApiRespVO().getId()); + } + } + // 在售商品 + ordersDO.setSupplierProductSku(code); + Long orderStatus = skuOrderListItem.getOrderStatus(); + // 1 待确认/待支付-订单创建完毕;105-已支付; 2-备货中; 101-部分发货; 3-已发货(全部发货);4- 已取消;5 已完成(已收货); + Long HaokaOrderStatus;// 号卡订单状态 + Long HaokaOrderRefundStatus;// 号卡订单退款状态 +// 解析订单状态 + if(orderStatus == 105L){ + HaokaOrderStatus = 100L; + ordersDO.setStatus(HaokaOrderStatus); + }else if(orderStatus == 101L || orderStatus == 3L){ + HaokaOrderStatus = 500L; + ordersDO.setStatus(HaokaOrderStatus); + }else { + // 更新订单退款状态 订单状态不变 + } + // 解析售后状态 + if(0L == afterSaleStatus){ + // 未进入售后 + HaokaOrderRefundStatus = 800L; + } else if(afterSaleStatus == 28L || refundStatus == 1L){ + // 未进入售后 + HaokaOrderRefundStatus = 800L; + } else if(refundStatus == 3L){ + // 进入售后 + HaokaOrderRefundStatus = 300L; + } else { + // 进入售后 + HaokaOrderRefundStatus = 200L; + } + ordersDO.setRefundStatus(String.valueOf(HaokaOrderRefundStatus)); + ordersDO.setStatusName(skuOrderListItem.getOrderStatusDesc()); + // 获取计划手机号 + for (LogisticsInfoItem logisticsInfoItem : logisticsInfo) { + for (ProductInfoItem productInfoItem : logisticsInfoItem.getProductInfo()) { + String skuOrderId = productInfoItem.getSkuOrderId(); + if(skuOrderId.equals(orderId)){ + String productName = productInfoItem.getProductName(); + ordersDO.setSupplierProductName(productName); + List skuSpecs = productInfoItem.getSkuSpecs(); + for (SkuSpecsItem skuSpec : skuSpecs) { + String name = skuSpec.getName(); + String planMobile = getPlanMobile(name); + if(planMobile != null){ + ordersDO.setPlanMobile(planMobile); + } + } + } + } + } + // 查询订单是否存在 不存在则新增,存在则更新 + List ordersDOS = ordersMapper.selectList(new QueryWrapper().eq("real_source_id", orderId).eq("deleted", 0)); + if(CollectionUtil.isNotEmpty(ordersDOS)){ + // 更新订单 + OrdersDO ordersDO1 = ordersDOS.get(0); + ordersDO1.setRefundStatus(String.valueOf(HaokaOrderRefundStatus)); + ordersMapper.updateById(ordersDO1); + }else { + // 新增订单 + ordersDO.setShopId(String.valueOf(shopId)); + ordersDO.setShopName(shopName); + // 真实订单 + ordersDO.setRealSourceId(orderId); + ordersDO.setSourceId(orderId); + // 买家备注 + ordersDO.setBuyerMemo(buyerWords); + //证件信息 + // ordersDO.setIdCardNum(idCardNo); + ordersDO.setEncryptIdCardNum(encryptIdCardNo); + // ordersDO.setIdCardName(idCardName); + ordersDO.setEncryptIdCardName(encryptIdCardName); + // 收件人信息 + // ordersDO.setAddressMobile(postTel); + ordersDO.setEncryptAddressMobile(encryptPostTel); + // ordersDO.setAddressName(postReceiver); + ordersDO.setEncryptAddressName(encryptPostReceiver); + // 收件人地址 省 + ordersDO.setAddressProvince(province.getName()); + ordersDO.setAddressProvinceCode(province.getId()); + // 市 + ordersDO.setAddressCity(city.getName()); + ordersDO.setAddressCityCode(city.getId()); + // 区 + ordersDO.setAddressDistrict(town.getName()); + ordersDO.setAddressDistrictCode(town.getId()); + // 街道/镇 + ordersDO.setTown(street.getName()); + // 详细地址 + // ordersDO.setAddress(detail); + ordersDO.setEncryptAddress(encryptDetail); + orderList.add(ordersDO); + } + + } + } + } + orderListAll.addAll(orderList); + ordersMapper.insertBatch(orderList); + } + // 执行解密,解密后更新数据库 + for (List ordersDOS : GroupListUtil.groupList(orderListAll, 50)) { + batchDecryptOrderAndUpdate(ordersDOS); + } + } + private CipherInfosItem createCipherItem(String cipherText, String authId) { + CipherInfosItem item = new CipherInfosItem(); + item.setCipherText(cipherText); + item.setAuthId(authId); + return item; + } + private void updateOrderFields(OrdersDO order, String cipherText, String decryptText) { + // 检查并更新每个加密字段 + if (cipherText.equals(order.getEncryptAddress())) { + order.setEncryptAddress(decryptText); // 更新为解密后的值 + } else if (cipherText.equals(order.getEncryptIdCardName())) { + order.setEncryptIdCardName(decryptText); + } else if (cipherText.equals(order.getEncryptAddressName())) { + order.setEncryptAddressName(decryptText); + } else if (cipherText.equals(order.getEncryptIdCardNum())) { + order.setEncryptIdCardNum(decryptText); + } else if (cipherText.equals(order.getEncryptAddressMobile())) { + order.setEncryptAddressMobile(decryptText); + } + } + private void batchDecryptOrderAndUpdate(List orderList) { + List cipherInfos = new ArrayList<>(); + for (OrdersDO ordersDO : orderList) { + // 构建 CipherInfosItem 列表 + cipherInfos.add(createCipherItem(ordersDO.getEncryptAddress(), ordersDO.getRealSourceId())); + cipherInfos.add(createCipherItem(ordersDO.getEncryptIdCardName(), ordersDO.getRealSourceId())); + cipherInfos.add(createCipherItem(ordersDO.getEncryptAddressName(), ordersDO.getRealSourceId())); + cipherInfos.add(createCipherItem(ordersDO.getEncryptIdCardNum(), ordersDO.getRealSourceId())); + cipherInfos.add(createCipherItem(ordersDO.getEncryptAddressMobile(), ordersDO.getRealSourceId())); + + } + List objects = batchDecrypt(cipherInfos); + for (DecryptInfosItem object : objects) { + String authId = object.getAuthId(); + String decryptText = object.getDecryptText(); + String cipherText = object.getCipherText(); + + for (OrdersDO ordersDO : orderList) { + if (ordersDO.getRealSourceId().equals(authId)) { + // 将解密后的字段替换到 order 中 + updateOrderFields(ordersDO, cipherText, decryptText); + } + } + } + ordersMapper.updateBatch(orderList); + } + + /** + * 使用正则表达式获取手机号 + * @param skuName + * @return + */ + private String getPlanMobile(String skuName) { + // 去除空格 + String noSpace = StringUtils.deleteWhitespace(skuName); + String pattern = "(?<=\\/)\\d{11}"; + Pattern compile = Pattern.compile(pattern); + Matcher matcher = compile.matcher(noSpace); + if(matcher.find()){ +// 找到匹配手机号 + return matcher.group(1); + }else { + return null; + } + } + + + /** + * 分页查询订单 + * @param accessToken 访问令牌 + * @param createTimeStart 创建时间起始 + * @param createTimeEnd 创建时间结束 + * @return 所有订单数据 + */ + private List fetchOrders(AccessToken accessToken, long createTimeStart, long createTimeEnd) { + OrderSearchListRequest request = new OrderSearchListRequest(); + OrderSearchListParam param = request.getParam(); +// param.setProduct("3473196049974326153"); +// param.setBType(2L); + param.setAfterSaleStatusDesc("refund_success"); +// param.setTrackingNo("435435"); +// param.setPresellType(0L); +// param.setOrderType(1L); + param.setCreateTimeStart(createTimeStart); + param.setCreateTimeEnd(createTimeEnd); +// param.setAbnormalOrder(1L); +// param.setTradeType(1L); +// param.setUpdateTimeStart(1617355413L); +// param.setUpdateTimeEnd(1617355413L); + param.setSize(100L); + param.setPage(0L); + param.setOrderBy("create_time"); + param.setOrderAsc(false); +// param.setFulfilStatus("no_accept"); + + List allOrders = new ArrayList<>(); + + while (true) { + try { + OrderSearchListResponse response = request.execute(accessToken); + OrderSearchListData data = response.getData(); + List shopOrderList = data.getShopOrderList(); + Long total = data.getTotal(); + Long size = data.getSize(); + Long currentPage = data.getPage(); + allOrders.addAll(shopOrderList); + + if (currentPage * size >= total) { + break; + } + + param.setPage(++currentPage); + } catch (Exception e) { +// do nothing + break; + } + } + return allOrders; + } + + /** + * 批量解密接口 + * @param cipherInfos 待解密数据 一次性最多50条 + * @return + */ + private List batchDecrypt(List cipherInfos){ + GlobalConfig.initAppKey(SYNC_APP_KEY); + GlobalConfig.initAppSecret(SYNC_APP_SECRET); +//入参为code + AccessToken accessToken= AccessTokenBuilder.build(SYNC_SHOP_ID); + OrderBatchDecryptRequest request = new OrderBatchDecryptRequest(); + OrderBatchDecryptParam param = request.getParam(); + param.setCipherInfos(cipherInfos); + OrderBatchDecryptResponse response = request.execute(accessToken); + OrderBatchDecryptData data = response.getData(); + List decryptInfos = data.getDecryptInfos(); + return decryptInfos; + } + + + public OrderOrderDetailData orderDetail(String shopOrderId) { + GlobalConfig.initAppKey(SYNC_APP_KEY); + GlobalConfig.initAppSecret(SYNC_APP_SECRET); +//入参为code + AccessToken accessToken= AccessTokenBuilder.build(SYNC_SHOP_ID); + OrderOrderDetailRequest request = new OrderOrderDetailRequest(); + OrderOrderDetailParam param = request.getParam(); + param.setShopOrderId(shopOrderId); + OrderOrderDetailResponse response = request.execute(accessToken); + return response.getData(); + } + public void refreshToken() { + //设置appKey和appSecret,全局设置一次 + GlobalConfig.initAppKey("7381306825771091495"); + GlobalConfig.initAppSecret("09c06553-b77c-4712-aed9-84cbfe16ca13"); +//入参为code + AccessToken accessToken= AccessTokenBuilder.build(20811777L); + String refreshToken = accessToken.getRefreshToken();//16dde1a3-2d6f-4946-aef2-afbd29d2eb92是code + TokenRefreshRequest request = new TokenRefreshRequest(); + TokenRefreshParam param = request.getParam(); + param.setRefreshToken(refreshToken); + param.setGrantType("refresh_token"); + TokenRefreshResponse response = request.execute(accessToken); + String refreshToken1 = response.getData().getRefreshToken(); + System.out.println(response); + } + + +} diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/orderCatch/orderCatchService.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/orderCatch/orderCatchService.java new file mode 100644 index 0000000000..81c5bae621 --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/orderCatch/orderCatchService.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.haoka.service.orderCatch; + +import cn.iocoder.yudao.module.haoka.controller.admin.orderCatch.po.Message; +import cn.iocoder.yudao.module.haoka.controller.admin.orderCatch.vo.OrderCatchRepVO; +import com.doudian.open.core.AccessToken; + +import java.util.List; + +public interface OrderCatchService { + /** + * 查询订单列表 + */ + void syncOrder(AccessToken accessToken, long createTimeStart, long createTimeEnd); + + void catchOrders(List catchRepVO); +} diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/orders/OrdersServiceImpl.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/orders/OrdersServiceImpl.java index d206dcd12d..9dc4291b59 100644 --- a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/orders/OrdersServiceImpl.java +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/orders/OrdersServiceImpl.java @@ -114,7 +114,7 @@ public class OrdersServiceImpl extends ServiceImpl imple OnSaleProductPreOrderRespVO onSaleProductPreOrder = onSaleProductService.getOnSaleProductPreOrder(createReqVO.getOnSaleProductId()); orders.setAutoType(onSaleProductPreOrder.getParentProduct().getAutoType()); orders.setOnSaleProductId(onSaleProductPreOrder.getId()); - orders.setProducerId(onSaleProductPreOrder.getParentProduct().getId()); + orders.setProductId(onSaleProductPreOrder.getParentProduct().getId()); orders.setSuperiorProductConfigId(onSaleProductPreOrder.getSuperiorProductConfigRespVO().getId()); orders.setSuperiorApiId(onSaleProductPreOrder.getSuperiorApiRespVO().getId()); // 订单就绪 diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/ordersynclog/OrderSyncLogService.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/ordersynclog/OrderSyncLogService.java new file mode 100644 index 0000000000..ee5903444e --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/ordersynclog/OrderSyncLogService.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.haoka.service.ordersynclog; + +import java.util.*; +import jakarta.validation.*; +import cn.iocoder.yudao.module.haoka.controller.admin.ordersynclog.vo.*; +import cn.iocoder.yudao.module.haoka.dal.dataobject.ordersynclog.OrderSyncLogDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * 抓单记录 Service 接口 + * + * @author 超级管理员 + */ +public interface OrderSyncLogService { + + /** + * 创建抓单记录 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createOrderSyncLog(@Valid OrderSyncLogSaveReqVO createReqVO); + + /** + * 更新抓单记录 + * + * @param updateReqVO 更新信息 + */ + void updateOrderSyncLog(@Valid OrderSyncLogSaveReqVO updateReqVO); + + /** + * 删除抓单记录 + * + * @param id 编号 + */ + void deleteOrderSyncLog(Long id); + + /** + * 获得抓单记录 + * + * @param id 编号 + * @return 抓单记录 + */ + OrderSyncLogDO getOrderSyncLog(Long id); + + /** + * 获得抓单记录分页 + * + * @param pageReqVO 分页查询 + * @return 抓单记录分页 + */ + PageResult getOrderSyncLogPage(OrderSyncLogPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/ordersynclog/OrderSyncLogServiceImpl.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/ordersynclog/OrderSyncLogServiceImpl.java new file mode 100644 index 0000000000..d106d23daf --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/service/ordersynclog/OrderSyncLogServiceImpl.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.haoka.service.ordersynclog; + +import org.springframework.stereotype.Service; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import cn.iocoder.yudao.module.haoka.controller.admin.ordersynclog.vo.*; +import cn.iocoder.yudao.module.haoka.dal.dataobject.ordersynclog.OrderSyncLogDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; + +import cn.iocoder.yudao.module.haoka.dal.mysql.ordersynclog.OrderSyncLogMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.haoka.enums.ErrorCodeConstants.*; + +/** + * 抓单记录 Service 实现类 + * + * @author 超级管理员 + */ +@Service +@Validated +public class OrderSyncLogServiceImpl implements OrderSyncLogService { + + @Resource + private OrderSyncLogMapper orderSyncLogMapper; + + @Override + public Long createOrderSyncLog(OrderSyncLogSaveReqVO createReqVO) { + // 插入 + OrderSyncLogDO orderSyncLog = BeanUtils.toBean(createReqVO, OrderSyncLogDO.class); + orderSyncLogMapper.insert(orderSyncLog); + // 返回 + return orderSyncLog.getId(); + } + + @Override + public void updateOrderSyncLog(OrderSyncLogSaveReqVO updateReqVO) { + // 校验存在 + validateOrderSyncLogExists(updateReqVO.getId()); + // 更新 + OrderSyncLogDO updateObj = BeanUtils.toBean(updateReqVO, OrderSyncLogDO.class); + orderSyncLogMapper.updateById(updateObj); + } + + @Override + public void deleteOrderSyncLog(Long id) { + // 校验存在 + validateOrderSyncLogExists(id); + // 删除 + orderSyncLogMapper.deleteById(id); + } + + private void validateOrderSyncLogExists(Long id) { + if (orderSyncLogMapper.selectById(id) == null) { + throw exception(ORDER_SYNC_LOG_NOT_EXISTS); + } + } + + @Override + public OrderSyncLogDO getOrderSyncLog(Long id) { + return orderSyncLogMapper.selectById(id); + } + + @Override + public PageResult getOrderSyncLogPage(OrderSyncLogPageReqVO pageReqVO) { + return orderSyncLogMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/utils/GroupListUtil.java b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/utils/GroupListUtil.java new file mode 100644 index 0000000000..72e3d02144 --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/java/cn/iocoder/yudao/module/haoka/utils/GroupListUtil.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.haoka.utils; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author xiongxiong + * @description: 数组分片工具 + * @date 2024/12/30 + */ +public class GroupListUtil { + public static List> groupList(List originalList, int groupSize) { + if (groupSize <= 0) { + throw new IllegalArgumentException("Group size must be positive."); + } + List> result = new ArrayList<>(); + int size = originalList.size(); + for (int i = 0; i < size; i += groupSize) { + int endIndex = i + groupSize; + if (endIndex > size) { + endIndex = size; + } + List sub = new ArrayList<>(originalList.subList(i, endIndex)); + result.add(sub); + } + return result; + } +} diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/main/resources/mapper/ordersynclog/OrderSyncLogMapper.xml b/yudao-module-haoka/yudao-module-haoka-biz/src/main/resources/mapper/ordersynclog/OrderSyncLogMapper.xml new file mode 100644 index 0000000000..1b20409c68 --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/main/resources/mapper/ordersynclog/OrderSyncLogMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/test/java/cn/iocoder/yudao/module/haoka/service/orderCatch/DouDianOrderCatchServiceImplTest.java b/yudao-module-haoka/yudao-module-haoka-biz/src/test/java/cn/iocoder/yudao/module/haoka/service/orderCatch/DouDianOrderCatchServiceImplTest.java new file mode 100644 index 0000000000..62afc95aa5 --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/test/java/cn/iocoder/yudao/module/haoka/service/orderCatch/DouDianOrderCatchServiceImplTest.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.haoka.service.orderCatch; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.haoka.controller.admin.orderCatch.po.Message; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.doudian.open.api.order_orderDetail.data.OrderOrderDetailData; +import com.doudian.open.gson.Gson; +import com.doudian.open.msg.refund_RefundCreated.param.RefundRefundCreatedParam; +import jakarta.annotation.Resource; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import java.util.List; + +@Import(DouDianOrderCatchServiceImpl.class) +public class DouDianOrderCatchServiceImplTest extends BaseDbUnitTest { + @Resource + private DouDianOrderCatchServiceImpl orderCatchService; + @Test + public void syncOrder() { +// long createTimeStart, long createTimeEnd +// orderCatchService.syncOrder(); + } + + @Test + public void testOrderDetail() { + // 创建 DouDianOrderCatchServiceImpl 对象 + DouDianOrderCatchServiceImpl service = new DouDianOrderCatchServiceImpl(); + + // 模拟传入的 shopOrderId + String shopOrderId = "6939514703116113670"; + + // 调用 orderDetail 方法 + OrderOrderDetailData data = service.orderDetail(shopOrderId); + + // 进行断言,检查返回的数据是否符合预期 + System.out.println(data); + // 可以根据具体的业务逻辑添加更多的断言 + } + + @Test + public void testOrderDetail1() { +String orderString = "[{\"tag\":\"xxx\",\"msgId\":\"0443477XXXXXXX48874::xxx:1618990587:6837374XXXXXXX89128\",\"data\":{\"aftersale_id\":7000893114000949000,\"aftersale_status\":6,\"aftersale_type\":2,\"apply_time\":1630022518,\"p_id\":4835804142146757000,\"reason_code\":1,\"refund_amount\":8900,\"refund_post_amount\":0,\"refund_voucher_num\":0,\"return_book_info\":{\"encrypt_addr\":\"北京市海淀区海淀街道海淀街道海淀大街x号xx大厦x楼xxx室\",\"send_type\":1,\"time_begin\":\"09:00\",\"time_end\":\"11:00\"},\"s_id\":4835804142146757000,\"shop_id\":10437917,\"update_time\":\"2022-09-02T10:27:50+08:00\"}}]"; + Gson gson = new Gson(); + List parse = JSON.parseArray(orderString, Message.class); + for (Message message : parse) { + RefundRefundCreatedParam refundRefundCreatedParam = gson.fromJson(message.getData()+"", RefundRefundCreatedParam.class); + System.out.println(); + } + } + + +} diff --git a/yudao-module-haoka/yudao-module-haoka-biz/src/test/java/cn/iocoder/yudao/module/haoka/service/ordersynclog/OrderSyncLogServiceImplTest.java b/yudao-module-haoka/yudao-module-haoka-biz/src/test/java/cn/iocoder/yudao/module/haoka/service/ordersynclog/OrderSyncLogServiceImplTest.java new file mode 100644 index 0000000000..331b0ab01d --- /dev/null +++ b/yudao-module-haoka/yudao-module-haoka-biz/src/test/java/cn/iocoder/yudao/module/haoka/service/ordersynclog/OrderSyncLogServiceImplTest.java @@ -0,0 +1,146 @@ +package cn.iocoder.yudao.module.haoka.service.ordersynclog; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import jakarta.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.haoka.controller.admin.ordersynclog.vo.*; +import cn.iocoder.yudao.module.haoka.dal.dataobject.ordersynclog.OrderSyncLogDO; +import cn.iocoder.yudao.module.haoka.dal.mysql.ordersynclog.OrderSyncLogMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.haoka.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link OrderSyncLogServiceImpl} 的单元测试类 + * + * @author 超级管理员 + */ +@Import(OrderSyncLogServiceImpl.class) +public class OrderSyncLogServiceImplTest extends BaseDbUnitTest { + + @Resource + private OrderSyncLogServiceImpl orderSyncLogService; + + @Resource + private OrderSyncLogMapper orderSyncLogMapper; + + @Test + public void testCreateOrderSyncLog_success() { + // 准备参数 + OrderSyncLogSaveReqVO createReqVO = randomPojo(OrderSyncLogSaveReqVO.class).setId(null); + + // 调用 + Long orderSyncLogId = orderSyncLogService.createOrderSyncLog(createReqVO); + // 断言 + assertNotNull(orderSyncLogId); + // 校验记录的属性是否正确 + OrderSyncLogDO orderSyncLog = orderSyncLogMapper.selectById(orderSyncLogId); + assertPojoEquals(createReqVO, orderSyncLog, "id"); + } + + @Test + public void testUpdateOrderSyncLog_success() { + // mock 数据 + OrderSyncLogDO dbOrderSyncLog = randomPojo(OrderSyncLogDO.class); + orderSyncLogMapper.insert(dbOrderSyncLog);// @Sql: 先插入出一条存在的数据 + // 准备参数 + OrderSyncLogSaveReqVO updateReqVO = randomPojo(OrderSyncLogSaveReqVO.class, o -> { + o.setId(dbOrderSyncLog.getId()); // 设置更新的 ID + }); + + // 调用 + orderSyncLogService.updateOrderSyncLog(updateReqVO); + // 校验是否更新正确 + OrderSyncLogDO orderSyncLog = orderSyncLogMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, orderSyncLog); + } + + @Test + public void testUpdateOrderSyncLog_notExists() { + // 准备参数 + OrderSyncLogSaveReqVO updateReqVO = randomPojo(OrderSyncLogSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> orderSyncLogService.updateOrderSyncLog(updateReqVO), ORDER_SYNC_LOG_NOT_EXISTS); + } + + @Test + public void testDeleteOrderSyncLog_success() { + // mock 数据 + OrderSyncLogDO dbOrderSyncLog = randomPojo(OrderSyncLogDO.class); + orderSyncLogMapper.insert(dbOrderSyncLog);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbOrderSyncLog.getId(); + + // 调用 + orderSyncLogService.deleteOrderSyncLog(id); + // 校验数据不存在了 + assertNull(orderSyncLogMapper.selectById(id)); + } + + @Test + public void testDeleteOrderSyncLog_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> orderSyncLogService.deleteOrderSyncLog(id), ORDER_SYNC_LOG_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetOrderSyncLogPage() { + // mock 数据 + OrderSyncLogDO dbOrderSyncLog = randomPojo(OrderSyncLogDO.class, o -> { // 等会查询到 + o.setSyncType(null); + o.setSyncShopId(null); + o.setSyncEndTime(null); + o.setSyncCreateTime(null); + o.setCreateTime(null); + }); + orderSyncLogMapper.insert(dbOrderSyncLog); + // 测试 syncType 不匹配 + orderSyncLogMapper.insert(cloneIgnoreId(dbOrderSyncLog, o -> o.setSyncType(null))); + // 测试 syncShopId 不匹配 + orderSyncLogMapper.insert(cloneIgnoreId(dbOrderSyncLog, o -> o.setSyncShopId(null))); + // 测试 syncEndTime 不匹配 + orderSyncLogMapper.insert(cloneIgnoreId(dbOrderSyncLog, o -> o.setSyncEndTime(null))); + // 测试 syncCreateTime 不匹配 + orderSyncLogMapper.insert(cloneIgnoreId(dbOrderSyncLog, o -> o.setSyncCreateTime(null))); + // 测试 createTime 不匹配 + orderSyncLogMapper.insert(cloneIgnoreId(dbOrderSyncLog, o -> o.setCreateTime(null))); + // 准备参数 + OrderSyncLogPageReqVO reqVO = new OrderSyncLogPageReqVO(); + reqVO.setSyncType(null); + reqVO.setSyncShopId(null); +// reqVO.setSyncEndTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); +// reqVO.setSyncCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = orderSyncLogService.getOrderSyncLogPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbOrderSyncLog, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/yudao-server/src/main/resources/db/migration/V5.0.17__order_update_table_add_shop.sql b/yudao-server/src/main/resources/db/migration/V5.0.17__order_update_table_add_shop.sql new file mode 100644 index 0000000000..ec4469fa4c --- /dev/null +++ b/yudao-server/src/main/resources/db/migration/V5.0.17__order_update_table_add_shop.sql @@ -0,0 +1,9 @@ +-- 订单新增参数 +delete from haoka_orders; +ALTER TABLE haoka_orders + ADD COLUMN shop_id varchar(50) COMMENT '店铺ID' AFTER is_urgent, + ADD COLUMN shop_name varchar(50) COMMENT '店铺名称' AFTER shop_id, + ADD COLUMN room_id varchar(50) COMMENT '直播间ID' AFTER shop_name, + ADD COLUMN room_name varchar(50) COMMENT '直播间名称' AFTER room_id, + ADD COLUMN sales_attribution varchar(50) COMMENT '销售归属' AFTER room_name, + ADD COLUMN sales_attribution_name varchar(50) COMMENT '销售归属名称' AFTER sales_attribution; diff --git a/yudao-server/src/main/resources/db/migration/V6.0.1__order_catch_log.sql b/yudao-server/src/main/resources/db/migration/V6.0.1__order_catch_log.sql new file mode 100644 index 0000000000..8800c5c6e6 --- /dev/null +++ b/yudao-server/src/main/resources/db/migration/V6.0.1__order_catch_log.sql @@ -0,0 +1,70 @@ +-- 菜单 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status, component_name +) +VALUES ( + '抓单记录管理', '', 2, 0, 3016, + 'order-sync-log', '', 'haoka/ordersynclog/index', 0, 'OrderSyncLog' +); + +-- 按钮父菜单ID +-- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码 +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '抓单记录查询', 'haoka:order-sync-log:query', 3, 1, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '抓单记录创建', 'haoka:order-sync-log:create', 3, 2, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '抓单记录更新', 'haoka:order-sync-log:update', 3, 3, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '抓单记录删除', 'haoka:order-sync-log:delete', 3, 4, @parentId, + '', '', '', 0 +); +INSERT INTO system_menu( + name, permission, type, sort, parent_id, + path, icon, component, status +) +VALUES ( + '抓单记录导出', 'haoka:order-sync-log:export', 3, 5, @parentId, + '', '', '', 0 +); +CREATE TABLE `haoka_order_sync_log` ( + `id` bigint(20) NOT NULL COMMENT '主键ID', + `sync_type` varchar(50) DEFAULT NULL COMMENT '同步类型(电商渠道)', + `sync_shop_id` varchar(50) DEFAULT NULL COMMENT '同步店铺ID', + `sync_end_time` bigint(20) DEFAULT NULL COMMENT '同步结束时间', + `sync_create_time` bigint(20) DEFAULT NULL COMMENT '同步开始时间', + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `tenant_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '租户编号', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='抓单记录表'; +