From 69a68e55317f7da690ceb86a26498f3ff489f155 Mon Sep 17 00:00:00 2001 From: Gauthier LO Date: Wed, 14 Jun 2023 11:37:39 +0200 Subject: [PATCH] feat : new pages (sav_refund, shipping_calculation, billable_orders_breakdown), warehouses implementation --- .../base/controller/JeecgController.java | 2 +- .../controller/admin/ClientController.java | 16 ++ .../LogisticChannelController.java | 6 +- .../shippingInvoice/InvoiceController.java | 26 ++- .../modules/business/domain/api/ScanType.java | 3 +- .../domain/api/cmk/CMKParcelDetail.java | 28 +++ .../domain/api/cmk/CMKParcelTrace.java | 221 ++++++++++++++++++ .../domain/api/cmk/CMKParcelTraceData.java | 46 ++++ .../business/domain/api/cmk/CMKRequest.java | 56 +++++ .../business/domain/api/cmk/CMKResponse.java | 37 +++ .../api/mabang/doSearchSkuList/SkuData.java | 2 +- .../business/domain/job/MabangSkuJob.java | 165 ++++++++----- .../ShippingInvoiceFactory.java | 122 ++++++---- .../business/entity/LogisticChannel.java | 25 +- .../modules/business/entity/SavRefund.java | 5 +- .../mapper/LogisticChannelPriceMapper.java | 10 +- .../business/mapper/PlatformOrderMapper.java | 19 +- .../mapper/xml/LogisticChannelPriceMapper.xml | 22 +- .../mapper/xml/PlatformOrderMapper.xml | 42 +++- .../service/ILogisticChannelService.java | 4 +- .../service/IPlatformOrderService.java | 6 +- .../PlatformOrderShippingInvoiceService.java | 7 +- .../impl/LogisticChannelPriceServiceImpl.java | 7 +- .../impl/LogisticChannelServiceImpl.java | 8 +- .../impl/PlatformOrderServiceImpl.java | 12 +- .../business/vo/ShippingInvoiceParam.java | 17 +- .../src/main/resources/application-prod.yml | 16 +- 27 files changed, 747 insertions(+), 183 deletions(-) create mode 100644 jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKParcelDetail.java create mode 100644 jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKParcelTrace.java create mode 100644 jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKParcelTraceData.java create mode 100644 jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKRequest.java create mode 100644 jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKResponse.java diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java index 3bb08f1b3..79c19a42e 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java @@ -63,7 +63,7 @@ public class JeecgController> { } // Step.2 获取导出数据 List exportList = service.list(queryWrapper); - + System.out.println("Export LIST : " + exportList.toString()); // Step.3 AutoPoi 导出Excel ModelAndView mv = new ModelAndView(new JeecgEntityExcelView()); //此处设置的filename无效 ,前端会重更新设置一下 diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/ClientController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/ClientController.java index 456e0a91c..06805f0b9 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/ClientController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/ClientController.java @@ -11,6 +11,7 @@ import org.jeecg.common.api.vo.Result; import org.jeecg.common.aspect.annotation.AutoLog; import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.system.vo.LoginUser; +import org.jeecg.common.util.SpringContextUtils; import org.jeecg.common.util.oConvertUtils; import org.jeecg.modules.business.entity.Client; import org.jeecg.modules.business.entity.ClientSku; @@ -19,6 +20,7 @@ import org.jeecg.modules.business.service.IClientService; import org.jeecg.modules.business.service.IClientSkuService; import org.jeecg.modules.business.service.IShopService; import org.jeecg.modules.business.vo.ClientPage; +import org.jeecg.modules.online.cgform.mapper.OnlCgformFieldMapper; import org.jeecgframework.poi.excel.ExcelImportUtil; import org.jeecgframework.poi.excel.def.NormalExcelConstants; import org.jeecgframework.poi.excel.entity.ExportParams; @@ -130,9 +132,23 @@ public class ClientController { return Result.error("未找到对应数据"); } clientService.updateMain(client, clientPage.getShopList(), clientPage.getClientSkuList()); + updateShopId(); + log.info("Shop names replaced by new created shop IDs"); return Result.OK("编辑成功!"); } + /** + * Call a routine to replace shop names (from MabangAPI) + * by shop IDs in platform_order table after creating a new shop + */ + private static void updateShopId() { + OnlCgformFieldMapper onlCgformFieldMapper = SpringContextUtils.getBean(OnlCgformFieldMapper.class); + Map params = new HashMap<>(); + String sql = "UPDATE platform_order SET shop_id = shopErpToId(shop_id) WHERE shop_id NOT LIKE '1%'"; + params.put("execute_sql_string", sql); + onlCgformFieldMapper.executeUpdatetSQL(params); + } + /** * 通过id删除 * diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/logisticChannel/LogisticChannelController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/logisticChannel/LogisticChannelController.java index 845f4cee0..d5d32abe7 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/logisticChannel/LogisticChannelController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/logisticChannel/LogisticChannelController.java @@ -269,11 +269,11 @@ public class LogisticChannelController { @GetMapping(value = "/find") - public Result> findPrices(@RequestParam(name = "country") String country, + public Result> findPrices(@RequestParam(name = "countryList[]") List countryList, @RequestParam(name = "weight") int weight, @RequestParam(name = "volume", defaultValue = "1") int volume) { - List calculations = logisticChannelService.logisticChannelTrial(weight, volume, country); + List calculations = logisticChannelService.logisticChannelTrial(weight, volume, countryList); return Result.OK(calculations); } @@ -329,7 +329,7 @@ public class LogisticChannelController { logisticChannelService.logisticChannelTrial( totalWeight, totalVolume, - param.getCountryCode() + Collections.singletonList(param.getCountryCode()) ); return Result.OK(calculations); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java index 34031e732..449cfdd19 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/shippingInvoice/InvoiceController.java @@ -18,6 +18,7 @@ import org.jeecg.modules.business.mapper.PlatformOrderContentMapper; import org.jeecg.modules.business.mapper.PlatformOrderMapper; import org.jeecg.modules.business.service.*; import org.jeecg.modules.business.vo.*; +import org.jeecg.modules.message.entity.SysMessage; import org.jeecg.modules.quartz.entity.QuartzJob; import org.jeecg.modules.quartz.service.IQuartzJobService; import org.springframework.beans.factory.annotation.Autowired; @@ -92,7 +93,9 @@ public class InvoiceController { @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "type") String type, + @RequestParam(name = "warehouses[]") List warehouses, HttpServletRequest req) { + String warehouseString = String.join(",", warehouses); QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(platformOrder, req.getParameterMap()); LambdaQueryWrapper lambdaQueryWrapper = queryWrapper.lambda(); if(type.equals("shipping")) @@ -107,7 +110,7 @@ public class InvoiceController { Page page = new Page<>(pageNo, pageSize); IPage pageList; log.info("Request for " + type + " orders from client : " + clientId); - if (shopIDs == null || shopIDs.isEmpty()) { + if (shopIDs == null || shopIDs.isEmpty()) { // obsolete, used in old pages only lambdaQueryWrapper.inSql(PlatformOrder::getId, "SELECT po.id FROM platform_order po\n" + " JOIN shop s ON po.shop_id = s.id\n" + " JOIN client c ON s.owner_id = c.id WHERE c.id = '" + clientId + "'"); @@ -118,12 +121,20 @@ public class InvoiceController { if(start != null || end != null){ log.info("Specified period between " + start + " and " + end); if (type.equals("shipping")) - lambdaQueryWrapper.inSql(PlatformOrder::getId, "SELECT id FROM platform_order po WHERE po.shipping_time between '" + start + "' AND '" + end + "'"); + lambdaQueryWrapper.inSql(PlatformOrder::getId, "SELECT po.id FROM platform_order po\n" + + "JOIN logistic_channel lc ON po.logistic_channel_name = lc.zh_name\n" + + "WHERE po.shipping_time between '" + start + "' AND '" + end + "'\n" + + "AND lc.warehouse_in_china IN (" + warehouseString + ")"); else - lambdaQueryWrapper.inSql(PlatformOrder::getId, "SELECT id FROM platform_order po WHERE po.order_time between '" + start + "' AND '" + end + "'"); + lambdaQueryWrapper.inSql(PlatformOrder::getId, "SELECT po.id FROM platform_order po\n" + + "JOIN logistic_channel lc ON po.logistic_channel_name = lc.zh_name\n" + + "WHERE po.order_time between '" + start + "' AND '" + end + "'\n" + + "AND lc.warehouse_in_china IN (" + warehouseString + ")"); } - else { - lambdaQueryWrapper.inSql(PlatformOrder::getId, "SELECT id FROM platform_order po"); + else {// obsolete + lambdaQueryWrapper.inSql(PlatformOrder::getId, "SELECT po.id FROM platform_order po\n" + + "JOIN logistic_channel lc ON po.logistic_channel_name = lc.zh_name\n" + + "WHERE lc.warehouse_in_china IN (" + warehouseString + ")"); } pageList = platformOrderMapper.selectPage(page, lambdaQueryWrapper); return Result.OK(pageList); @@ -171,7 +182,6 @@ public class InvoiceController { public Result makeCompleteShippingInvoice(@RequestBody ShippingInvoiceParam param) { try { String method = param.getErpStatuses().toString().equals("[3]") ? "post" : param.getErpStatuses().toString().equals("[1, 2]") ? "pre-shipping" : "all"; - System.out.println(param.getErpStatuses().toString()); InvoiceMetaData metaData = shippingInvoiceService.makeCompleteInvoicePostShipping(param, method); return Result.OK(metaData); } catch (UserException e) { @@ -228,8 +238,10 @@ public class InvoiceController { log.info("Request for valid order time period for shops: " + shopIDs.toString() + " and erpStatuses : " + erpStatuses.toString()); Period period = shippingInvoiceService.getValidOrderTimePeriod(shopIDs, erpStatuses); - if (period.isValid()) + if (period.isValid()) { + System.out.println("start : " + period.start() + "; end : " + period.end()); return Result.OK(period); + } else return Result.error("No package in the selected period"); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/ScanType.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/ScanType.java index e8c7dd2b8..9159167b5 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/ScanType.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/ScanType.java @@ -18,7 +18,8 @@ public enum ScanType { WAITING_FOR_DELIVERY("Waiting for Delivery"), ARRIVED_PORT("Arrived at Port"), FLIGHT_PREPARING("Flight Preparing"), - CN_CUSTOMS_INSPECTION("Customs Inspection"); + CN_CUSTOMS_INSPECTION("Customs Inspection"), + BAGGING("Bagging"); private final String desc; ScanType(String desc) { diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKParcelDetail.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKParcelDetail.java new file mode 100644 index 000000000..d5e8ddb6a --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKParcelDetail.java @@ -0,0 +1,28 @@ +package org.jeecg.modules.business.domain.api.cmk; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Data +public class CMKParcelDetail { + + @JsonProperty("seventeenNo") + private String orderNo; + + @JsonProperty("guoJia") + private String country; + + @JsonProperty("shouHuoQuDao") + private String productCode; + + public CMKParcelDetail(String orderNo, String country, String productCode) { + this.orderNo = orderNo; + this.country = country; + this.productCode = productCode; + } + + public CMKParcelDetail() { + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKParcelTrace.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKParcelTrace.java new file mode 100644 index 000000000..55f58e581 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKParcelTrace.java @@ -0,0 +1,221 @@ +package org.jeecg.modules.business.domain.api.cmk; + +import com.alibaba.fastjson.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.jeecg.modules.business.domain.api.ScanType; + +import java.util.Objects; + +import static org.jeecg.modules.business.domain.api.ScanType.*; + +@Slf4j +@Data +public class CMKParcelTrace { + + @JSONField(deserialize = false) + private String parcelId; + + @JsonProperty("desc") + private String description; + + private String descriptionEn; + + private String time; + /** + * 位置 + */ + @JsonProperty("localtion") + private String location; + + private String scanType; + + public static final String VENTE_EN_LIGNE_TO_IGNORE = "009910,VENTE ON LINE"; + public static final String VENTE_EN_LIGNE_CN_TO_IGNORE = "该包裹在法邮创建,等待送往法邮"; + public static final String CUSTOM_CLEARED_CN_TO_IGNORE = "您的包裹已清关"; + + public static final String CMK = "Shipment information sent to CMK"; + public static final String SHIPMENT_INFO_RECEIVED = "Shipment information received"; + public static final String ARRIVE_FACILITY = "Arrived at Facility"; + public static final String PROCESSED_FACILITY = "Processed at Facility"; + public static final String DEPART_FACILITY = "Departed from Facility"; + public static final String PACKED = "已打包"; + public static final String PACKED_EN = "Bagging"; + public static final String ARRIVE_AIRPORT_ABROAD = "Arrive at international airport to abroad"; + public static final String DEPART_AIRPORT_ABROAD = "Departed from AIRPORT of Origin"; + public static final String ARRIVE_AIRPORT_DESTINATION = "Arrived at AIRPORT of Destination"; + public static final String CUSTOM_CLEARED = "Custom clearance completed"; + public static final String CUSTOM_CLEARED_CN = "清关完成"; + public static final String END_ARRIVED = "Delivery to local courier"; + public static final String END_RECEIVED = "法邮已收取快件, 派送中"; + public static final String END_RECEIVED_EN = "Shipment given to local courier"; + public static final String ARRIVED_AT_DELIVERY = "包裹已到达分拣中心"; + public static final String ARRIVED_AT_DELIVERY_EN = "Shipment arrived at distribution center"; + public static final String DELIVERY_SCHEDULED = "包裹将在收件人选择的日期预约递送"; + public static final String DELIVERY_SCHEDULED_2 = "包裹将在收件人选择的日期通过预约递送"; + public static final String DELIVERY_SCHEDULED_EN = "Package will be delivered on date chosen by consignee"; + public static final String DELIVERY_DELAYED = "包裹今天无法送达.将尽快安排再次配送"; + public static final String DELIVERY_DELAYED_EN = "Package can not be delivered today, another attempt will be arranged as soon as possible"; + public static final String DELIVERY_DELAYED_2 = "由于收件人地址的问题,包裹今天无法送达.将尽快安排再次配送"; + public static final String DELIVERY_DELAYED_2_EN = "Due to a problem with the address, package can not be delivered today, another attempt will be arranged as soon as possible"; + public static final String DELIVERY_DELAYED_3 = "由于无法控制的特殊情况,包裹今天无法送达.将尽快安排再次配送"; + public static final String DELIVERY_DELAYED_3_EN = "Due to a circumstances beyond our control, package can not be delivered today, another attempt will be arranged as soon as possible"; + public static final String CONSIGNEE_ABSENT = "由于收件人不在,您的包裹无法送达.它将在下一个工作日再次交付"; + public static final String CONSIGNEE_ABSENT_EN = "Consignee absent, package can not be delivered today, another attempt will be made the next working day"; + public static final String DELIVERY_NEXT_WORKING_DAY = "包裹将在下一个工作日送达。 如果您不在,请在www.colissimo.fr/monchoix告诉我们。"; + public static final String DELIVERY_NEXT_WORKING_DAY_EN = "Package will be delivered the next working day. If absent, please inform us at www.colissimo.fr/monchoix"; + public static final String DELIVERY_STATION = "您的包裹位于支持您地址的送货站点。我们准备交付。"; + public static final String DELIVERY_STATION_EN = "Package has arrived at delivery site."; + public static final String DELIVERED = "包裹已送达"; + public static final String DELIVERED_EN = "Delivered"; + public static final String DELIVERED_TO_CONCIERGE = "包裹已由楼层管理员签收"; + public static final String DELIVERED_TO_CONCIERGE_EN = "Delivered to concierge"; + public static final String INSTRUCTIONS_RECEIVED = "包裹根据收件人的要求重新送至其指定的地点"; + public static final String INSTRUCTIONS_RECEIVED_EN = "Package is being redirected to instructed address"; + public static final String TO_BE_RETRIEVED = "包裹已投放至所选择的取货点, 收件人需10日携带有效证件前往领取"; + public static final String TO_BE_RETRIEVED_EN = "Package has been left at relay point chosen by consignee and can be retrieved in the next 10 working days"; + public static final String END_ABNORMAL_ADDRESS = "由于地址问题,您的包裹无法交付给您。它将退还给发件人。"; + public static final String END_ABNORMAL_ADDRESS_EN = "Due to a problem with the address, the package can not be delivered and will be returned to sender"; + public static final String END_ABNORMAL_ADDRESS_INCOMPLETE = "收件人地址信息不完整,无法送达.请联系客服部门补充地址信息"; + public static final String END_ABNORMAL_ADDRESS_INCOMPLETE_EN = "Package can not be delivered due to incomplete consignee address, please contact customer service"; + public static final String END_ABNORMAL_PICKING = "包裹分拣错误,现已重新派送"; + public static final String END_ABNORMAL_PICKING_EN = "Picking error, package will be re-delivered"; + public static final String END_RETURN_TO_SENDER = "包裹退回,送还至发件人"; + public static final String END_RETURN_TO_SENDER_EN = "Return to sender"; + public static final String END_RETURN = "包裹退回"; + public static final String END_RETURN_EN = "Returned"; + + + public CMKParcelTrace() { + } + + public void parcelTraceProcess(String parcelId) { + setParcelId(parcelId); + switch (description) { + case CMK: + setDescriptionEn(SHIPMENT_INFO_RECEIVED); + setScanType(ORDER_PLACED.getDesc()); + break; + case PACKED: + setDescriptionEn(PACKED_EN); + setScanType(BAGGING.getDesc()); + break; + case ARRIVE_FACILITY: + setScanType(FACILITY_ARRIVED.getDesc()); + break; + case PROCESSED_FACILITY: + setScanType(FACILITY_OUTBOUND.getDesc()); + break; + case DEPART_FACILITY: + setScanType(FACILITY_DEPARTURE.getDesc()); + break; + case ARRIVE_AIRPORT_ABROAD: + setScanType(ARRIVED_PORT.getDesc()); + break; + case DEPART_AIRPORT_ABROAD: + setScanType(FLIGHT_DEPARTURE.getDesc()); + break; + case ARRIVE_AIRPORT_DESTINATION: + setScanType(FLIGHT_ARRIVED.getDesc()); + break; + case CUSTOM_CLEARED: + setScanType(CUSTOMS_CLEARANCE_COMPLETED.getDesc()); + break; + case CUSTOM_CLEARED_CN: + setDescriptionEn(CUSTOM_CLEARED); + setScanType(CUSTOMS_CLEARANCE_COMPLETED.getDesc()); + break; + case END_ARRIVED: + setScanType(ScanType.END_ARRIVED.getDesc()); + break; + case END_RECEIVED: + setDescriptionEn(END_RECEIVED_EN); + setScanType(ScanType.END_RECEIVED.getDesc()); + break; + case ARRIVED_AT_DELIVERY: + setDescriptionEn(ARRIVED_AT_DELIVERY_EN); + setScanType(END_DELIVERY.getDesc()); + break; + case DELIVERY_STATION: + setDescriptionEn(DELIVERY_STATION_EN); + setScanType(END_DELIVERY.getDesc()); + break; + case INSTRUCTIONS_RECEIVED: + setDescriptionEn(INSTRUCTIONS_RECEIVED_EN); + setScanType(END_DELIVERY.getDesc()); + break; + case DELIVERY_SCHEDULED: + case DELIVERY_SCHEDULED_2: + setDescriptionEn(DELIVERY_SCHEDULED_EN); + setScanType(END_DELIVERY.getDesc()); + break; + case DELIVERY_NEXT_WORKING_DAY: + setDescriptionEn(DELIVERY_NEXT_WORKING_DAY_EN); + setScanType(END_DELIVERY.getDesc()); + break; + case DELIVERY_DELAYED: + setDescriptionEn(DELIVERY_DELAYED_EN); + setScanType(END_ABNORMAL.getDesc()); + break; + case DELIVERY_DELAYED_2: + setDescriptionEn(DELIVERY_DELAYED_2_EN); + setScanType(END_ABNORMAL.getDesc()); + break; + case DELIVERY_DELAYED_3: + setDescriptionEn(DELIVERY_DELAYED_3_EN); + setScanType(END_ABNORMAL.getDesc()); + break; + case CONSIGNEE_ABSENT: + setDescriptionEn(CONSIGNEE_ABSENT_EN); + setScanType(END_ABNORMAL.getDesc()); + break; + case DELIVERED: + setDescriptionEn(DELIVERED_EN); + setScanType(END_DELIVERED.getDesc()); + break; + case DELIVERED_TO_CONCIERGE: + setDescriptionEn(DELIVERED_TO_CONCIERGE_EN); + setScanType(END_DELIVERED.getDesc()); + break; + case TO_BE_RETRIEVED: + setDescriptionEn(TO_BE_RETRIEVED_EN); + setScanType(END_DELIVERED.getDesc()); + break; + case END_ABNORMAL_ADDRESS: + setDescriptionEn(END_ABNORMAL_ADDRESS_EN); + setScanType(END_ABNORMAL.getDesc()); + break; + case END_ABNORMAL_PICKING: + setDescriptionEn(END_ABNORMAL_PICKING_EN); + setScanType(END_ABNORMAL.getDesc()); + break; + case END_ABNORMAL_ADDRESS_INCOMPLETE: + setDescriptionEn(END_ABNORMAL_ADDRESS_INCOMPLETE_EN); + setScanType(END_ABNORMAL.getDesc()); + break; + case END_RETURN: + setDescriptionEn(END_RETURN_EN); + setScanType(RETURN.getDesc()); + break; + case END_RETURN_TO_SENDER: + setDescriptionEn(END_RETURN_TO_SENDER_EN); + setScanType(RETURN.getDesc()); + break; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CMKParcelTrace that = (CMKParcelTrace) o; + return Objects.equals(description, that.description) && Objects.equals(time, that.time) && Objects.equals(location, that.location); + } + + public boolean isUseful() { + return !getDescription().equalsIgnoreCase(VENTE_EN_LIGNE_CN_TO_IGNORE) + && !getLocation().equalsIgnoreCase(VENTE_EN_LIGNE_TO_IGNORE) + && !getDescription().equalsIgnoreCase(CUSTOM_CLEARED_CN_TO_IGNORE); + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKParcelTraceData.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKParcelTraceData.java new file mode 100644 index 000000000..e99ffb5d8 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKParcelTraceData.java @@ -0,0 +1,46 @@ +package org.jeecg.modules.business.domain.api.cmk; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +@Slf4j +@Data +@TableName("parcel") +public class CMKParcelTraceData { + + + @TableId(type = IdType.ASSIGN_ID) + private String id = IdWorker.getIdStr(); + + /** + * 单号,与查询单号一致 + */ + @JsonProperty("no") + private String thirdBillCode; + + private String errorMsg; + + private CMKParcelDetail detail; + + @JsonProperty("trackList") + private List traceList; + + private String country; + + public CMKParcelTraceData(String thirdBillCode, String errorMsg, CMKParcelDetail detail, List traceList) { + this.thirdBillCode = thirdBillCode; + this.errorMsg = errorMsg; + this.detail = detail; + this.traceList = traceList; + } + + public CMKParcelTraceData() { + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKRequest.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKRequest.java new file mode 100644 index 000000000..6c4af962f --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKRequest.java @@ -0,0 +1,56 @@ +package org.jeecg.modules.business.domain.api.cmk; + + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.message.BasicNameValuePair; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +@Slf4j +public class CMKRequest { + private final static String URL = "https://cmk.itdida.com/itdida-api/queryTracks"; + private static final String API_KEY = "ITDIDA-APP-KEY-YR573T2VQ2"; + private static final RequestConfig REQUEST_CONFIG = RequestConfig.custom().build(); + + private final List trackingNumbers; + + public CMKRequest(List trackingNumbers) { + this.trackingNumbers = trackingNumbers; + } + + /** + * Sent request to the CMK API with a request body. + * + * @return the response + */ + public HttpResponse send() { + int attempts = 0; + while (attempts++ < 5) { + try { + HttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(REQUEST_CONFIG).build(); + HttpGet request = new HttpGet(URL + "?no=" + String.join(",", trackingNumbers)); + + // adding the form data + request.setHeader(HttpHeaders.AUTHORIZATION, API_KEY); + return httpClient.execute(request); + } catch (Exception e) { + log.error("Request failed on attempt n°" + attempts); + } + } + return null; + } + +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKResponse.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKResponse.java new file mode 100644 index 000000000..5562af70e --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/cmk/CMKResponse.java @@ -0,0 +1,37 @@ +package org.jeecg.modules.business.domain.api.cmk; + +import com.alibaba.fastjson.annotation.JSONField; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +@Slf4j +@Data +public class CMKResponse { + + @TableId(type = IdType.ASSIGN_ID) + private String id = IdWorker.getIdStr(); + + @JSONField(deserialize = false) + private Integer statusCode; + + @JSONField(deserialize = false) + private Boolean success; + + @JsonProperty("data") + private List parcelData; + + public CMKResponse(Integer statusCode, Boolean success, List parcelData) { + this.statusCode = statusCode; + this.success = success; + this.parcelData = parcelData; + } + + public CMKResponse() { + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuList/SkuData.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuList/SkuData.java index 226c8f7af..6a8688e9b 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuList/SkuData.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuList/SkuData.java @@ -64,7 +64,7 @@ public class SkuData { @JSONField(name="height") private String height; @JSONField(name="weight") - private double weight; + private Double weight; /** * saleRemark contains the weight */ diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/MabangSkuJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/MabangSkuJob.java index 9d9cfb5be..8aade1ad2 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/MabangSkuJob.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/MabangSkuJob.java @@ -6,15 +6,18 @@ import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; import org.jeecg.common.api.dto.message.TemplateMessageDTO; import org.jeecg.common.system.api.ISysBaseAPI; +import org.jeecg.common.util.SpringContextUtils; import org.jeecg.modules.business.domain.api.mabang.doSearchSkuList.*; import org.jeecg.modules.business.domain.api.mabang.doSearchSkuList.SkuData; import org.jeecg.modules.business.entity.Sku; import org.jeecg.modules.business.service.ISkuListMabangService; +import org.jeecg.modules.online.cgform.mapper.OnlCgformFieldMapper; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.time.ZoneId; @@ -25,20 +28,36 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import static org.jeecg.modules.business.domain.api.mabang.doSearchSkuList.SkuStatus.*; - /** * A Job that retrieves all Sku from Mabang * if the sku is of status 3 (normal) and not in DB, then we insert it in DB */ @Slf4j +@Component public class MabangSkuJob implements Job { + private static final String SECTION_START = "
"; + private static final String DIV_START = "
"; + private static final String DIV_END_NEXT_DIV_START = "
"; + private static final String ROW_START = ""; + private static final String ROW_END = ""; + private static final String NEXT_COLUMN = ""; + private static final String TABLE_START = ""; + private static final String SECTION_END = ""; + private static final String TABLE_END = "
SKU中文名重量申报价售价
"; @Autowired @Setter private ISkuListMabangService skuListMabangService; private static final Integer DEFAULT_NUMBER_OF_DAYS = 5; - private static final DateType DEFAULT_DATE_TYPE = DateType.UPDATE; + private static final Integer NBR_SKU_PER_PAGE = 400; + private static final DateType DEFAULT_DATE_TYPE = DateType.CREATE; @Autowired private ISysBaseAPI ISysBaseApi; @@ -72,11 +91,9 @@ public class MabangSkuJob implements Job { if (!endDateTime.isAfter(startDateTime)) { throw new RuntimeException("EndDateTime must be strictly greater than StartDateTime !"); } -// else if (endDateTime.minusDays(30).isAfter(startDateTime)) { -// throw new RuntimeException("No more than 30 days can separate startDateTime and endDateTime !"); -// } Map newSkusMap = new HashMap<>(); + Map skuDataMap = new HashMap<>(); try { while (startDateTime.until(endDateTime, ChronoUnit.HOURS) > 0) { LocalDateTime dayBeforeEndDateTime = endDateTime.minusDays(1); @@ -85,10 +102,11 @@ public class MabangSkuJob implements Job { SkuListStream stream = new SkuListStream(rawStream); // the status is directly filtered in all() method List skusFromMabang = stream.all(); + skusFromMabang.forEach(skuData -> skuDataMap.put(skuData.getErpCode(), skuData)); log.info("{} skus from {} to {} ({})to be inserted.", skusFromMabang.size(), dayBeforeEndDateTime, endDateTime, dateType); - if(skusFromMabang.size() > 0) { + if (skusFromMabang.size() > 0) { // we save the skuDatas in DB newSkusMap.putAll(skuListMabangService.saveSkuFromMabang(skusFromMabang)); } @@ -98,67 +116,90 @@ public class MabangSkuJob implements Job { throw new RuntimeException(e); } + updateSkuId(); + log.info("SKU codes replaced by new created SKU IDs"); + // here we send system notification with the number and list of new skus saved in DB - if(newSkusMap.size() > 0) { - List messageContentList = new ArrayList<>(); - List newSkuCodeList = newSkusMap.keySet().stream().map(Sku::getErpCode).sorted().collect(Collectors.toList()); - String skuListContent = ""; - // we truncate the message and only send skus by groups of 400 - for (int i = 0; i < newSkuCodeList.size(); i++) { - if (i % 10 == 0 && i != 0 && i % 400 != 0) { - skuListContent = skuListContent.concat("
"); - } - if (i == 0) { - skuListContent = skuListContent.concat("
" + - "
"); - } - skuListContent = skuListContent.concat("

