diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderAbnormal/OrderSuspendRequestBody.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderAbnormal/OrderSuspendRequestBody.java index ba95beaba..0d64d5ca9 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderAbnormal/OrderSuspendRequestBody.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderAbnormal/OrderSuspendRequestBody.java @@ -13,13 +13,15 @@ import java.util.function.Function; public class OrderSuspendRequestBody implements RequestBody { private String platformOrderId; - private String abnormal_label_name = "客户要求暂时不处理"; + private String abnormalLabelName; private String description; - public OrderSuspendRequestBody(String platformOrderId, String description) { + public OrderSuspendRequestBody(String platformOrderId, String abnormalLabelName, String description) { this.platformOrderId = platformOrderId; + this.abnormalLabelName = abnormalLabelName; this.description = description; } + @Override public String api() { return "order-do-order-abnormal"; @@ -29,8 +31,8 @@ public class OrderSuspendRequestBody implements RequestBody { public Map parameters() { JSONObject json = new JSONObject(); putNonNull(json, "platformOrderId", platformOrderId); - putNonNull(json, "abnormal_label_name", abnormal_label_name); - putNonNull(json, "description", description); + putNonNull(json, "abnormal_label_name", abnormalLabelName); + putNonNull(json, "descr", description); return json; } private void putNonNull(JSONObject json, String key, E value) { diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/DiscountCode.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/DiscountCode.java new file mode 100644 index 000000000..49add5e66 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/shopify/DiscountCode.java @@ -0,0 +1,12 @@ +package org.jeecg.modules.business.domain.api.shopify; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +class DiscountCode{ + @JsonProperty("code") + private String code; + + public DiscountCode() {} +} \ No newline at end of file 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 index 4898a2e4d..792a1f362 100644 --- 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 @@ -4,7 +4,7 @@ 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"; + public static final String ENDPOINT = "orders.json?status=open&limit=250&fields=id,note,discount_codes&ids=%s"; private final List ids; 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 index 031b8f03c..d8035d793 100644 --- 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 @@ -6,6 +6,8 @@ import lombok.Data; import lombok.extern.slf4j.Slf4j; import java.math.BigInteger; +import java.util.List; +import java.util.stream.Collectors; @Slf4j @Data @@ -17,10 +19,24 @@ public class Order { @JsonProperty("note") private String note; + @JsonProperty("discount_codes") + private List discountCodes; + public Order() { } public boolean hasNote() { return note != null; } + + public boolean hasDiscountCodes() { + return discountCodes != null && !discountCodes.isEmpty(); + } + + public String getDiscountCode() { + if (discountCodes != null && !discountCodes.isEmpty()) { + return discountCodes.stream().map(DiscountCode::getCode).collect(Collectors.joining(",")); + } + return 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 fc38e000f..29b10b359 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/2024-01/%2$s"; + private final static String BASE_URL = "https://%1$s.myshopify.com/admin/api/2025-04/%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/ChangeWarehouseJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ChangeWarehouseJob.java index 6fe18bd16..17c6ecbd7 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ChangeWarehouseJob.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ChangeWarehouseJob.java @@ -158,8 +158,7 @@ public class ChangeWarehouseJob implements Job { Responses responses = new Responses(); List> abnormalFutures = ordersToSetAbnormal.stream() .map(id -> CompletableFuture.supplyAsync(() -> { - OrderSuspendRequestBody body = new OrderSuspendRequestBody(id, ""); - body.setAbnormal_label_name(DEFAULT_ABNORMAL_LABEL_NAME); + OrderSuspendRequestBody body = new OrderSuspendRequestBody(id, DEFAULT_ABNORMAL_LABEL_NAME, ""); OrderSuspendRequest request = new OrderSuspendRequest(body); OrderSuspendResponse response = request.send(); Responses r = new Responses(); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ShopifyPromoCodeJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ShopifyPromoCodeJob.java new file mode 100644 index 000000000..3d0e10949 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ShopifyPromoCodeJob.java @@ -0,0 +1,148 @@ +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.mabang.orderDoOrderAbnormal.OrderSuspendRequest; +import org.jeecg.modules.business.domain.api.mabang.orderDoOrderAbnormal.OrderSuspendRequestBody; +import org.jeecg.modules.business.domain.api.mabang.orderDoOrderAbnormal.OrderSuspendResponse; +import org.jeecg.modules.business.domain.api.shopify.GetOrderListRequest; +import org.jeecg.modules.business.domain.api.shopify.GetOrderListRequestBody; +import org.jeecg.modules.business.domain.api.shopify.GetOrderListResponse; +import org.jeecg.modules.business.domain.api.shopify.Order; +import org.jeecg.modules.business.entity.PlatformOrder; +import org.jeecg.modules.business.entity.PlatformOrderShopSync; +import org.jeecg.modules.business.service.IPlatformOrderService; +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.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.*; +import static java.util.stream.Collectors.toList; + +@Slf4j +public class ShopifyPromoCodeJob implements Job { + + private static final List DEFAULT_INCLUDED_SHOPS = Arrays.asList("AC"); + + private static final Integer DEFAULT_NUMBER_OF_THREADS = 10; + + private final String DEFAULT_ABNORMAL_LABEL_NAME = "AC自行处理"; + + private final String DEFAULT_PROMO_CODE = "BARBE20"; + + @Autowired + private IPlatformOrderService platformOrderService; + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + List shops = DEFAULT_INCLUDED_SHOPS; + String promoCode = DEFAULT_PROMO_CODE; + 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; + } + if (!jsonObject.isNull("promoCode")) { + promoCode = jsonObject.getString("promoCode"); + } + } 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 promo code", 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 promo code to orders without one"); + Map orderNoteMap = orders.stream().filter(Order::hasDiscountCodes).collect(toMap(order -> order.getId().toString(), Order::getDiscountCode)); + if (orderNoteMap.isEmpty()) { + log.info("No promo code can be added to orders, quitting now"); + } else { + List ordersToAddPromoCode = new ArrayList<>(orderNoteMap.keySet()); + List platformOrders = platformOrderService.selectByPlatformOrderIds(ordersToAddPromoCode); + platformOrders.forEach(platformOrder -> platformOrder.setShopifyNote(orderNoteMap.get(platformOrder.getPlatformOrderId()).trim())); + platformOrderService.updateBatchById(platformOrders); + log.info("Finished adding Shopify promo code to {} orders without one into DB.", platformOrders.size()); + } + + log.info("Setting orders to abnormal..."); + List orderIdsByShopifyNote = platformOrderService.fetchPlatformOrderIdsByShopifyNote(promoCode); + String finalPromoCode = promoCode; + List> abnormalFutures = orderIdsByShopifyNote.stream() + .map(id -> CompletableFuture.supplyAsync(() -> { + OrderSuspendRequestBody body = new OrderSuspendRequestBody(id, DEFAULT_ABNORMAL_LABEL_NAME, finalPromoCode); + OrderSuspendRequest request = new OrderSuspendRequest(body); + OrderSuspendResponse response = request.send(); + return response.success(); + }, executor)) + .collect(toList()); + List abnormalResults = abnormalFutures.stream().map(CompletableFuture::join).collect(Collectors.toList()); + log.info("Successfully set {}/{} orders to abnormal.", abnormalResults.size(), orderIdsByShopifyNote.size()); + executor.shutdown(); + } +} 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 c5506b7cc..b7a315791 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 @@ -261,4 +261,6 @@ public interface PlatformOrderMapper extends BaseMapper { Map selectBatchUninvoicedIdsForUpdate(@Param("ids") List orderIds); PlatformOrder selectForUpdateSkipLock(@Param("id") String orderId); + + List fetchPlatformOrderIdsByShopifyNote(String shopifyNote); } 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 5fcdfcf38..fdcf5135a 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 @@ -485,7 +485,7 @@ > #{shop} - AND erp_status <> 5 + AND erp_status in (1,2) AND shopify_note IS NULL ORDER BY order_time; @@ -1405,4 +1405,11 @@ WHERE id = #{id} FOR UPDATE; + + diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderService.java index 870b1ac70..6c7e52d3a 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderService.java @@ -269,7 +269,6 @@ public interface IPlatformOrderService extends IService { Map fetchShippingPeriodAndType(String invoiceNumber); - void anonymizePersonalData(int indirectClientAnonymizationPeriod); List ordersByShop(String shopID); @@ -297,4 +296,6 @@ public interface IPlatformOrderService extends IService { int countListByClientAndShops(String clientId, List shopIDs, String start, String end, String invoicingMethod, List warehouses); PlatformOrder selectForUpdateSkipLock(String orderId); + + List fetchPlatformOrderIdsByShopifyNote(String shopifyNote); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderMabangServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderMabangServiceImpl.java index 509072f97..af27ea1ef 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderMabangServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderMabangServiceImpl.java @@ -61,6 +61,7 @@ public class PlatformOrderMabangServiceImpl extends ServiceImpl> futures = orderIds.stream() .map(id -> CompletableFuture.supplyAsync(() -> { - OrderSuspendRequestBody body = new OrderSuspendRequestBody(id, sysUser.getRealname() + " : " + orderOperation.getReason()); + OrderSuspendRequestBody body = new OrderSuspendRequestBody(id, ABNORMAL_LABEL_NAME,sysUser.getRealname() + " : " + orderOperation.getReason()); OrderSuspendRequest request = new OrderSuspendRequest(body); OrderSuspendResponse response = request.send(); Responses r = new Responses(); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderServiceImpl.java index 75a4926d8..0eb850236 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/PlatformOrderServiceImpl.java @@ -610,4 +610,9 @@ public class PlatformOrderServiceImpl extends ServiceImpl fetchPlatformOrderIdsByShopifyNote(String shopifyNote) { + return platformOrderMap.fetchPlatformOrderIdsByShopifyNote(shopifyNote); + } }