diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/AddOrderAbnNumberRequest.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/AddOrderAbnNumberRequest.java new file mode 100644 index 000000000..ec5a97d2f --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/AddOrderAbnNumberRequest.java @@ -0,0 +1,15 @@ +package org.jeecg.modules.business.domain.api.mabang.dochangeorder; + +import org.jeecg.modules.business.domain.api.mabang.Request; + +public class AddOrderAbnNumberRequest extends Request { + public AddOrderAbnNumberRequest(AddOrderAbnNumberRequestBody body) { + super(body); + } + + @Override + public ChangeOrderResponse send() { + String jsonString = rawSend().getBody(); + return ChangeOrderResponse.parse(jsonString); + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/AddOrderAbnNumberRequestBody.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/AddOrderAbnNumberRequestBody.java new file mode 100644 index 000000000..4d70e5d40 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/AddOrderAbnNumberRequestBody.java @@ -0,0 +1,49 @@ +package org.jeecg.modules.business.domain.api.mabang.dochangeorder; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.jeecg.modules.business.domain.api.mabang.RequestBody; + +public class AddOrderAbnNumberRequestBody implements RequestBody { + + private String platformOrderId; + private final String abnNumber; + + // 韩国税号已添加在马帮系统中的ID是1042522 + private static final String KOREAN_TAX_NUMBER_LABEL_ID = "1042522"; + + public AddOrderAbnNumberRequestBody(String platformOrderId, String abnNumber) { + this.platformOrderId = platformOrderId; + this.abnNumber = abnNumber; + } + + @Override + public String api() { + return "order-do-change-order"; + } + + @Override + public JSONObject parameters() { + JSONObject json = new JSONObject(); + putNonNull(json, "platformOrderId", platformOrderId); + putNonNull(json, "abnnumber", abnNumber); + JSONArray labelId = new JSONArray(); + labelId.add(KOREAN_TAX_NUMBER_LABEL_ID); + putNonNull(json, "labelId", labelId); + return json; + } + + public String getPlatformOrderId() { + return platformOrderId; + } + + public void setPlatformOrderId(String platformOrderId) { + this.platformOrderId = platformOrderId; + } + + private void putNonNull(JSONObject json, String key, E value) { + if (value != null) { + json.put(key, value); + } + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/Order.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/Order.java index d87a18e20..9f4ee3e8f 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/Order.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/Order.java @@ -89,6 +89,11 @@ public class Order { */ @JSONField(name = "postCode") private String postcode; + /** + * 税号 + */ + @JSONField(name = "abnnumber") + private String taxNumber; /** * 状态 diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderListRequestBody.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderListRequestBody.java index fc560dc76..2156bf636 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderListRequestBody.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderListRequestBody.java @@ -22,6 +22,8 @@ public class OrderListRequestBody implements RequestBody { private String cursor = ""; private Integer page = 1; private boolean hasNext = true; + // 1.Orders of any status 2.Default value, must set status + private final static String ALL = "1"; @Override public String api() { @@ -31,7 +33,11 @@ public class OrderListRequestBody implements RequestBody { @Override public JSONObject parameters() { JSONObject json = new JSONObject(); - putNonNull(json, "status", status, OrderStatus::getCode); + if (platformOrderIds != null) { + putNonNull(json, "allstatus", ALL); + } else { + putNonNull(json, "status", status, OrderStatus::getCode); + } putNonNull(json, "platformOrderIds", platformOrderIds, (ids) -> String.join(",", ids)); if(datetimeType != null && platformOrderIds == null){ putNonNull(json, datetimeType.text() + "Start", startDate, formatter::format); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/CreateFulfillmentRequest.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/CreateFulfillmentRequest.java index 1494ba457..23c8808a3 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/CreateFulfillmentRequest.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/CreateFulfillmentRequest.java @@ -43,6 +43,7 @@ public class CreateFulfillmentRequest extends ShopifyRequest { POST_NL("https://postnl.post/", "PostNL International Mail", "LS[0-9]{9}NL"), COLI_COLI("https://www.colicoli.fr/trackings?id=%s", "Coli Coli", "CC[0-9]{14}[A-Z]*"), LUXEMBOURG_POST("https://www.post.lu/particuliers/colis-courrier/track-and-trace#/search", "Luxembourg Post", "LL[0-9]{9}LU"), + CJ_LOGISTICS("https://www.cjlogistics.com/ko/tool/parcel/tracking", "CJ대한통운", "57575[0-9]{7}"), ; private final String trackingUrl; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/GetOrderListRequest.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/GetOrderListRequest.java new file mode 100644 index 000000000..10df715a8 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/GetOrderListRequest.java @@ -0,0 +1,16 @@ +package org.jeecg.modules.business.domain.api.shopify; + +import com.alibaba.fastjson.JSONObject; +import org.springframework.http.HttpMethod; + +public class GetOrderListRequest extends ShopifyRequest { + + public GetOrderListRequest(ShopifyRequestBody body) { + super(HttpMethod.GET, body); + } + + @Override + protected JSONObject generateJson(ShopifyRequestBody body) { + return null; + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/GetOrderListRequestBody.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/GetOrderListRequestBody.java new file mode 100644 index 000000000..4898a2e4d --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/GetOrderListRequestBody.java @@ -0,0 +1,20 @@ +package org.jeecg.modules.business.domain.api.shopify; + +import java.util.List; + +public class GetOrderListRequestBody extends ShopifyRequestBody { + + public static final String ENDPOINT = "orders.json?status=open&limit=250&fields=id,note&ids=%s"; + + private final List ids; + + public GetOrderListRequestBody(String sitePrefix, String shopToken, List ids) { + super(sitePrefix, shopToken); + this.ids = ids; + } + + @Override + public String endpoint() { + return String.format(ENDPOINT, String.join(",", ids)); + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/GetOrderListResponse.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/GetOrderListResponse.java new file mode 100644 index 000000000..f5d182ec8 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/GetOrderListResponse.java @@ -0,0 +1,22 @@ +package org.jeecg.modules.business.domain.api.shopify; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +@Slf4j +@Data +public class GetOrderListResponse { + + @JsonProperty("orders") + private List orders; + + public GetOrderListResponse() { + } + + public GetOrderListResponse(List orders) { + this.orders = orders; + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/Order.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/Order.java new file mode 100644 index 000000000..031b8f03c --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/Order.java @@ -0,0 +1,26 @@ +package org.jeecg.modules.business.domain.api.shopify; + +import com.alibaba.fastjson.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.math.BigInteger; + +@Slf4j +@Data +public class Order { + + @JSONField(deserialize = false) + private BigInteger id; + + @JsonProperty("note") + private String note; + + public Order() { + } + + public boolean hasNote() { + return note != null; + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/ShopifyRequest.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/ShopifyRequest.java index c2977e906..fc38e000f 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/ShopifyRequest.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/ShopifyRequest.java @@ -10,7 +10,7 @@ import org.springframework.http.ResponseEntity; @Slf4j public abstract class ShopifyRequest { - private final static String BASE_URL = "https://%1$s.myshopify.com/admin/api/2022-10/%2$s"; + private final static String BASE_URL = "https://%1$s.myshopify.com/admin/api/2024-01/%2$s"; private final static String SHOPIFY_TOKEN_HEADER_NAME = "X-Shopify-Access-Token"; private final HttpMethod method; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/AddOrderAbnNumberJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/AddOrderAbnNumberJob.java new file mode 100644 index 000000000..030d101d2 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/AddOrderAbnNumberJob.java @@ -0,0 +1,138 @@ +package org.jeecg.modules.business.domain.job; + +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.codehaus.jettison.json.JSONArray; +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.modules.business.domain.api.mabang.dochangeorder.*; +import org.jeecg.modules.business.domain.api.mabang.getorderlist.*; +import org.jeecg.modules.business.entity.PlatformOrder; +import org.jeecg.modules.business.entity.PlatformOrderShopSync; +import org.jeecg.modules.business.service.IPlatformOrderService; +import org.jetbrains.annotations.NotNull; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +@Slf4j +public class AddOrderAbnNumberJob implements Job { + + private static final List DEFAULT_INCLUDED_SHOPS = Arrays.asList("JCH8 KR"); + private static final Integer DEFAULT_NUMBER_OF_THREADS = 10; + private static final Integer MABANG_API_RATE_LIMIT_PER_MINUTE = 300; + + @Autowired + private IPlatformOrderService platformOrderService; + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + List shops = DEFAULT_INCLUDED_SHOPS; + JobDataMap jobDataMap = context.getMergedJobDataMap(); + String parameter = ((String) jobDataMap.get("parameter")); + if (parameter != null) { + try { + JSONObject jsonObject = new JSONObject(parameter); + if (!jsonObject.isNull("includedShops")) { + JSONArray shopsArray = jsonObject.getJSONArray("includedShops"); + List shopList = new ArrayList<>(); + for (int i = 0; i < shopsArray.length(); i++) { + shopList.add(shopsArray.getString(i)); + } + shops = shopList; + } + } catch (JSONException e) { + log.error("Error while parsing parameter as JSON, falling back to default parameters."); + } + } + + List platformOrders = platformOrderService.fetchOrderInShopsReadyForAbnNumberJob(shops); + Map shopifyNoteMap = platformOrders.stream() + .collect(Collectors.toMap(PlatformOrder::getPlatformOrderId, PlatformOrder::getShopifyNote)); + if (platformOrders.isEmpty()) { + log.info("No order with abnNumbers ready to be added via MabangAPI, quitting now."); + return; + } + log.info("{} orders with abnNumbers ready to be added via MabangAPI", platformOrders.size()); + List platformOrderIds = new ArrayList<>(shopifyNoteMap.keySet()); + List> platformOrderIdLists = Lists.partition(platformOrderIds, 10); + List requests = new ArrayList<>(); + for (List platformOrderIdList : platformOrderIdLists) { + requests.add(new OrderListRequestBody().setPlatformOrderIds(platformOrderIdList)); + } + + log.info("Started retrieving those orders from Mabang for comparison to avoid re-writing"); + List mabangOrders = new ArrayList<>(); + ExecutorService executor = Executors.newFixedThreadPool(DEFAULT_NUMBER_OF_THREADS); + List> futures = requests.stream() + .map(request -> CompletableFuture.supplyAsync(() -> { + boolean success = false; + try { + OrderListRawStream rawStream = new OrderListRawStream(request); + OrderListStream stream = new OrderListStream(rawStream); + List orders = stream.all(); + mabangOrders.addAll(orders); + success = !orders.isEmpty(); + } catch (RuntimeException e) { + log.error("Error communicating with MabangAPI", e); + } + return success; + }, executor)) + .collect(Collectors.toList()); + List results = futures.stream().map(CompletableFuture::join).collect(Collectors.toList()); + long nbSuccesses = results.stream().filter(b -> b).count(); + log.info("{}/{} requests have succeeded.", nbSuccesses, requests.size()); + int syncedOrderNumber = mabangOrders.size(); + log.info("{}/{} mabang orders have been retrieved.", syncedOrderNumber, platformOrderIds.size()); + + log.info("Started comparison of {} orders to construct order modification request", mabangOrders.size()); + List addOrderAbnNumberRequestBodies = new ArrayList<>(); + mabangOrders.forEach(order -> { + String taxNumber = order.getTaxNumber(); + String platformOrderId = order.getPlatformOrderId(); + String abnNumber = shopifyNoteMap.get(platformOrderId); + if (taxNumber == null || taxNumber.isEmpty()) { + addOrderAbnNumberRequestBodies.add(new AddOrderAbnNumberRequestBody(platformOrderId, abnNumber)); + } else { + if (order.getTaxNumber().equalsIgnoreCase(abnNumber)) { + log.info("AbnNumber {} already present for order {}, ignoring", order.getTaxNumber(), platformOrderId); + } else { + // If the number EVER changes (EXTREMELY UNLIKELY), send it to Mabang anyway + addOrderAbnNumberRequestBodies.add(new AddOrderAbnNumberRequestBody(platformOrderId, abnNumber)); + } + } + }); + + ExecutorService throttlingExecutorService = ThrottlingExecutorService.createExecutorService(DEFAULT_NUMBER_OF_THREADS, + MABANG_API_RATE_LIMIT_PER_MINUTE, TimeUnit.MINUTES); + List> changeOrderFutures = addOrderAbnNumberRequestBodies.stream() + .map(addOrderAbnNumberRequestBody -> CompletableFuture.supplyAsync(() -> { + boolean success = false; + try { + AddOrderAbnNumberRequest addOrderAbnNumberRequest = new AddOrderAbnNumberRequest(addOrderAbnNumberRequestBody); + ChangeOrderResponse response = addOrderAbnNumberRequest.send(); + success = response.success(); + } catch (RuntimeException e) { + log.error("Error communicating with MabangAPI", e); + } + return success; + }, throttlingExecutorService)) + .collect(Collectors.toList()); + results = changeOrderFutures.stream().map(CompletableFuture::join).collect(Collectors.toList()); + nbSuccesses = results.stream().filter(b -> b).count(); + log.info("{}/{} order abnNumber adding requests have succeeded.", nbSuccesses, addOrderAbnNumberRequestBodies.size()); + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/AddPortraitTubeJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/AddPortraitTubeJob.java index 95ee6fba1..3fa53bf4a 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/AddPortraitTubeJob.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/AddPortraitTubeJob.java @@ -43,8 +43,11 @@ public class AddPortraitTubeJob implements Job { private static final List TUBE_SKUS = Arrays.asList(TUBE_30_SKU_SINGLE_DOUBLE, TUBE_50_SKU_MULTIPLE, TUBE_50_SKU_SINGLE, TUBE_40_SKU_MULTIPLE, TUBE_40_SKU_SINGLE); private static final String PREFIX_50_CANVAS = "JJ2501"; + private static final String PREFIX_50_CANVAS_CHROME = "JJ2001"; private static final String PREFIX_40_CANVAS = "JJ2500"; + private static final String PREFIX_40_CANVAS_CHROME = "JJ2000"; private static final String PREFIX_30_CANVAS = "JJ2502"; + private static final String PREFIX_30_CANVAS_CHROME = "JJ2002"; @Autowired private IPlatformOrderService platformOrderService; @@ -165,11 +168,11 @@ public class AddPortraitTubeJob implements Job { int quantity = orderItem.getQuantity(); if (TUBE_SKUS.contains(sku)) { currentTubes.add(Pair.of(sku, quantity)); - } else if (sku.startsWith(PREFIX_50_CANVAS)) { + } else if (sku.startsWith(PREFIX_50_CANVAS) || sku.startsWith(PREFIX_50_CANVAS_CHROME)) { canvas50Count += quantity; - } else if (sku.startsWith(PREFIX_40_CANVAS)) { + } else if (sku.startsWith(PREFIX_40_CANVAS) || sku.startsWith(PREFIX_40_CANVAS_CHROME)) { canvas40Count += quantity; - } else if (sku.startsWith(PREFIX_30_CANVAS)) { + } else if (sku.startsWith(PREFIX_30_CANVAS) || sku.startsWith(PREFIX_30_CANVAS_CHROME)) { canvas30Count += quantity; } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/MabangOrderSyncJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/MabangOrderSyncJob.java index f77d49d32..62f1e9fc2 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/MabangOrderSyncJob.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/MabangOrderSyncJob.java @@ -58,10 +58,7 @@ public class MabangOrderSyncJob implements Job { List> platformOrderIdLists = Lists.partition(platformOrderIds, 10); List requests = new ArrayList<>(); for (List platformOrderIdList : platformOrderIdLists) { - // There's no other way to sync orders of all statuses, so we duplicate requests to make sure - // that we get all orders - requests.add(new OrderListRequestBody().setPlatformOrderIds(platformOrderIdList).setStatus(OrderStatus.AllUnshipped)); - requests.add(new OrderListRequestBody().setPlatformOrderIds(platformOrderIdList).setStatus(OrderStatus.AllNonUnshipped)); + requests.add(new OrderListRequestBody().setPlatformOrderIds(platformOrderIdList)); } List mabangOrders = new ArrayList<>(); ExecutorService executor = Executors.newFixedThreadPool(DEFAULT_NUMBER_OF_THREADS); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ShopifyNoteJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ShopifyNoteJob.java new file mode 100644 index 000000000..7d964762f --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ShopifyNoteJob.java @@ -0,0 +1,121 @@ +package org.jeecg.modules.business.domain.job; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.codehaus.jettison.json.JSONArray; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.jeecg.modules.business.domain.api.shopify.*; +import org.jeecg.modules.business.entity.PlatformOrder; +import org.jeecg.modules.business.entity.PlatformOrderShopSync; +import org.jeecg.modules.business.entity.Shop; +import org.jeecg.modules.business.service.IPlatformOrderService; +import org.jeecg.modules.business.service.IShopService; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toMap; + +@Slf4j +public class ShopifyNoteJob implements Job { + + private static final List DEFAULT_INCLUDED_SHOPS = Arrays.asList("JCH8 KR"); + + private static final Integer DEFAULT_NUMBER_OF_THREADS = 10; + + @Autowired + private IPlatformOrderService platformOrderService; + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + List shops = DEFAULT_INCLUDED_SHOPS; + JobDataMap jobDataMap = context.getMergedJobDataMap(); + String parameter = ((String) jobDataMap.get("parameter")); + if (parameter != null) { + try { + JSONObject jsonObject = new JSONObject(parameter); + if (!jsonObject.isNull("includedShops")) { + JSONArray shopsArray = jsonObject.getJSONArray("includedShops"); + List shopList = new ArrayList<>(); + for (int i = 0; i < shopsArray.length(); i++) { + shopList.add(shopsArray.getString(i)); + } + shops = shopList; + } + } catch (JSONException e) { + log.error("Error while parsing parameter as JSON, falling back to default parameters."); + } + } + + ObjectMapper mapper = new ObjectMapper(); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + + List ordersWithoutShopifyNote = platformOrderService.fetchOrderInShopsWithoutShopifyNote(shops); + log.info("Fetched {} orders without Shopify note", ordersWithoutShopifyNote.size()); + Map> ordersByShop = ordersWithoutShopifyNote.stream().collect( + groupingBy(PlatformOrderShopSync::getShopifyPrefix)); + + List orders = new ArrayList<>(); + + ExecutorService executor = Executors.newFixedThreadPool(DEFAULT_NUMBER_OF_THREADS); + log.info("Constructing order retrieval requests"); + List getOrderListRequestBodyList = new ArrayList<>(); + ordersByShop.values().forEach(platformOrderShopSyncs -> { + if (!platformOrderShopSyncs.isEmpty()) { + List orderIds = platformOrderShopSyncs.stream().map(PlatformOrderShopSync::getPlatformOrderId).collect(Collectors.toList()); + String shopifyPrefix = platformOrderShopSyncs.get(0).getShopifyPrefix(); + String shopifyToken = platformOrderShopSyncs.get(0).getShopifyToken(); + getOrderListRequestBodyList.add(new GetOrderListRequestBody(shopifyPrefix, shopifyToken, orderIds)); + } + }); + + List> futures = getOrderListRequestBodyList.stream() + .map(body -> CompletableFuture.supplyAsync(() -> { + boolean success = false; + try { + GetOrderListRequest getOrderListRequest = new GetOrderListRequest(body); + String responseStr = getOrderListRequest.rawSend().getBody(); + GetOrderListResponse response = mapper.readValue(responseStr, GetOrderListResponse.class); + orders.addAll(response.getOrders()); + success = true; + } catch (RuntimeException e) { + log.error("Error communicating with ShopifyAPI", e); + } catch (JsonProcessingException e) { + log.error("Error processing json", e); + } + return success; + }, executor)) + .collect(Collectors.toList()); + List results = futures.stream().map(CompletableFuture::join).collect(Collectors.toList()); + long nbSuccesses = results.stream().filter(b -> b).count(); + log.info("{}/{} order retrieval requests have succeeded.", nbSuccesses, getOrderListRequestBodyList.size()); + log.info("{} orders have been retrieved.", orders.size()); + + log.info("Started adding Shopify notes to orders without one"); + Map orderNoteMap = orders.stream().filter(Order::hasNote).collect(toMap(order -> order.getId().toString(), Order::getNote)); + if (orderNoteMap.isEmpty()) { + log.info("No notes can be added to orders, quitting now"); + return; + } + List platformOrders = platformOrderService.selectByPlatformOrderIds(new ArrayList<>(orderNoteMap.keySet())); + platformOrders.forEach(platformOrder -> platformOrder.setShopifyNote(orderNoteMap.get(platformOrder.getPlatformOrderId()).trim())); + platformOrderService.updateBatchById(platformOrders); + log.info("Finished adding Shopify notes to {} orders without one into DB.", platformOrders.size()); + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/PlatformOrder.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/PlatformOrder.java index ee7d877d4..645107014 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/PlatformOrder.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/PlatformOrder.java @@ -18,8 +18,8 @@ import java.util.Date; /** * @Description: 平台订单表 * @Author: jeecg-boot - * @Date: 2023-11-28 - * @Version: V1.7 + * @Date: 2024-01-25 + * @Version: V1.8 */ @ApiModel(value = "platform_order对象", description = "平台订单表") @Data @@ -234,4 +234,22 @@ public class PlatformOrder implements Serializable { @Excel(name = "包材费", width = 15) @ApiModelProperty(value = "包材费") private java.math.BigDecimal packagingMaterialFee; + /** + * 收件人城市 + */ + @Excel(name = "收件人城市", width = 15) + @ApiModelProperty(value = "收件人城市") + private java.lang.String city; + /** + * Shopify平台留言 + */ + @Excel(name = "Shopify平台留言", width = 15) + @ApiModelProperty(value = "Shopify平台留言") + private java.lang.String shopifyNote; + /** + * 个人税号 + */ + @Excel(name = "个人税号", width = 15) + @ApiModelProperty(value = "个人税号") + private java.lang.String taxNumber; } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/Shop.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/Shop.java index 82587d91f..79654afb5 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/Shop.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/Shop.java @@ -16,8 +16,8 @@ import java.io.Serializable; /** * @Description: 店铺 * @Author: jeecg-boot - * @Date: 2021-08-11 - * @Version: V1.1 + * @Date: 2024-01-25 + * @Version: V1.2 */ @ApiModel(value = "Shop对象", description = "店铺") @Data @@ -91,10 +91,29 @@ public class Shop implements Serializable { @Excel(name = "订单服务费", width = 15) @ApiModelProperty(value = "订单服务费") private java.math.BigDecimal orderServiceFee; + /** - * 包材费 + * 是否活跃 */ - @Excel(name = "包材费", width = 15) - @ApiModelProperty(value = "包材费") + @Excel(name = "是否活跃", width = 15, dicCode = "yn") + @ApiModelProperty(value = "是否活跃") + private java.lang.String active; + /** + * Shopify前缀 + */ + @Excel(name = "Shopify前缀", width = 15) + @ApiModelProperty(value = "Shopify前缀") + private java.lang.String shopifyPrefix; + /** + * Shopify API Token + */ + @Excel(name = "Shopify API Token", width = 15) + @ApiModelProperty(value = "Shopify API Token") + private java.lang.String shopifyToken; + /** + * 海外仓包材费 + */ + @Excel(name = "海外仓包材费", width = 15) + @ApiModelProperty(value = "海外仓包材费") private java.math.BigDecimal packagingMaterialFee; } 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 5188ccce8..6fd072949 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 @@ -168,6 +168,8 @@ public interface PlatformOrderMapper extends BaseMapper { @Param("excludedTrackingNumbersRegex") String excludedTrackingNumbersRegex); List fetchOrderInShopsReadyForShopifySync(@Param("shops") List shopCodes); + List fetchOrderInShopsWithoutShopifyNote(@Param("shops") List shopCodes); + List fetchOrderInShopsReadyForAbnNumberJob(@Param("shops") List shopCodes); List fetchUninvoicedShippedOrderIDInShops(@Param("startDate") String startDate, @Param("endDate") String endDate, diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMabangMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMabangMapper.xml index 351832dff..f0967b264 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMabangMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMabangMapper.xml @@ -96,6 +96,11 @@ when #{item.id} then #{item.postcode} end, + tax_number = case id + + when #{item.id} then #{item.taxNumber} + + end, erp_status = case id when #{item.id} then #{item.status} @@ -157,7 +162,7 @@ update_time, shop_id, logistic_channel_name, platform_order_id, platform_order_number, erp_order_id, tracking_number, internal_tracking_number, order_time, shipping_time, recipient, - country, postcode, erp_status, product_available, can_send) + country, postcode, tax_number, erp_status, product_available, can_send) VALUES ( @@ -178,6 +183,7 @@ #{order.recipient}, #{order.country}, #{order.postcode}, + #{order.taxNumber}, #{order.status}, #{order.productAvailable}, #{order.canSend} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMapper.xml index c8d92c9ba..5cb4065ec 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/PlatformOrderMapper.xml @@ -466,6 +466,45 @@ ORDER BY shipping_time; + + + +