" + newSkuCodeList.get(i) + "

"); - if (i == newSkuCodeList.size() - 1 || i % 400 == 399) { - skuListContent = skuListContent.concat("
"); - messageContentList.add(skuListContent); - skuListContent = "
" + - "
"; - } + if (newSkusMap.size() == 0) { + return; + } + List messageContentList = new ArrayList<>(); + List newSkuCodeList = newSkusMap.keySet().stream().map(Sku::getErpCode).sorted().collect(Collectors.toList()); + String skuListContent = TABLE_START; + // we truncate the message and only send skus by groups of 400 + for (int i = 0; i < newSkuCodeList.size(); i++) { + String skuErpCode = newSkuCodeList.get(i); + SkuData skuData = skuDataMap.get(skuErpCode); + if (skuData != null) { + skuListContent = skuListContent + .concat(ROW_START) + .concat(skuErpCode) + .concat(NEXT_COLUMN) + .concat(skuData.getNameCN()) + .concat(NEXT_COLUMN) + .concat(String.valueOf(skuData.getWeight() == null ? 0 : skuData.getWeight())) + .concat(NEXT_COLUMN) + .concat(String.valueOf(skuData.getDeclareValue() == null ? 0 : skuData.getDeclareValue())) + .concat(NEXT_COLUMN) + .concat(String.valueOf(skuData.getSalePrice() == null ? 0 : skuData.getSalePrice())) + .concat(ROW_END); } + if (i == newSkuCodeList.size() - 1 || i % NBR_SKU_PER_PAGE == NBR_SKU_PER_PAGE - 1) { + skuListContent = skuListContent.concat(TABLE_END); + messageContentList.add(skuListContent); + skuListContent = TABLE_START; + } + } - // here we are printing the list of skus with extra info - Map needTreatmentSkuMap = new HashMap<>(); - for (Map.Entry entry : newSkusMap.entrySet()) { - if (!entry.getValue().equals("")) { - needTreatmentSkuMap.put(entry.getKey().getErpCode(), entry.getValue()); - } + // here we are printing the list of skus with extra info + Map needTreatmentSkuMap = new HashMap<>(); + for (Map.Entry entry : newSkusMap.entrySet()) { + if (!entry.getValue().isEmpty()) { + needTreatmentSkuMap.put(entry.getKey().getErpCode(), entry.getValue()); } - String needTreatmentSku = "
"; - int cpt = 0; - for (Map.Entry entry : needTreatmentSkuMap.entrySet()) { - if (cpt % 10 == 0 && cpt != 0) { - needTreatmentSku = needTreatmentSku.concat("
"); - } - if (cpt == 0) { - needTreatmentSku = needTreatmentSku.concat("
"); - } - needTreatmentSku = needTreatmentSku.concat("

