mirror of https://github.com/jeecgboot/jeecg-boot
commit
33fd0f01ac
|
@ -13,13 +13,15 @@ import java.util.function.Function;
|
||||||
public class OrderSuspendRequestBody implements RequestBody {
|
public class OrderSuspendRequestBody implements RequestBody {
|
||||||
|
|
||||||
private String platformOrderId;
|
private String platformOrderId;
|
||||||
private String abnormal_label_name = "客户要求暂时不处理";
|
private String abnormalLabelName;
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
public OrderSuspendRequestBody(String platformOrderId, String description) {
|
public OrderSuspendRequestBody(String platformOrderId, String abnormalLabelName, String description) {
|
||||||
this.platformOrderId = platformOrderId;
|
this.platformOrderId = platformOrderId;
|
||||||
|
this.abnormalLabelName = abnormalLabelName;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String api() {
|
public String api() {
|
||||||
return "order-do-order-abnormal";
|
return "order-do-order-abnormal";
|
||||||
|
@ -29,8 +31,8 @@ public class OrderSuspendRequestBody implements RequestBody {
|
||||||
public Map<String, Object> parameters() {
|
public Map<String, Object> parameters() {
|
||||||
JSONObject json = new JSONObject();
|
JSONObject json = new JSONObject();
|
||||||
putNonNull(json, "platformOrderId", platformOrderId);
|
putNonNull(json, "platformOrderId", platformOrderId);
|
||||||
putNonNull(json, "abnormal_label_name", abnormal_label_name);
|
putNonNull(json, "abnormal_label_name", abnormalLabelName);
|
||||||
putNonNull(json, "description", description);
|
putNonNull(json, "descr", description);
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
private <E> void putNonNull(JSONObject json, String key, E value) {
|
private <E> void putNonNull(JSONObject json, String key, E value) {
|
||||||
|
|
|
@ -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() {}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ import java.util.List;
|
||||||
|
|
||||||
public class GetOrderListRequestBody extends ShopifyRequestBody {
|
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<String> ids;
|
private final List<String> ids;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ import lombok.Data;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Data
|
@Data
|
||||||
|
@ -17,10 +19,24 @@ public class Order {
|
||||||
@JsonProperty("note")
|
@JsonProperty("note")
|
||||||
private String note;
|
private String note;
|
||||||
|
|
||||||
|
@JsonProperty("discount_codes")
|
||||||
|
private List<DiscountCode> discountCodes;
|
||||||
|
|
||||||
public Order() {
|
public Order() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasNote() {
|
public boolean hasNote() {
|
||||||
return note != null;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import org.springframework.http.ResponseEntity;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class ShopifyRequest {
|
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 static String SHOPIFY_TOKEN_HEADER_NAME = "X-Shopify-Access-Token";
|
||||||
|
|
||||||
private final HttpMethod method;
|
private final HttpMethod method;
|
||||||
|
|
|
@ -158,8 +158,7 @@ public class ChangeWarehouseJob implements Job {
|
||||||
Responses responses = new Responses();
|
Responses responses = new Responses();
|
||||||
List<CompletableFuture<Responses>> abnormalFutures = ordersToSetAbnormal.stream()
|
List<CompletableFuture<Responses>> abnormalFutures = ordersToSetAbnormal.stream()
|
||||||
.map(id -> CompletableFuture.supplyAsync(() -> {
|
.map(id -> CompletableFuture.supplyAsync(() -> {
|
||||||
OrderSuspendRequestBody body = new OrderSuspendRequestBody(id, "");
|
OrderSuspendRequestBody body = new OrderSuspendRequestBody(id, DEFAULT_ABNORMAL_LABEL_NAME, "");
|
||||||
body.setAbnormal_label_name(DEFAULT_ABNORMAL_LABEL_NAME);
|
|
||||||
OrderSuspendRequest request = new OrderSuspendRequest(body);
|
OrderSuspendRequest request = new OrderSuspendRequest(body);
|
||||||
OrderSuspendResponse response = request.send();
|
OrderSuspendResponse response = request.send();
|
||||||
Responses r = new Responses();
|
Responses r = new Responses();
|
||||||
|
|
|
@ -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<String> 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<String> 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<String> 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<PlatformOrderShopSync> ordersWithoutShopifyNote = platformOrderService.fetchOrderInShopsWithoutShopifyNote(shops);
|
||||||
|
log.info("Fetched {} orders without Shopify promo code", ordersWithoutShopifyNote.size());
|
||||||
|
Map<String, List<PlatformOrderShopSync>> ordersByShop = ordersWithoutShopifyNote.stream().collect(
|
||||||
|
groupingBy(PlatformOrderShopSync::getShopifyPrefix));
|
||||||
|
|
||||||
|
List<Order> orders = new ArrayList<>();
|
||||||
|
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(DEFAULT_NUMBER_OF_THREADS);
|
||||||
|
log.info("Constructing order retrieval requests");
|
||||||
|
List<GetOrderListRequestBody> getOrderListRequestBodyList = new ArrayList<>();
|
||||||
|
ordersByShop.values().forEach(platformOrderShopSyncs -> {
|
||||||
|
if (!platformOrderShopSyncs.isEmpty()) {
|
||||||
|
List<String> 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<CompletableFuture<Boolean>> 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<Boolean> 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<String, String> 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<String> ordersToAddPromoCode = new ArrayList<>(orderNoteMap.keySet());
|
||||||
|
List<PlatformOrder> 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<String> orderIdsByShopifyNote = platformOrderService.fetchPlatformOrderIdsByShopifyNote(promoCode);
|
||||||
|
String finalPromoCode = promoCode;
|
||||||
|
List<CompletableFuture<Boolean>> 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<Boolean> abnormalResults = abnormalFutures.stream().map(CompletableFuture::join).collect(Collectors.toList());
|
||||||
|
log.info("Successfully set {}/{} orders to abnormal.", abnormalResults.size(), orderIdsByShopifyNote.size());
|
||||||
|
executor.shutdown();
|
||||||
|
}
|
||||||
|
}
|
|
@ -261,4 +261,6 @@ public interface PlatformOrderMapper extends BaseMapper<PlatformOrder> {
|
||||||
Map<String, PlatformOrder> selectBatchUninvoicedIdsForUpdate(@Param("ids") List<String> orderIds);
|
Map<String, PlatformOrder> selectBatchUninvoicedIdsForUpdate(@Param("ids") List<String> orderIds);
|
||||||
|
|
||||||
PlatformOrder selectForUpdateSkipLock(@Param("id") String orderId);
|
PlatformOrder selectForUpdateSkipLock(@Param("id") String orderId);
|
||||||
|
|
||||||
|
List<String> fetchPlatformOrderIdsByShopifyNote(String shopifyNote);
|
||||||
}
|
}
|
||||||
|
|
|
@ -485,7 +485,7 @@
|
||||||
>
|
>
|
||||||
#{shop}
|
#{shop}
|
||||||
</foreach>
|
</foreach>
|
||||||
AND erp_status <> 5
|
AND erp_status in (1,2)
|
||||||
AND shopify_note IS NULL
|
AND shopify_note IS NULL
|
||||||
ORDER BY order_time;
|
ORDER BY order_time;
|
||||||
</select>
|
</select>
|
||||||
|
@ -1405,4 +1405,11 @@
|
||||||
WHERE id = #{id}
|
WHERE id = #{id}
|
||||||
FOR UPDATE;
|
FOR UPDATE;
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="fetchPlatformOrderIdsByShopifyNote" resultType="java.lang.String">
|
||||||
|
SELECT platform_order_id
|
||||||
|
FROM platform_order
|
||||||
|
WHERE shopify_note LIKE #{shopifyNote}
|
||||||
|
AND erp_status in (1,2);
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
|
@ -269,7 +269,6 @@ public interface IPlatformOrderService extends IService<PlatformOrder> {
|
||||||
|
|
||||||
Map<String, String> fetchShippingPeriodAndType(String invoiceNumber);
|
Map<String, String> fetchShippingPeriodAndType(String invoiceNumber);
|
||||||
|
|
||||||
|
|
||||||
void anonymizePersonalData(int indirectClientAnonymizationPeriod);
|
void anonymizePersonalData(int indirectClientAnonymizationPeriod);
|
||||||
|
|
||||||
List<PlatformOrderOption> ordersByShop(String shopID);
|
List<PlatformOrderOption> ordersByShop(String shopID);
|
||||||
|
@ -297,4 +296,6 @@ public interface IPlatformOrderService extends IService<PlatformOrder> {
|
||||||
int countListByClientAndShops(String clientId, List<String> shopIDs, String start, String end, String invoicingMethod, List<String> warehouses);
|
int countListByClientAndShops(String clientId, List<String> shopIDs, String start, String end, String invoicingMethod, List<String> warehouses);
|
||||||
|
|
||||||
PlatformOrder selectForUpdateSkipLock(String orderId);
|
PlatformOrder selectForUpdateSkipLock(String orderId);
|
||||||
|
|
||||||
|
List<String> fetchPlatformOrderIdsByShopifyNote(String shopifyNote);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,7 @@ public class PlatformOrderMabangServiceImpl extends ServiceImpl<PlatformOrderMab
|
||||||
|
|
||||||
private static final Integer DEFAULT_NUMBER_OF_THREADS = 2;
|
private static final Integer DEFAULT_NUMBER_OF_THREADS = 2;
|
||||||
private static final Integer MABANG_API_RATE_LIMIT_PER_MINUTE = 10;
|
private static final Integer MABANG_API_RATE_LIMIT_PER_MINUTE = 10;
|
||||||
|
private static final String ABNORMAL_LABEL_NAME = "客户要求暂时不处理";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
|
@ -235,7 +236,7 @@ public class PlatformOrderMabangServiceImpl extends ServiceImpl<PlatformOrderMab
|
||||||
|
|
||||||
List<CompletableFuture<Responses>> futures = orderIds.stream()
|
List<CompletableFuture<Responses>> futures = orderIds.stream()
|
||||||
.map(id -> CompletableFuture.supplyAsync(() -> {
|
.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);
|
OrderSuspendRequest request = new OrderSuspendRequest(body);
|
||||||
OrderSuspendResponse response = request.send();
|
OrderSuspendResponse response = request.send();
|
||||||
Responses r = new Responses();
|
Responses r = new Responses();
|
||||||
|
|
|
@ -610,4 +610,9 @@ public class PlatformOrderServiceImpl extends ServiceImpl<PlatformOrderMapper, P
|
||||||
public PlatformOrder selectForUpdateSkipLock(String orderId) {
|
public PlatformOrder selectForUpdateSkipLock(String orderId) {
|
||||||
return platformOrderMap.selectForUpdateSkipLock(orderId);
|
return platformOrderMap.selectForUpdateSkipLock(orderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> fetchPlatformOrderIdsByShopifyNote(String shopifyNote) {
|
||||||
|
return platformOrderMap.fetchPlatformOrderIdsByShopifyNote(shopifyNote);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue