diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/ChangeOrderRequestBody.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/ChangeOrderRequestBody.java index 86a79e8f3..d03bdf54b 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/ChangeOrderRequestBody.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/ChangeOrderRequestBody.java @@ -24,6 +24,7 @@ public class ChangeOrderRequestBody implements RequestBody { private final static String DEFAULT_WAREHOUSE_NAME = "SZBA宝安仓"; + @Getter public enum OperationType { MODIFY(1), REMOVE(2), diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/ChangeWarehouseRequest.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/ChangeWarehouseRequest.java new file mode 100644 index 000000000..6e25d0aba --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/ChangeWarehouseRequest.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 ChangeWarehouseRequest extends Request { + public ChangeWarehouseRequest(ChangeWarehouseRequestBody 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/ChangeWarehouseRequestBody.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/ChangeWarehouseRequestBody.java new file mode 100644 index 000000000..b27eb57ca --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/dochangeorder/ChangeWarehouseRequestBody.java @@ -0,0 +1,75 @@ +package org.jeecg.modules.business.domain.api.mabang.dochangeorder; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import lombok.Getter; +import lombok.Setter; +import org.jeecg.modules.business.domain.api.mabang.RequestBody; +import org.jeecg.modules.business.domain.api.mabang.getorderlist.Order; +import org.jeecg.modules.business.domain.api.mabang.getorderlist.OrderItem; + +import java.util.function.Function; + +import static org.jeecg.modules.business.domain.api.mabang.dochangeorder.ChangeOrderRequestBody.OperationType; +@Getter +@Setter +public class ChangeWarehouseRequestBody implements RequestBody { + private Order order; + private String platformOrderId; + private String warehouseName; + private String recipient; + private String street1; + private String street2; + + public ChangeWarehouseRequestBody(Order order, String warehouseName) { + this.platformOrderId = order.getPlatformOrderId(); + this.warehouseName = warehouseName; + this.recipient = order.getRecipient(); + this.street1 = order.getAddress(); + this.street2 = order.getAddress2(); + this.order = order; + } + + @Override + public String api() { + return "order-do-change-order"; + } + + @Override + public JSONObject parameters() { + JSONObject json = new JSONObject(); + JSONArray stockDataArray = new JSONArray(); + putNonNull(json, "platformOrderId", platformOrderId); + putNonNull(json, "buyerName", recipient); + putNonNull(json, "street1", street1); + putNonNull(json, "street2", street2); + if(order.getOrderItems() != null && !order.getOrderItems().isEmpty()) { + for(OrderItem orderItem : order.getOrderItems()) { + if(!isSkuValidFormat(orderItem.getErpCode())) + continue; + JSONObject stockData = new JSONObject(); + stockData.put("type", OperationType.MODIFY.getCode()); + stockData.put("stockSku", orderItem.getErpCode()); + stockData.put("warehouseName", warehouseName); + stockData.put("erpOrderItemId", orderItem.getErpOrderItemId()); + stockDataArray.add(stockData); + } + } + putNonNull(json, "stockData", stockDataArray.toJSONString()); + return json; + } + private boolean isSkuValidFormat(String sku) { + return sku != null && !sku.matches("^[0-9]+$"); + } + private void putNonNull(JSONObject json, String key, E value) { + if (value != null) { + json.put(key, value); + } + } + + private void putNonNull(JSONObject json, String key, E value, Function mapper) { + if (value != null) { + json.put(key, mapper.apply(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 9f4ee3e8f..9ff4916f1 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,16 @@ public class Order { */ @JSONField(name = "postCode") private String postcode; + /** + * 买家地址1 + */ + @JSONField(name = "street1") + private String address; + /** + * 买家地址2 + */ + @JSONField(name = "street2") + private String address2; /** * 税号 */ @@ -127,6 +137,10 @@ public class Order { @TableField(exist = false) private List orderItems; + @JSONField(name = "orderTypeNew") + @TableField(exist = false) + private OrderTypeNew orderType; + @JSONField(name = "phone1") private String phone1; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderItem.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderItem.java index 771fc776c..28f1839ca 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderItem.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderItem.java @@ -24,6 +24,11 @@ public class OrderItem { @JSONField(name = "originOrderId") private String originOrderId; + @JSONField(name="erpOrderItemId") + private String erpOrderItemId; + @JSONField(name = "stockWarehouseName") + private String warehouseName; + /** * 1 = 有货 * 2 = 缺货 diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderTypeLabel.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderTypeLabel.java new file mode 100644 index 000000000..d9f995234 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderTypeLabel.java @@ -0,0 +1,12 @@ +package org.jeecg.modules.business.domain.api.mabang.getorderlist; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +@Data +public class OrderTypeLabel { + @JSONField(name = "typeId") + private String typeId; + @JSONField(name = "name") + private String name; +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderTypeNew.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderTypeNew.java new file mode 100644 index 000000000..79e49419f --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/getorderlist/OrderTypeNew.java @@ -0,0 +1,12 @@ +package org.jeecg.modules.business.domain.api.mabang.getorderlist; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +@Data +public class OrderTypeNew { + @JSONField(name = "normalLabels") + private OrderTypeLabel[] normalLabels; + @JSONField(name = "abnormalLabels") + private OrderTypeLabel[] abnormalLabels; +} 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 322b32131..ba95beaba 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,7 +13,7 @@ import java.util.function.Function; public class OrderSuspendRequestBody implements RequestBody { private String platformOrderId; - private final String abnormal_label_name = "客户要求暂时不处理"; + private String abnormal_label_name = "客户要求暂时不处理"; private String description; public OrderSuspendRequestBody(String platformOrderId, String description) { diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderNormal/OrderToNormalRequest.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderNormal/OrderToNormalRequest.java new file mode 100644 index 000000000..ce97c5a0c --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderNormal/OrderToNormalRequest.java @@ -0,0 +1,30 @@ +package org.jeecg.modules.business.domain.api.mabang.orderDoOrderNormal; + +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.jeecg.modules.business.domain.api.mabang.Request; +import org.springframework.http.ResponseEntity; + +/** + * This class contains some key information and necessary procedures + * to send a request to mabang "order-do-order-abnormal" API, for example: target URL, + * correspondent HTTP method, procedure to generate authorization. + *

+ * One can use static method {@code sendRequest} to send request with body, + * and then get respective response. Or use instance of this class, see below. + *

+ */ +@Slf4j +public class OrderToNormalRequest extends Request { + + public OrderToNormalRequest(OrderToNormalRequestBody body) { + super(body); + } + + + @Override + public OrderToNormalResponse send() { + ResponseEntity res = rawSend(); + return OrderToNormalResponse.parse(JSON.parseObject(res.getBody())); + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderNormal/OrderToNormalRequestBody.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderNormal/OrderToNormalRequestBody.java new file mode 100644 index 000000000..ed5b2abfa --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderNormal/OrderToNormalRequestBody.java @@ -0,0 +1,41 @@ +package org.jeecg.modules.business.domain.api.mabang.orderDoOrderNormal; + +import com.alibaba.fastjson.JSONObject; +import lombok.Getter; +import lombok.Setter; +import org.jeecg.modules.business.domain.api.mabang.RequestBody; + +import java.util.Map; +import java.util.function.Function; + +@Getter +@Setter +public class OrderToNormalRequestBody implements RequestBody { + + private String platformOrderId; + + public OrderToNormalRequestBody(String platformOrderId) { + this.platformOrderId = platformOrderId; + } + @Override + public String api() { + return "order-do-order-normal"; + } + + @Override + public Map parameters() { + JSONObject json = new JSONObject(); + putNonNull(json, "platformOrderId", platformOrderId); + return json; + } + private void putNonNull(JSONObject json, String key, E value) { + if (value != null) { + json.put(key, value); + } + } + private void putNonNull(JSONObject json, String key, E value, Function mapper) { + if (value != null) { + json.put(key, mapper.apply(value)); + } + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderNormal/OrderToNormalRequestErrorException.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderNormal/OrderToNormalRequestErrorException.java new file mode 100644 index 000000000..9bcaacfa8 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderNormal/OrderToNormalRequestErrorException.java @@ -0,0 +1,11 @@ +package org.jeecg.modules.business.domain.api.mabang.orderDoOrderNormal; + +/** + * This class represents error that is returned by target order-do-order-abnormal API + * Message will contain error details. + */ +public class OrderToNormalRequestErrorException extends RuntimeException { + public OrderToNormalRequestErrorException(String msg) { + super(msg); + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderNormal/OrderToNormalResponse.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderNormal/OrderToNormalResponse.java new file mode 100644 index 000000000..1ed74c259 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/orderDoOrderNormal/OrderToNormalResponse.java @@ -0,0 +1,45 @@ +package org.jeecg.modules.business.domain.api.mabang.orderDoOrderNormal; + +import com.alibaba.fastjson.JSONObject; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.jeecg.modules.business.domain.api.mabang.Response; + +/** + * Immutable object + */ +@Slf4j +@Getter +public class OrderToNormalResponse extends Response { + private final String message; + + OrderToNormalResponse(Code successCode, String message) { + super(successCode); + this.message = message; + } + + /** + * Make an instance by parsing json, it only checks validity of code. + * if json is not valid, return null + * + * @param json the json to parse + * @return Instance + * @throws OrderToNormalRequestErrorException if response code represents error. + */ + public static OrderToNormalResponse parse(JSONObject json) throws OrderToNormalRequestErrorException { + log.debug("Constructing a response by json."); + String code = json.getString("code"); + String message = json.getString("message"); + if (code.equals("200")) + return new OrderToNormalResponse(Code.SUCCESS, message); + else + return new OrderToNormalResponse(Code.ERROR, message); + } + + @Override + public String toString() { + return "OrderToNormalResponse{" + + ", code=" + this.success() + + '}'; + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ChangeWareHouseParam.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ChangeWareHouseParam.java new file mode 100644 index 000000000..78478a16b --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ChangeWareHouseParam.java @@ -0,0 +1,12 @@ +package org.jeecg.modules.business.domain.job; + +import lombok.Data; + +import java.util.List; + +@Data +public class ChangeWareHouseParam { + private String shop; + private List skus; + private List countries; +} 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 new file mode 100644 index 000000000..d47cf2dd8 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ChangeWarehouseJob.java @@ -0,0 +1,192 @@ +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.modules.business.domain.api.mabang.dochangeorder.*; +import org.jeecg.modules.business.domain.api.mabang.getorderlist.*; +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.service.IPlatformOrderService; +import org.jeecg.modules.business.vo.Responses; +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.text.Normalizer; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +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; + +import static java.util.stream.Collectors.toList; + +@Slf4j +public class ChangeWarehouseJob implements Job { + @Autowired + private IPlatformOrderService platformOrderService; + + private static final Integer DEFAULT_NUMBER_OF_DAYS = 5; + private static final Integer DEFAULT_NUMBER_OF_THREADS = 10; + private final String DEFAULT_WAREHOUSE_NAME = "法国巴黎仓库-唯客路"; + private final String DEFAULT_ABNORMAL_LABEL_NAME = "AC海外仓非法国比利时不发货"; + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + log.info("Executing ChangeWarehouseJob..."); + LocalDateTime endDateTime = LocalDateTime.now(); + LocalDateTime startDateTime = endDateTime.minusDays(DEFAULT_NUMBER_OF_DAYS); + List allSkus = new ArrayList<>(); + List changeWareHouseParams = new ArrayList<>(); + + JobDataMap jobDataMap = context.getMergedJobDataMap(); + String parameter = ((String) jobDataMap.get("parameter")); + if (parameter != null) { + try { + JSONObject jsonObject = new JSONObject(parameter); + if (!jsonObject.isNull("startDateTime")) { + String startDateStr = jsonObject.getString("startDateTime"); + startDateTime = LocalDateTime.parse(startDateStr); + } + if (!jsonObject.isNull("endDateTime")) { + String endDateStr = jsonObject.getString("endDateTime"); + endDateTime = LocalDateTime.parse(endDateStr); + } + if (!jsonObject.isNull("data")) { + JSONArray dataJsonArray = jsonObject.getJSONArray("data"); + for (int i = 0; i < dataJsonArray.length(); i++) { + JSONObject object = dataJsonArray.getJSONObject(i); + ChangeWareHouseParam param = new ChangeWareHouseParam(); + if(!object.isNull("shop")) { + param.setShop(object.getString("shop")); + } + if(!object.isNull("skus")) { + JSONArray skusJsonArray = object.getJSONArray("skus"); + List skus = new ArrayList<>(); + for(int j = 0; j < skusJsonArray.length(); j++) { + skus.add(skusJsonArray.getString(j)); + } + param.setSkus(skus); + allSkus.addAll(skus); + } + if(!object.isNull("countries")) { + List countries = new ArrayList<>(); + JSONArray countriesJsonArray = object.getJSONArray("countries"); + for (int j = 0; j < countriesJsonArray.length(); j++) { + countries.add(countriesJsonArray.getString(j)); + } + param.setCountries(countries); + } + changeWareHouseParams.add(param); + } + } + } catch (JSONException e) { + log.error("Error while parsing parameter as JSON, falling back to default parameters."); + } + } + + if (!endDateTime.isAfter(startDateTime)) { + throw new RuntimeException("EndDateTime must be strictly greater than StartDateTime !"); + } + ExecutorService executor = Executors.newFixedThreadPool(DEFAULT_NUMBER_OF_THREADS); + + List platformOrderIds = new ArrayList<>(); + List ordersToSetAbnormal = new ArrayList<>(); + for(ChangeWareHouseParam param: changeWareHouseParams) { + List poIds = platformOrderService.fetchUninvoicedOrdersWithSkusInCountry(startDateTime, endDateTime, param.getShop(), param.getSkus(), param.getCountries()); + List abnormalPoIds = platformOrderService.fetchUninvoicedOrdersWithSkusNotInCountry(startDateTime, endDateTime, param.getShop(), allSkus, param.getCountries()); + platformOrderIds.addAll(poIds); + ordersToSetAbnormal.addAll(abnormalPoIds); + } + + // fetch orders from mabang + log.info("Fetching orders from mabang..."); + List> platformOrderIdLists = Lists.partition(platformOrderIds, 10); + List mabangOrders = new ArrayList<>(); + List requests = new ArrayList<>(); + for (List platformOrderIdList : platformOrderIdLists) { + requests.add(new OrderListRequestBody().setPlatformOrderIds(platformOrderIdList)); + } + List> completableFutures = 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 while fetching orders from mabang: {}", e.getMessage()); + } + return success; + }, executor)) + .collect(Collectors.toList()); + List fetchResults = completableFutures.stream().map(CompletableFuture::join).collect(Collectors.toList()); + long fetchSuccessCount = fetchResults.stream().filter(Boolean::booleanValue).count(); + log.info("Successfully fetched {} out of {} orders from mabang.", fetchSuccessCount, fetchResults.size()); + + log.info("Updating recipients info..."); + replaceOrdersAccents(mabangOrders); + + log.info("Updating warehouse name..."); + List> futures = mabangOrders.stream() + .map(order -> CompletableFuture.supplyAsync(() -> { + ChangeWarehouseRequestBody body = new ChangeWarehouseRequestBody(order, DEFAULT_WAREHOUSE_NAME); + ChangeWarehouseRequest request = new ChangeWarehouseRequest(body); + ChangeOrderResponse response = request.send(); + return response.success(); + }, executor)) + .collect(Collectors.toList()); + List results = futures.stream().map(CompletableFuture::join).collect(Collectors.toList()); + long successCount = results.stream().filter(Boolean::booleanValue).count(); + log.info("Successfully changed warehouse for {} out of {} orders.", successCount, results.size()); + + log.info("Setting orders to abnormal..."); + 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); + OrderSuspendRequest request = new OrderSuspendRequest(body); + OrderSuspendResponse response = request.send(); + Responses r = new Responses(); + if(response.success()) + r.addSuccess(id); + else + r.addFailure(id); + return r; + }, executor)) + .collect(toList()); + List abnormalResults = abnormalFutures.stream() + .map(CompletableFuture::join) + .collect(toList()); + abnormalResults.forEach(r -> { + responses.getSuccesses().addAll(r.getSuccesses()); + responses.getFailures().addAll(r.getFailures()); + }); + log.info("Successfully set {}/{} orders to abnormal.", responses.getSuccesses().size(), ordersToSetAbnormal.size()); + executor.shutdown(); + } + public void replaceOrdersAccents(List orders) { + for(Order order: orders) { + order.setRecipient(stripAccents(order.getRecipient())); + order.setAddress(stripAccents(order.getAddress())); + order.setAddress2(stripAccents(order.getAddress2())); + } + } + public String stripAccents(String input) { + input = Normalizer.normalize(input, Normalizer.Form.NFD); + input = input.replaceAll("[^\\p{ASCII}]", ""); + return input; + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/SetOrderToNormalJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/SetOrderToNormalJob.java new file mode 100644 index 000000000..f39e1ba3f --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/SetOrderToNormalJob.java @@ -0,0 +1,183 @@ +package org.jeecg.modules.business.domain.job; + +import com.google.common.collect.Lists; +import freemarker.template.Template; +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.getorderlist.*; +import org.jeecg.modules.business.domain.api.mabang.orderDoOrderNormal.OrderToNormalRequest; +import org.jeecg.modules.business.domain.api.mabang.orderDoOrderNormal.OrderToNormalRequestBody; +import org.jeecg.modules.business.domain.api.mabang.orderDoOrderNormal.OrderToNormalResponse; +import org.jeecg.modules.business.entity.PlatformOrder; +import org.jeecg.modules.business.entity.PlatformOrderContent; +import org.jeecg.modules.business.service.EmailService; +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 org.springframework.core.env.Environment; +import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import javax.mail.Authenticator; +import javax.mail.PasswordAuthentication; +import javax.mail.Session; +import java.time.LocalDate; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; + +@Slf4j +public class SetOrderToNormalJob implements Job { + + @Autowired + private EmailService emailService; + @Autowired + private IPlatformOrderService platformOrderService; + + @Autowired + Environment env; + @Autowired + private FreeMarkerConfigurer freemarkerConfigurer; + + private static final Integer DEFAULT_NUMBER_OF_THREADS = 10; + private final String WAREHOUSE_NAME = "法国巴黎仓库-唯客路"; + private final String ABNORMAL_LABEL_NAME = "自动创建SKU的订单"; + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + log.info("Executing SetOrderToNormalJob..."); + JobDataMap jobDataMap = context.getMergedJobDataMap(); + String parameter = ((String) jobDataMap.get("parameter")); + + List skus = new ArrayList<>(); + List shops = new ArrayList<>(); + if (parameter != null) { + try { + JSONObject jsonObject = new JSONObject(parameter); + if(!jsonObject.isNull("skus")) { + JSONArray skusJsonArray = jsonObject.getJSONArray("skus"); + for (int i = 0; i < skusJsonArray.length(); i++) { + skus.add(skusJsonArray.getString(i)); + } + } + if(!jsonObject.isNull("shops")) { + JSONArray shopsJsonArray = jsonObject.getJSONArray("shops"); + for (int i = 0; i < shopsJsonArray.length(); i++) { + shops.add(shopsJsonArray.getString(i)); + } + } + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + List orderIds = platformOrderService.findReadyAbnormalOrders(skus, shops); + List orderIdsWithSkus = platformOrderService.findReadyAbnormalOrdersWithSkus(skus); + List orderReadyWithSkus = orderIds.stream() + .filter(orderIdsWithSkus::contains) + .collect(Collectors.toList()); + if(!orderReadyWithSkus.isEmpty()) { + Map> orderContents = platformOrderService.fetchOrderData(orderReadyWithSkus); + // Remove orders that contains sku from "skus" list and have wrong warehouse + for(Map.Entry> entry : orderContents.entrySet()) { + for(PlatformOrderContent content : entry.getValue()) { + if(!content.getWarehouseName().equals(WAREHOUSE_NAME)) { + orderIds.remove(content.getPlatformOrderId()); + break; + } + } + } + } + + ExecutorService executor = Executors.newFixedThreadPool(DEFAULT_NUMBER_OF_THREADS); + + List platform_order_ids = platformOrderService.listByIds(orderIds).stream() + .map(PlatformOrder::getPlatformOrderId) + .collect(Collectors.toList()); + List mabangOrders = new ArrayList<>(); + + List> partitionedPlatformOrderIds = Lists.partition(platform_order_ids, 10); + List requests = new ArrayList<>(); + for (List platformOrderIdList : partitionedPlatformOrderIds) { + requests.add(new OrderListRequestBody().setPlatformOrderIds(platformOrderIdList)); + } + // Fetch orders from mabang + List> mabangFutures = requests.stream() + .map(request -> CompletableFuture.supplyAsync(() -> { + boolean success = false; + OrderListRawStream rawStream = new OrderListRawStream(request); + OrderListStream stream = new OrderListStream(rawStream); + List orders = stream.all(); + mabangOrders.addAll(orders); + success = !orders.isEmpty(); + return success; + }, executor)) + .collect(Collectors.toList()); + List fetchResults = mabangFutures.stream().map(CompletableFuture::join).collect(Collectors.toList()); + long fetchSuccessCount = fetchResults.stream().filter(Boolean::booleanValue).count(); + log.info("Successfully fetched {} out of {} orders groups from mabang.", fetchSuccessCount, fetchResults.size()); + + List poIdsToSetNormal = new ArrayList<>(); + if(!mabangOrders.isEmpty()) { + for(Order order : mabangOrders) { + OrderTypeLabel[] labels = order.getOrderType().getAbnormalLabels(); + if(labels.length > 1) { + continue; + } + if(labels[0].getName().equals(ABNORMAL_LABEL_NAME)) { + poIdsToSetNormal.add(order.getPlatformOrderId()); + } + } + } + + List> futures = poIdsToSetNormal.stream() + .map(orderId -> CompletableFuture.supplyAsync(() -> { + log.info("Setting order {} to normal", orderId); + OrderToNormalRequestBody requestBody = new OrderToNormalRequestBody(orderId); + OrderToNormalRequest request = new OrderToNormalRequest(requestBody); + OrderToNormalResponse response = request.send(); + return response.success(); + }, executor)) + .collect(Collectors.toList()); + List results = futures.stream() + .map(CompletableFuture::join) + .collect(Collectors.toList()); + long successCount = results.stream().filter(Boolean::booleanValue).count(); + log.info("Successfully set {}/{} orders to normal", successCount, poIdsToSetNormal.size()); + + executor.shutdown(); + + // send list of order ids by mail + if(!poIdsToSetNormal.isEmpty()) { + String subject = "[" + LocalDate.now() + "] Set Orders To Normal Job Report"; + String destEmail = env.getProperty("spring.mail.username"); + Properties prop = emailService.getMailSender(); + Map templateModel = new HashMap<>(); + templateModel.put("orderIds", poIdsToSetNormal); + templateModel.put("count", poIdsToSetNormal.size()); + Session session = Session.getInstance(prop, new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(env.getProperty("spring.mail.username"), env.getProperty("spring.mail.password")); + } + }); + try { + freemarkerConfigurer = emailService.freemarkerClassLoaderConfig(); + Template freemarkerTemplate = freemarkerConfigurer.getConfiguration() + .getTemplate("admin/ordersSetToNormalJobReport.ftl"); + String htmlBody = FreeMarkerTemplateUtils.processTemplateIntoString(freemarkerTemplate, templateModel); + emailService.sendSimpleMessage(destEmail, subject, htmlBody, session); + log.info("Mail sent successfully !"); + } catch (Exception e) { + log.error("Error while sending Set Orders To Normal Job report mail !"); + e.printStackTrace(); + } + } + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/PlatformOrderContent.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/PlatformOrderContent.java index ece603025..26f4920a5 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/PlatformOrderContent.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/PlatformOrderContent.java @@ -139,6 +139,12 @@ public class PlatformOrderContent implements Serializable { @Excel(name = "商品多属性", width = 15) @ApiModelProperty(value = "商品多属性") private java.lang.String customizationData; + /** + * 仓库 + */ + @Excel(name = "Warehouse name", width = 15) + @ApiModelProperty(value = "添加的商品仓库") + private String warehouseName; @Override public boolean equals(Object o) { 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 2a8d6ba16..805e5f328 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 @@ -224,4 +224,11 @@ public interface PlatformOrderMapper extends BaseMapper { void anonymizePersonalData(@Param("period") int indirectClientAnonymizationPeriod); List ordersByShop(@Param("shopID") String shopID); + + List fetchUninvoicedOrdersWithSkusInCountry(@Param("startDate") LocalDateTime startDateTime, @Param("endDate") LocalDateTime endDateTime, @Param("shop") String shop, @Param("skus") List skus, @Param("countries") List countries); + List fetchUninvoicedOrdersWithSkusNotInCountry(@Param("startDate") LocalDateTime startDateTime, @Param("endDate") LocalDateTime endDateTime, @Param("shop") String shop, @Param("skus") List skus, @Param("countries") List countries); + + List findReadyAbnormalOrders(@Param("skus") List skus, @Param("shops") List shops); + + List findReadyAbnormalOrdersWithSkus(@Param("skus") List skus); } 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 f0967b264..d40a0abda 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 @@ -195,14 +195,14 @@ INSERT INTO platform_order_content( id, create_by, create_time, update_by, update_time, platform_order_id, - sku_id, quantity, erp_status, product_available, customization_data) + sku_id, quantity, erp_status, product_available, customization_data, warehouse_name) VALUES ( UUID(), 'Mabang API', NOW(), 'Mabang API', NOW(), #{item.platformOrderId}, skuErpToId(#{item.erpCode}), #{item.quantity}, #{item.erpStatus}, - #{item.productAvailable}, #{item.specifics}) + #{item.productAvailable}, #{item.specifics}, #{item.warehouseName}) 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 4bc711014..6b2b1917a 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 @@ -898,4 +898,170 @@ WHERE shop_id = #{shopID} AND erp_status IN (1,2,3) + + + + 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 c27ae4dbc..1205ffb28 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 @@ -248,4 +248,11 @@ public interface IPlatformOrderService extends IService { void anonymizePersonalData(int indirectClientAnonymizationPeriod); List ordersByShop(String shopID); + + List fetchUninvoicedOrdersWithSkusInCountry(LocalDateTime startDateTime, LocalDateTime endDateTime, String shop, List skus, List countries); + List fetchUninvoicedOrdersWithSkusNotInCountry(LocalDateTime startDateTime, LocalDateTime endDateTime, String shop, List skus, List countries); + + List findReadyAbnormalOrders(List skus, List shops); + + List findReadyAbnormalOrdersWithSkus(List skus); } 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 0e6b5bee0..f7838f03b 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 @@ -501,4 +501,23 @@ public class PlatformOrderServiceImpl extends ServiceImpl ordersByShop(String shopID) { return platformOrderMap.ordersByShop(shopID); } + + @Override + public List fetchUninvoicedOrdersWithSkusInCountry(LocalDateTime startDateTime, LocalDateTime endDateTime, String shop, List skus, List countries) { + return platformOrderMap.fetchUninvoicedOrdersWithSkusInCountry(startDateTime, endDateTime, shop, skus, countries); + } + @Override + public List fetchUninvoicedOrdersWithSkusNotInCountry(LocalDateTime startDateTime, LocalDateTime endDateTime, String shop, List skus, List countries) { + return platformOrderMap.fetchUninvoicedOrdersWithSkusNotInCountry(startDateTime, endDateTime, shop, skus, countries); + } + + @Override + public List findReadyAbnormalOrders(List skus, List shops) { + return platformOrderMap.findReadyAbnormalOrders(skus, shops); + } + + @Override + public List findReadyAbnormalOrdersWithSkus(List skus) { + return platformOrderMap.findReadyAbnormalOrdersWithSkus(skus); + } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/admin/ordersSetToNormalJobReport.ftl b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/admin/ordersSetToNormalJobReport.ftl new file mode 100644 index 000000000..f7d392cfc --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/admin/ordersSetToNormalJobReport.ftl @@ -0,0 +1,17 @@ +<#include "../components/header.ftl"> + + Cher Collègue + + + Voici la liste des commandes dont le status a été mis à jour à "Normal" : + + + Nombre de commandes : ${count}
+

    + <#list orderIds as orderId> +
  • ${orderId}
  • + +
+ + +<#include "../components/footer.ftl"> \ No newline at end of file