" + entry.getKey() + " : " + entry.getValue() + "

"); - cpt++; + } + String needTreatmentSku = SECTION_START; + int cpt = 0; + for (Map.Entry entry : needTreatmentSkuMap.entrySet()) { + if (cpt % 10 == 0 && cpt != 0) { + needTreatmentSku = needTreatmentSku.concat(DIV_END_NEXT_DIV_START); } - needTreatmentSku = needTreatmentSku.concat("
"); + if (cpt == 0) { + needTreatmentSku = needTreatmentSku.concat(DIV_START); + } + needTreatmentSku = needTreatmentSku.concat("

" + entry.getKey() + " : " + entry.getValue() + "

"); + cpt++; + } + needTreatmentSku = needTreatmentSku.concat(SECTION_END); - int page = 1; - for (String msg : messageContentList) { - Map param = new HashMap<>(); - param.put("nb_of_entries", String.valueOf(newSkusMap.size())); - param.put("sku_list", msg); - param.put("need_treatment", needTreatmentSkuMap.size() > 0 ? needTreatmentSku : "None"); - param.put("current_page", String.valueOf(page)); - param.put("total_page", String.valueOf(messageContentList.size())); - page++; - TemplateMessageDTO message = new TemplateMessageDTO("admin", "admin", "SKU导入任务", param, "sku_mabang_job_result"); - ISysBaseApi.sendTemplateAnnouncement(message); - message = new TemplateMessageDTO("admin", "Alice", "SKU导入任务", param, "sku_mabang_job_result"); - ISysBaseApi.sendTemplateAnnouncement(message); - message = new TemplateMessageDTO("admin", "Jessyca", "SKU导入任务", param, "sku_mabang_job_result"); - ISysBaseApi.sendTemplateAnnouncement(message); - } + int page = 1; + for (String msg : messageContentList) { + Map param = new HashMap<>(); + param.put("nb_of_entries", String.valueOf(newSkusMap.size())); + param.put("sku_list", msg); + param.put("need_treatment", needTreatmentSkuMap.size() > 0 ? needTreatmentSku : "None"); + param.put("current_page", String.valueOf(page)); + param.put("total_page", String.valueOf(messageContentList.size())); + TemplateMessageDTO message = new TemplateMessageDTO("admin", "admin", "SKU导入任务", param, "sku_mabang_job_result"); + ISysBaseApi.sendTemplateAnnouncement(message); + message = new TemplateMessageDTO("admin", "Alice", "SKU导入任务", param, "sku_mabang_job_result"); + ISysBaseApi.sendTemplateAnnouncement(message); + message = new TemplateMessageDTO("admin", "Jessyca", "SKU导入任务", param, "sku_mabang_job_result"); + ISysBaseApi.sendTemplateAnnouncement(message); + log.info("Page {} of recap sent through system announcement", page); + page++; } } -} + /** + * Call a routine to replace SKU codes (from MabangAPI) + * by SKU IDs in platform_order_content table after creating new SKUs + */ + private static void updateSkuId() { + OnlCgformFieldMapper onlCgformFieldMapper = SpringContextUtils.getBean(OnlCgformFieldMapper.class); + Map params = new HashMap<>(); + String sql = "UPDATE platform_order_content SET sku_id = skuErpToId(sku_id) WHERE sku_id NOT LIKE '1%'"; + params.put("execute_sql_string", sql); + onlCgformFieldMapper.executeUpdatetSQL(params); + } +} \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/shippingInvoice/ShippingInvoiceFactory.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/shippingInvoice/ShippingInvoiceFactory.java index cf4ff6fd6..1d1af156a 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/shippingInvoice/ShippingInvoiceFactory.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/shippingInvoice/ShippingInvoiceFactory.java @@ -220,7 +220,9 @@ public class ShippingInvoiceFactory { Map skuServiceFees = new HashMap<>(); skuDataPreparation(skuRealWeights, skuServiceFees); List countryList = countryService.findAll(); - Map> channelPriceMap = getChannelPriceMap(orderAndContent, true); + Map logisticChannelMap = logisticChannelMapper.getAll().stream() + .collect(toMap(LogisticChannel::getId, Function.identity())); + Map> channelPriceMap = getChannelPriceMap(logisticChannelMap, orderAndContent, true); List latestDeclaredValues = skuDeclaredValueService.getLatestDeclaredValues(); List shops = shopMapper.selectBatchIds(shopIds); @@ -230,7 +232,7 @@ public class ShippingInvoiceFactory { shops.forEach(shop -> shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee())); String invoiceCode = generateCompleteInvoiceCode(); log.info("New invoice code: {}", invoiceCode); - calculateFees(orderAndContent, channelPriceMap, countryList, skuRealWeights, skuServiceFees, + calculateFees(logisticChannelMap, orderAndContent, channelPriceMap, countryList, skuRealWeights, skuServiceFees, latestDeclaredValues, client, shopServiceFeeMap, shopPackageMatFeeMap, invoiceCode); BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD"); @@ -320,7 +322,7 @@ public class ShippingInvoiceFactory { * channel price, this exception will be thrown. */ @Transactional - public ShippingInvoice createInvoice(String customerId, List shopIds, Date begin, Date end, List erpStatuses) throws UserException { + public ShippingInvoice createInvoice(String customerId, List shopIds, Date begin, Date end, List erpStatuses, List warehouses) throws UserException { log.info( "Creating an invoice with arguments:\n client ID: {}, shop IDs: {}, period:[{} - {}]", customerId, shopIds.toString(), begin, end @@ -335,7 +337,7 @@ public class ShippingInvoiceFactory { SUBJECT_FORMAT.format(begin), SUBJECT_FORMAT.format(end) ); - uninvoicedOrderToContent = platformOrderService.findUninvoicedOrders(shopIds, begin, end); + uninvoicedOrderToContent = platformOrderService.findUninvoicedOrders(shopIds, begin, end, warehouses); } else if (erpStatuses.toString().equals("[1, 2]")) { subject = String.format( @@ -343,7 +345,7 @@ public class ShippingInvoiceFactory { SUBJECT_FORMAT.format(begin), SUBJECT_FORMAT.format(end) ); - uninvoicedOrderToContent = platformOrderService.findUninvoicedOrderContentsForShopsAndStatus(shopIds, begin, end, erpStatuses); + uninvoicedOrderToContent = platformOrderService.findUninvoicedOrderContentsForShopsAndStatus(shopIds, begin, end, erpStatuses, warehouses); } else { subject = String.format( @@ -351,7 +353,7 @@ public class ShippingInvoiceFactory { SUBJECT_FORMAT.format(begin), SUBJECT_FORMAT.format(end) ); - uninvoicedOrderToContent = platformOrderService.findUninvoicedOrderContentsForShopsAndStatus(shopIds, begin, end, erpStatuses); + uninvoicedOrderToContent = platformOrderService.findUninvoicedOrderContentsForShopsAndStatus(shopIds, begin, end, erpStatuses, warehouses); } return createInvoice(customerId, shopIds, uninvoicedOrderToContent, savRefunds, subject, false); } @@ -393,11 +395,13 @@ public class ShippingInvoiceFactory { skuDataPreparation(skuRealWeights, skuServiceFees); List countryList = countryService.findAll(); Map> channelPriceMap; + Map logisticChannelMap = logisticChannelMapper.getAll().stream() + .collect(toMap(LogisticChannel::getId, Function.identity())); if(subject.contains("Pre") || subject.contains("All")) { - channelPriceMap = getChannelPriceMap(orderAndContent, skipShippingTimeComparing, "order"); + channelPriceMap = getChannelPriceMap(logisticChannelMap, orderAndContent, skipShippingTimeComparing, "order"); } else { - channelPriceMap = getChannelPriceMap(orderAndContent, skipShippingTimeComparing); + channelPriceMap = getChannelPriceMap(logisticChannelMap, orderAndContent, skipShippingTimeComparing); } List latestDeclaredValues = skuDeclaredValueService.getLatestDeclaredValues(); @@ -409,7 +413,7 @@ public class ShippingInvoiceFactory { shops.forEach(shop -> shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee())); String invoiceCode = generateInvoiceCode(); log.info("New invoice code: {}", invoiceCode); - calculateFees(orderAndContent, channelPriceMap, countryList, skuRealWeights, skuServiceFees, + calculateFees(logisticChannelMap, orderAndContent, channelPriceMap, countryList, skuRealWeights, skuServiceFees, latestDeclaredValues, client, shopServiceFeeMap, shopPackageMatFeeMap, invoiceCode); BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD"); if (savRefunds != null) { @@ -420,7 +424,19 @@ public class ShippingInvoiceFactory { return invoice; } - private Map> getChannelPriceMap(Map> orderAndContent, + /** + * Construct a map between LogisticChannel and LogisticChannelPrices, by using distinct country names and + * distinct effective logistic channel names(invoice logistic channel names trump over logistic channel names) + * from orders as filter. + * In the case where the logistic channel name points to a ghost channel(i.e. a channel whose samePriceChannelId isn't null), + * the result map may NOT contain the real channel if no order is actually shipped from it. + * @param logisticChannelMap A map of LogisticChannels keyed by IDs + * @param orderAndContent Map of order and contents + * @param skipShippingTimeComparing True if shipping time comparison should be skipped, false otherwise + * @return + */ + private Map> getChannelPriceMap(Map logisticChannelMap, + Map> orderAndContent, boolean skipShippingTimeComparing, String ... dateType ) { Date latestShippingTime; List sortedList; @@ -445,12 +461,10 @@ public class ShippingInvoiceFactory { List distinctChannelNames = sortedList.stream() .map(order -> order.getInvoiceLogisticChannelName() == null ? order.getLogisticChannelName() : order.getInvoiceLogisticChannelName()) .distinct().collect(toList()); - Map logisticChannelMapById = logisticChannelMapper.getAll().stream() - .collect(toMap(LogisticChannel::getId, Function.identity())); List allEligiblePrices = logisticChannelPriceMapper.findPricesBy(latestShippingTime, distinctCountries, distinctChannelNames); return allEligiblePrices.stream().collect( - groupingBy(logisticChannelPrice -> logisticChannelMapById.get(logisticChannelPrice.getChannelId())) + groupingBy(logisticChannelPrice -> logisticChannelMap.get(logisticChannelPrice.getChannelId())) ); } @@ -464,7 +478,7 @@ public class ShippingInvoiceFactory { } } - private void calculateFees(Map> orderAndContent, + private void calculateFees(Map logisticChannelMap, Map> orderAndContent, Map> channelPriceMap, List countryList, Map skuRealWeights, @@ -497,7 +511,8 @@ public class ShippingInvoiceFactory { contentMap, skuRealWeights ); - Pair logisticChannelPair = findAppropriatePrice(countryList, channelPriceMap, uninvoicedOrder, contentWeight); + Pair logisticChannelPair = findAppropriatePrice(countryList, logisticChannelMap, + channelPriceMap, uninvoicedOrder, contentWeight); LogisticChannelPrice price = logisticChannelPair.getRight(); // update attributes of orders and theirs content BigDecimal packageMatFee = shopPackageMatFeeMap.get(uninvoicedOrder.getShopId()); @@ -603,11 +618,22 @@ public class ShippingInvoiceFactory { return totalDeclaredValue; } + /** + * + * @param countryList + * @param logisticChannelMap Map of LogisticChannels where keys are IDs + * @param channelPriceMap + * @param uninvoicedOrder + * @param contentWeight + * @return + * @throws UserException + */ @NotNull - private Pair findAppropriatePrice(List countryList, Map> channelPriceMap, - PlatformOrder uninvoicedOrder, BigDecimal contentWeight) throws UserException { - LogisticChannelPrice price = null; - LogisticChannel channel = null; + private Pair findAppropriatePrice(List countryList, Map logisticChannelMap, + Map> channelPriceMap, + PlatformOrder uninvoicedOrder, BigDecimal contentWeight) throws UserException { + LogisticChannelPrice price; + LogisticChannel channel; try { /* Find channel price */ Optional foundCountry = countryList.stream() @@ -620,24 +646,24 @@ public class ShippingInvoiceFactory { } Date shippingTime = uninvoicedOrder.getShippingTime() == null ? now().toSqlDate() : uninvoicedOrder.getShippingTime(); - String logisticChannelName = uninvoicedOrder.getInvoiceLogisticChannelName() == null ? - uninvoicedOrder.getLogisticChannelName() : uninvoicedOrder.getInvoiceLogisticChannelName(); - Optional>> channelPriceMapCandidate = channelPriceMap.entrySet().stream() - // Find prices of the used channel - .filter(entry -> entry.getKey().getZhName().equals(logisticChannelName)) - .findFirst(); - if (channelPriceMapCandidate.isPresent()) { - channel = channelPriceMapCandidate.get().getKey(); - Optional priceCandidate = channelPriceMapCandidate.get().getValue().stream() - .filter(channelPrice -> channelPrice.getEffectiveCountry().equals(foundCountry.get().getCode())) - .filter(channelPrice -> channelPrice.getWeightRangeEnd() >= contentWeight.intValue() - && channelPrice.getWeightRangeStart() < contentWeight.intValue()) - .filter(channelPrice -> channelPrice.getEffectiveDate().before(shippingTime)) - .max(Comparator.comparing(LogisticChannelPrice::getEffectiveDate)); - price = priceCandidate.orElse(null); + Map logisticChannelNameMap = channelPriceMap.keySet().stream().collect(toMap(LogisticChannel::getZhName, Function.identity())); + // If an invoice logistic channel already present, use it, + // otherwise write in the same price logistic channel name (if present) + String invoiceLogisticChannelName = uninvoicedOrder.getInvoiceLogisticChannelName(); + String logisticChannelName = invoiceLogisticChannelName == null ? uninvoicedOrder.getLogisticChannelName() : invoiceLogisticChannelName; + channel = logisticChannelNameMap.get(logisticChannelName); + if (invoiceLogisticChannelName == null && channel != null) { + String samePriceChannelId = channel.getSamePriceChannelId(); + if (samePriceChannelId != null) { + LogisticChannel samePriceChannel = logisticChannelMap.get(samePriceChannelId); + if (samePriceChannel != null) { + // We don't affect samePriceChannel to channel here because channelPriceMap may not contain it + uninvoicedOrder.setInvoiceLogisticChannelName(samePriceChannel.getZhName()); + } + } } - if (price == null) { - String format = "Can not find propre channel price for" + + if (channel == null) { + String format = "Can not find propre channel for" + "package Serial No: %s, delivered at %s, " + "weight: %s, channel name: %s, destination: %s"; String msg = String.format( @@ -651,8 +677,15 @@ public class ShippingInvoiceFactory { log.error(msg); throw new UserException(msg); } - if (channel == null) { - String format = "Can not find propre channel for" + + Optional priceCandidate = channelPriceMap.get(channel).stream() + .filter(channelPrice -> channelPrice.getEffectiveCountry().equals(foundCountry.get().getCode())) + .filter(channelPrice -> channelPrice.getWeightRangeEnd() >= contentWeight.intValue() + && channelPrice.getWeightRangeStart() < contentWeight.intValue()) + .filter(channelPrice -> channelPrice.getEffectiveDate().before(shippingTime)) + .max(Comparator.comparing(LogisticChannelPrice::getEffectiveDate)); + price = priceCandidate.orElse(null); + if (price == null) { + String format = "Can not find propre channel price for" + "package Serial No: %s, delivered at %s, " + "weight: %s, channel name: %s, destination: %s"; String msg = String.format( @@ -729,7 +762,9 @@ public class ShippingInvoiceFactory { Map> flattenedOrdersMap = uninvoicedOrdersByShopId.values().stream() .flatMap(map -> map.entrySet().stream()) .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); - Map> channelPriceMap = getChannelPriceMap(flattenedOrdersMap, true); + Map logisticChannelMap = logisticChannelMapper.getAll().stream() + .collect(toMap(LogisticChannel::getId, Function.identity())); + Map> channelPriceMap = getChannelPriceMap(logisticChannelMap, flattenedOrdersMap, true); for (Map.Entry> entry : clientToShopsMap.entrySet()) { Client client = entry.getKey(); @@ -741,7 +776,7 @@ public class ShippingInvoiceFactory { shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee()); Map> orders = uninvoicedOrdersByShopId.get(shop.getId()); try { - calculateFees(orders, channelPriceMap, countryList, skuRealWeights, skuServiceFees, + calculateFees(logisticChannelMap, orders, channelPriceMap, countryList, skuRealWeights, skuServiceFees, latestDeclaredValues, client, shopServiceFeeMap,shopPackageMatFeeMap, null); BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD"); ShippingInvoice invoice = new ShippingInvoice(client, "", "", orders, null, eurToUsd); @@ -785,7 +820,10 @@ public class ShippingInvoiceFactory { Map skuServiceFees = new HashMap<>(); skuDataPreparation(skuRealWeights, skuServiceFees); - Map> channelPriceMap = getChannelPriceMap(ordersMap, true); + Map logisticChannelMap = logisticChannelMapper.getAll().stream() + .collect(toMap(LogisticChannel::getId, Function.identity())); + Map> channelPriceMap = getChannelPriceMap(logisticChannelMap, ordersMap, true); + for (Shop shop : shops) { Map shopServiceFeeMap = new HashMap<>(); @@ -794,7 +832,7 @@ public class ShippingInvoiceFactory { shopPackageMatFeeMap.put(shop.getId(), shop.getPackagingMaterialFee()); Map> orders = uninvoicedOrdersByShopId.get(shop.getId()); try { - calculateFees(orders, channelPriceMap, countryList, skuRealWeights, skuServiceFees, + calculateFees(logisticChannelMap, orders, channelPriceMap, countryList, skuRealWeights, skuServiceFees, latestDeclaredValues, client, shopServiceFeeMap, shopPackageMatFeeMap, null); BigDecimal eurToUsd = exchangeRatesMapper.getLatestExchangeRate("EUR", "USD"); ShippingInvoice invoice = new ShippingInvoice(client, "", "", orders, null, eurToUsd); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/LogisticChannel.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/LogisticChannel.java index 1f631d939..c171620d3 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/LogisticChannel.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/LogisticChannel.java @@ -19,7 +19,7 @@ import io.swagger.annotations.ApiModelProperty; * @Description: 物流渠道 * @Author: jeecg-boot * @Date: 2022-05-31 - * @Version: V1.1 + * @Version: V1.2 */ @ApiModel(value = "logistic_channel对象", description = "物流渠道") @Data @@ -68,7 +68,13 @@ public class LogisticChannel implements Serializable { */ @Excel(name = "中文名称", width = 15) @ApiModelProperty(value = "中文名称") - private String zhName; + private java.lang.String zhName; + /** + * 渠道编码 + */ + @Excel(name = "渠道编码", width = 15) + @ApiModelProperty(value = "渠道编码") + private java.lang.String code; /** * 英文名称 */ @@ -101,16 +107,17 @@ public class LogisticChannel implements Serializable { @Excel(name = "是否活跃", width = 15) @ApiModelProperty(value = "是否活跃") private String active; - /** - * 是否活跃 - */ - @Excel(name = "渠道编码", width = 15) - @ApiModelProperty(value = "渠道编码") - private String code; /** * 仓库是否在中国 */ @Excel(name = "中国仓库", width = 15) @ApiModelProperty(value = "中国仓库") - private String warehouseInChina; + private java.lang.String warehouseInChina; + /** + * 对标物流渠道ID + */ + @Excel(name = "对标物流渠道ID", width = 15, dictTable = "logistic_channel", dicText = "internal_name", dicCode = "id") + @Dict(dictTable = "logistic_channel", dicText = "internal_name", dicCode = "id") + @ApiModelProperty(value = "对标物流渠道ID") + private java.lang.String samePriceChannelId; } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/SavRefund.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/SavRefund.java index 5ea5dc007..7b42179c6 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/SavRefund.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/SavRefund.java @@ -64,8 +64,9 @@ public class SavRefund implements Serializable { /** * 平台订单ID */ - @Excel(name = "平台订单ID", width = 15, dictTable = "platform_order", dicText = "platform_order_id", dicCode = "id") - @Dict(dictTable = "platform_order", dicText = "platform_order_id", dicCode = "id") +// @Excel(name = "平台订单ID", width = 15, dictTable = "platform_order", dicText = "platform_order_id", dicCode = "id") + @Excel(name = "平台订单ID", width = 15) +// @Dict(dictTable = "platform_order", dicText = "platform_order_id", dicCode = "id") @ApiModelProperty(value = "平台订单ID") private String platformOrderId; /** diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/LogisticChannelPriceMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/LogisticChannelPriceMapper.java index 71fca5d7e..7002cedd9 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/LogisticChannelPriceMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/LogisticChannelPriceMapper.java @@ -25,23 +25,23 @@ public interface LogisticChannelPriceMapper extends BaseMapper getAllCountry(); /** - * Find logistic channel price by indicting its channel name, and destination country, + * Find logistic channel price by indicating its channel name, and destination country, * also the platform order's shipping time and weight. * * @param channelName the channel name * @param shippingTime the shipping time * @param weight the weight - * @param country the country, represented by 2 letters code + * @param countryList the country, represented by 2 letters code * @return one propre price */ LogisticChannelPrice findBy( @Param("channelName") String channelName, @Param("date") Date shippingTime, @Param("trueWeight") BigDecimal weight, - @Param("country") String country); + @Param("countryList") List countryList); /** - * Find logistic channel price by indicting platform order's shipping time + * Find logistic channel price by indicating platform order's shipping time * * @param shippingTime the shipping time * @param distinctCountries Country names @@ -52,7 +52,7 @@ public interface LogisticChannelPriceMapper extends BaseMapper distinctChannelNames); /** - * Find logistic channel price by indicting its channel id, and destination country, + * Find logistic channel price by indicating its channel id, and destination country, * also the platform order's shipping time and weight. * * @param channelId the channel name diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderMapper.java index 4171f093a..bfd2580b3 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/PlatformOrderMapper.java @@ -81,7 +81,8 @@ public interface PlatformOrderMapper extends BaseMapper { List findUninvoicedOrders( @Param("shopIDs") List shopIds, @Param("begin") Date begin, - @Param("end") Date end + @Param("end") Date end, + @Param("warehouses") List warehouses ); /** @@ -114,13 +115,13 @@ public interface PlatformOrderMapper extends BaseMapper { String findPreviousCompleteInvoice(); - Date findEarliestUninvoicedPlatformOrder(List shopIDs); + Date findEarliestUninvoicedPlatformOrder(@Param("shopIDs") List shopIDs); - Date findLatestUninvoicedPlatformOrder(List shopIDs); + Date findLatestUninvoicedPlatformOrder(@Param("shopIDs") List shopIDs); - Date findEarliestUninvoicedPlatformOrderTime(List shopIDs, List erpStatuses); + Date findEarliestUninvoicedPlatformOrderTime(@Param("shopIDs") List shopIDs, @Param("erpStatuses") List erpStatuses); - Date findLatestUninvoicedPlatformOrderTime(List shopIDs, List erpStatuses); + Date findLatestUninvoicedPlatformOrderTime(@Param("shopIDs") List shopIDs, @Param("erpStatuses") List erpStatuses); /** * Find all platform order containing a particular sku @@ -167,11 +168,13 @@ public interface PlatformOrderMapper extends BaseMapper { List fetchOrderInShopsReadyForShopifySync(@Param("shops") List shopCodes); List fetchUninvoicedShippedOrderIDInShops(@Param("startDate") String startDate, - @Param("endDate") String endDate, - @Param("shops") List shops); + @Param("endDate") String endDate, + @Param("shops") List shops, + @Param("warehouses") List warehouses); List fetchUninvoicedShippedOrderIDInShopsAndOrderTime(@Param("startDate") String startDate, @Param("endDate") String endDate, @Param("shops") List shops, - @Param("erpStatuses") List erpStatuses); + @Param("erpStatuses") List erpStatuses, + @Param("warehouses") List warehouses); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/LogisticChannelPriceMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/LogisticChannelPriceMapper.xml index 70b7672f1..bdac56ddb 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/LogisticChannelPriceMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/LogisticChannelPriceMapper.xml @@ -20,19 +20,31 @@ WHERE zh_name = #{channelName} AND weight_range_start <= #{trueWeight} AND weight_range_end >= #{trueWeight} - AND effective_country = #{country} + AND effective_country IN + + #{country} + AND effective_date <= #{date} AND active = 1 ORDER BY effective_date DESC LIMIT 1 SELECT shipping_time - FROM platform_order + FROM platform_order AS po WHERE shipping_invoice_number IS NULL AND shipping_time IS NOT NULL AND erp_status = 3 @@ -222,7 +234,7 @@