From 536b0230a049a5fb2dad0e4c62d2646536ee2d61 Mon Sep 17 00:00:00 2001 From: Gauthier LO Date: Thu, 4 Jul 2024 11:06:30 +0200 Subject: [PATCH 1/5] feat: sku update job --- .../mabang/doSearchSkuListNew/SkuData.java | 3 + .../SkuListRequestBody.java | 2 +- .../SkuUpdateListStream.java | 122 +++++++++++++++++ .../business/domain/job/MabangSkuSyncJob.java | 113 ++++++++++++++++ .../jeecg/modules/business/entity/Sku.java | 8 ++ .../modules/business/mapper/xml/SkuMapper.xml | 2 + .../service/ISkuListMabangService.java | 1 + .../impl/SkuListMabangServiceImpl.java | 123 +++++++++++++++++- 8 files changed, 369 insertions(+), 5 deletions(-) create mode 100644 jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuListNew/SkuUpdateListStream.java create mode 100644 jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/MabangSkuSyncJob.java diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuListNew/SkuData.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuListNew/SkuData.java index 2d5e4e7e3..b0285813c 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuListNew/SkuData.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuListNew/SkuData.java @@ -90,6 +90,9 @@ public class SkuData { public SkuStatus getStatus() { return SkuStatus.fromCode(this.status); } + public int getStatusValue() { + return this.status; + } public String toString() { return "ID : " + this.id + "\nStockSkuId : " + this.stockSkuId + diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuListNew/SkuListRequestBody.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuListNew/SkuListRequestBody.java index 52c486243..8433d44c1 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuListNew/SkuListRequestBody.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuListNew/SkuListRequestBody.java @@ -18,7 +18,7 @@ public class SkuListRequestBody implements RequestBody { private String stockSku = null; // 50 skus max private String stockSkuList = null; - private DateType datetimeType; + private DateType datetimeType = DateType.CREATE; private LocalDateTime startDate; private LocalDateTime endDate; private Integer page = 1; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuListNew/SkuUpdateListStream.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuListNew/SkuUpdateListStream.java new file mode 100644 index 000000000..1ded31b2c --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/api/mabang/doSearchSkuListNew/SkuUpdateListStream.java @@ -0,0 +1,122 @@ +package org.jeecg.modules.business.domain.api.mabang.doSearchSkuListNew; + +import lombok.extern.slf4j.Slf4j; +import org.jeecg.modules.business.domain.api.mabang.getorderlist.NetworkDataStream; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.NoSuchElementException; + +/** + * This class provide stream of order. + */ +@Slf4j +public class SkuUpdateListStream implements NetworkDataStream { + + private final NetworkDataStream rawStream; + + private List skus; + + private int index; + + private boolean began; + + /** + * Flag of current data is already empty, + * either currentOrders is null or currentIndex arrives at the end. + * In both case, we should call next() of the rawStream. + */ + private boolean empty; + + + public SkuUpdateListStream(NetworkDataStream rawStream) { + this.rawStream = rawStream; + skus = null; + this.index = 0; + this.empty = true; + this.began = false; + } + @Override + public List all() { + SkuData firstElement = attempt(); + if (firstElement == null) { + return Collections.emptyList(); + } + + ArrayList res = new ArrayList<>(); + if (firstElement.getStatus().equals(SkuStatus.Normal) || firstElement.getStatus().equals(SkuStatus.StoppedSelling)) { + res.add(firstElement); + } + while (hasNext()) { + SkuData nextSku = next(); + if(nextSku.getStatus().equals(SkuStatus.Normal) || firstElement.getStatus().equals(SkuStatus.StoppedSelling)) { + res.add(nextSku); + } + } + return res; + } + @Override + public SkuData attempt() { + began = true; + log.info("Attempting for the first request"); + SkuListResponse response = rawStream.attempt(); + if (response == null) { + log.info("No response"); + return null; + } + if (response.getData().isEmpty()) { + log.info("Response with empty data"); + return null; + } + skus = response.getData().toJavaList(SkuData.class); + index = 1; + log.info("Returned the first element"); + empty = index >= skus.size(); + return skus.get(0); + } + + @Override + public boolean hasNext() { + // the first time + if (!began) { + throw new IllegalStateException("Calling hasNext before begin"); + } + + // Current data is not yet empty + if (index < skus.size()) { + log.debug("Current order list is not empty yet"); + return true; + } + + /* Current data is empty */ + this.empty = true; + log.debug("Current order list is already empty,"); + // and raw stream is empty too. + if (!rawStream.hasNext()) { + log.debug("and source stream is empty too, hasNext: false"); + return false; + } + // but raw stream not empty. + else { + log.debug("but source stream still has data, hasNext: true"); + return true; + } + } + + @Override + public SkuData next() { + if (!hasNext()) { + throw new NoSuchElementException("Stream is empty!"); + } + if (empty) { + skus = this.rawStream.next().getData().toJavaList(SkuData.class); + empty = false; + index = 0; + } + log.debug("Return data at {}", index); + SkuData res = skus.get(index); + index++; + return res; + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/MabangSkuSyncJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/MabangSkuSyncJob.java new file mode 100644 index 000000000..4b585f93b --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/MabangSkuSyncJob.java @@ -0,0 +1,113 @@ +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.doSearchSkuListNew.*; +import org.jeecg.modules.business.service.ISkuListMabangService; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; + +/** + * A Job that retrieves all Sku from Mabang + * if the sku is of status 3 (normal) and not in DB, then we insert it in DB + */ +@Slf4j +@Component +public class MabangSkuSyncJob implements Job { + + @Autowired + private ISkuListMabangService skuListMabangService; + private static final Integer DEFAULT_NUMBER_OF_DAYS = 5; + private static final DateType DEFAULT_DATE_TYPE = DateType.UPDATE; + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + LocalDateTime endDateTime = LocalDateTime.now(ZoneId.of(ZoneId.SHORT_IDS.get("CTT"))); + LocalDateTime startDateTime = endDateTime.minusDays(DEFAULT_NUMBER_OF_DAYS); + List skus = new ArrayList<>(); + DateType dateType = DEFAULT_DATE_TYPE; + 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("dateType")) { + dateType = DateType.fromCode(jsonObject.getInt("dateType")); + } + if (!jsonObject.isNull("skus")) { + JSONArray array = jsonObject.getJSONArray("skus"); + for(int i = 0; i < array.length(); i++) { + skus.add(array.getString(i)); + } + } + } 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 !"); + } + + try { + if(skus.isEmpty()) { + log.info("Updating skus by date"); + while (startDateTime.until(endDateTime, ChronoUnit.HOURS) > 0) { + LocalDateTime dayBeforeEndDateTime = endDateTime.minusDays(1); + SkuListRequestBody body = SkuListRequestBodys.allSkuOfDateType(dayBeforeEndDateTime, endDateTime, dateType); + SkuListRawStream rawStream = new SkuListRawStream(body); + SkuUpdateListStream stream = new SkuUpdateListStream(rawStream); + // the status is directly filtered in all() method + List skusFromMabang = stream.all(); + log.info("{} skus from {} to {} ({})to be updated.", skusFromMabang.size(), + dayBeforeEndDateTime, endDateTime, dateType); + + if (!skusFromMabang.isEmpty()) { + // we save the skuDatas in DB + skuListMabangService.updateSkusFromMabang(skusFromMabang); + } + endDateTime = dayBeforeEndDateTime; + } + } + else { + log.info("Updating skus by erpCode : {}", skus); + List> skusPartition = Lists.partition(skus, 50); + for(List skuPartition : skusPartition) { + SkuListRequestBody body = new SkuListRequestBody(); + body.setStockSkuList(String.join(",", skuPartition)); + SkuListRawStream rawStream = new SkuListRawStream(body); + SkuUpdateListStream stream = new SkuUpdateListStream(rawStream); + List skusFromMabang = stream.all(); + log.info("{} skus to be updated.", skusFromMabang.size()); + if (!skusFromMabang.isEmpty()) { + // we save the skuDatas in DB + skuListMabangService.updateSkusFromMabang(skusFromMabang); + } + } + } + } catch (SkuListRequestErrorException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/Sku.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/Sku.java index f4f4b1ebc..a1380c912 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/Sku.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/entity/Sku.java @@ -98,4 +98,12 @@ public class Sku implements Serializable { @Excel(name = "服务费", width = 15) @ApiModelProperty(value = "服务费") private java.math.BigDecimal serviceFee; + /** + * Status + * 1:自动创建;2:待开发;3:正常;4:清仓;5:停止销售" + * default : 3 + */ + @Excel(name = "Status", width = 15) + @ApiModelProperty(value = "Status") + private java.lang.Integer status; } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/SkuMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/SkuMapper.xml index bcc68487f..f01af9170 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/SkuMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/SkuMapper.xml @@ -209,6 +209,7 @@ LEFT JOIN sales_7 s7 ON s.id = s7.sku_id LEFT JOIN qtyInOrdersNotShipped ON s.id = qtyInOrdersNotShipped.ID WHERE client_sku.client_id = #{clientId} + AND s.status = 3 ORDER BY ${column} ${order} LIMIT #{offset}, #{size} @@ -272,6 +273,7 @@ LEFT JOIN sales_7 s7 ON s.id = s7.sku_id LEFT JOIN qtyInOrdersNotShippedCTE ON s.id = qtyInOrdersNotShippedCTE.ID WHERE client_sku.client_id = #{clientId} + AND s.status = 3 AND ( s.erp_code REGEXP #{erpCodes} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/ISkuListMabangService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/ISkuListMabangService.java index f280732ca..9ecb551f3 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/ISkuListMabangService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/ISkuListMabangService.java @@ -15,6 +15,7 @@ public interface ISkuListMabangService extends IService { * @param skuDataList skus to save. */ Map saveSkuFromMabang(List skuDataList); + void updateSkusFromMabang(List skuDataList); /** * Save products to DB from mabang api. diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/SkuListMabangServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/SkuListMabangServiceImpl.java index 0e958dda3..e41834dca 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/SkuListMabangServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/impl/SkuListMabangServiceImpl.java @@ -54,7 +54,10 @@ public class SkuListMabangServiceImpl extends ServiceImpl skuDataList) { + if (skuDataList.isEmpty()) { + return; + } + // we collect all erpCode + List allSkuErpCode = skuDataList.stream() + .map(SkuData::getErpCode) + .collect(toList()); + // find Skus that already exist in DB + List existingSkuList = skuListMabangMapper.searchExistence(allSkuErpCode); + // We map all existing Skus in DB with erpCode as key + Map existingSkusIDMap = existingSkuList.stream() + .collect( + Collectors.toMap( + Sku::getErpCode, Function.identity() + ) + ); + + ArrayList existingSkuDatas = new ArrayList<>(); + for (SkuData retrievedSkuData : skuDataList) { + Sku skuInDatabase = existingSkusIDMap.get(retrievedSkuData.getErpCode()); + // the current SkuData's erpCode is in DB, so we add it to the list of existingSkuDatas + if (skuInDatabase != null) { + existingSkuDatas.add(retrievedSkuData); + } + } + + /* for skuDatas to update, update product names and sku status them to DB */ + try { + if (!existingSkuDatas.isEmpty()) { + // we need to check if the product associated with the sku exists, for that we are going to parse the Sku erpCode into product code + // check if the product code exists in DB, if not we create a new entry in DB and fill all the infos. + // then we can finally add the new Sku, product has to be created first if it doesn't exist, since we need to fill productID in Sku table + // we can now proceed to create new sku_declare_value associated with the new Sku and also sku_price + updateProductFromMabang(existingSkuDatas); + log.info("{} skus to be updated.", existingSkuDatas.size()); + + //update status of existing skus + List skusToUpdate = new ArrayList<>(); + for(SkuData skuData: existingSkuDatas) { + Sku s = new Sku(); + s.setId(existingSkusIDMap.get(skuData.getErpCode()).getId()); + s.setUpdateBy("mabang api"); + s.setUpdateTime(new Date()); + s.setStatus(skuData.getStatusValue()); + skusToUpdate.add(s); + } + skuService.updateBatchById(skusToUpdate); + log.info("Updated {} skus : {}.", skusToUpdate.size(), existingSkuDatas.stream().map(SkuData::getErpCode).collect(toList())); + } + } catch (RuntimeException e) { + log.error(e.getLocalizedMessage()); + } + } + /** * Save products to DB from mabang api. * @@ -197,6 +257,63 @@ public class SkuListMabangServiceImpl extends ServiceImpl skuDataList) { + List allProductCodes = parseSkuListToProductCodeList(skuDataList); + + List< Product> existingProduct = skuListMabangMapper.searchProductExistence(allProductCodes); + Map existingProductsIDMap = existingProduct.stream() + .collect( + Collectors.toMap( + Product::getCode, Function.identity() + ) + ); + List skuDatasToUpdate = new ArrayList<>(); + // we ignore the new products and only update the existing ones + for(SkuData skuData : skuDataList) { + Product productInDB = existingProductsIDMap.get(parseSkuToProduct(skuData.getErpCode())); + // the current product code is in DB, so we add it to the list of newProducts + if (productInDB != null) { + skuDatasToUpdate.add(skuData); + } + } + List productsToUpdate = new ArrayList<>(); + for(SkuData skuData: skuDatasToUpdate) { + Product p = new Product(); + p.setId(existingProductsIDMap.get(parseSkuToProduct(skuData.getErpCode())).getId()); + p.setUpdateBy("mabang api"); + p.setUpdateTime(new Date()); + // Removing the customer code from the product CN name + if (!skuData.getNameEN().isEmpty()) { + Matcher enNameMatcher = enNamePattern.matcher(skuData.getNameEN()); + if (enNameMatcher.matches() && !enNameMatcher.group(2).isEmpty()) { + p.setEnName(enNameMatcher.group(2)); + } + else { + p.setEnName(skuData.getNameEN()); + } + } + // Removing the customer code from the product CN name + if (!skuData.getNameCN().isEmpty()) { + Matcher cnNameMatcher = cnNamePattern.matcher(skuData.getNameCN()); + if (cnNameMatcher.matches() && !cnNameMatcher.group(2).isEmpty()) { + p.setZhName(cnNameMatcher.group(2)); + } + else { + p.setZhName(skuData.getNameCN()); + } + } + productsToUpdate.add(p); + } + if(!productsToUpdate.isEmpty()) { + productService.updateBatchById(productsToUpdate); + } + log.info("Updated {} products : {}.", productsToUpdate.size(), skuDatasToUpdate.stream().map(SkuData::getErpCode).collect(toList())); + } public void saveSkuPrices(List newSkus) { List l = new ArrayList<>(); @@ -290,8 +407,6 @@ public class SkuListMabangServiceImpl extends ServiceImpl Date: Thu, 4 Jul 2024 15:21:14 +0200 Subject: [PATCH 2/5] feat: order management now triggers mabang order sync on success --- .../admin/PlatformOrderController.java | 16 +++- .../domain/job/MabangOrderSyncJob.java | 76 ++++++------------- .../service/IPlatformOrderMabangService.java | 4 + .../impl/PlatformOrderMabangServiceImpl.java | 49 ++++++++++++ .../client/orderManagementNotification.ftl | 24 +++++- 5 files changed, 113 insertions(+), 56 deletions(-) diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/PlatformOrderController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/PlatformOrderController.java index aa5fcce11..5178a667f 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/PlatformOrderController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/controller/admin/PlatformOrderController.java @@ -20,6 +20,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.google.common.collect.Lists; import freemarker.template.Template; import freemarker.template.TemplateException; +import org.codehaus.jettison.json.JSONException; import org.jeecg.modules.business.domain.api.mabang.dochangeorder.ChangeOrderResponse; import org.jeecg.modules.business.domain.api.mabang.dochangeorder.ChangeWarehouseRequest; import org.jeecg.modules.business.domain.api.mabang.dochangeorder.ChangeWarehouseRequestBody; @@ -385,7 +386,7 @@ public class PlatformOrderController { } @PostMapping("/orderManagement") - public Result orderManagement(@RequestBody List orderOperations) throws IOException { + public Result orderManagement(@RequestBody List orderOperations) throws IOException, JSONException { boolean isEmployee = securityService.checkIsEmployee(); LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); Client client; @@ -469,6 +470,9 @@ public class PlatformOrderController { } List mabangOrders = platformOrderMabangService.getOrdersFromMabang(requests, executor); for(Order mabangOrder : mabangOrders) { + if(mabangOrder.getTrackingNumber() == null) { + continue; + } if(!mabangOrder.getTrackingNumber().isEmpty()) { ordersWithTrackingNumber.add(mabangOrder); } @@ -511,14 +515,17 @@ public class PlatformOrderController { templateModel.put("lastname", client.getSurname()); if(cancelCount > 0) { templateModel.put("cancelSuccessCount", cancelResponses.getSuccesses().size() + "/" + cancelCount); + templateModel.put("cancelSuccesses", cancelResponses.getSuccesses()); templateModel.put("cancelFailures", cancelResponses.getFailures()); } if(suspendCount > 0) { templateModel.put("suspendSuccessCount", suspendResponses.getSuccesses().size() + "/" + suspendCount); + templateModel.put("suspendSuccesses", suspendResponses.getSuccesses()); templateModel.put("suspendFailures", suspendResponses.getFailures()); } if(editCount > 0) { templateModel.put("editSuccessCount", editResponses.getSuccesses().size() + "/" + editCount); + templateModel.put("editSuccesses", editResponses.getSuccesses()); templateModel.put("editFailures", editResponses.getFailures()); } @@ -539,6 +546,13 @@ public class PlatformOrderController { throw new RuntimeException(e); } + // sync orders from Mabang + List poIdsSuccesses = new ArrayList<>(); + poIdsSuccesses.addAll(cancelResponses.getSuccesses()); + poIdsSuccesses.addAll(suspendResponses.getSuccesses()); + poIdsSuccesses.addAll(editResponses.getSuccesses()); + platformOrderMabangService.syncOrdersFromMabang(poIdsSuccesses); + return Result.OK(result); } @GetMapping("/recipientInfo") 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 62f1e9fc2..87720542f 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 @@ -1,13 +1,11 @@ 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.getorderlist.*; import org.jeecg.modules.business.service.IPlatformOrderMabangService; import org.jetbrains.annotations.NotNull; import org.quartz.Job; @@ -17,10 +15,6 @@ import org.quartz.JobExecutionException; import org.springframework.beans.factory.annotation.Autowired; 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 MabangOrderSyncJob implements Job { @@ -29,7 +23,6 @@ public class MabangOrderSyncJob implements Job { private IPlatformOrderMabangService platformOrderMabangService; @Autowired private ISysBaseAPI ISysBaseApi; - private static final Integer DEFAULT_NUMBER_OF_THREADS = 10; @Override public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap jobDataMap = context.getMergedJobDataMap(); @@ -54,53 +47,32 @@ public class MabangOrderSyncJob implements Job { throw new RuntimeException("PlatformOrder ID list can't be empty !"); } - log.info("Syncing following orders {}", platformOrderIds); - List> platformOrderIdLists = Lists.partition(platformOrderIds, 10); - List requests = new ArrayList<>(); - for (List platformOrderIdList : platformOrderIdLists) { - requests.add(new OrderListRequestBody().setPlatformOrderIds(platformOrderIdList)); - } - 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(); - List syncedOrderIds = mabangOrders.stream().map(Order::getPlatformOrderId).collect(Collectors.toList()); - log.info("{}/{} mabang orders have been retrieved.", syncedOrderNumber, platformOrderIds.size()); - - log.info("{} orders to be updated.", syncedOrderNumber); - platformOrderMabangService.saveOrderFromMabang(mabangOrders); - - Map param = new HashMap<>(); - param.put("requested_order_number", String.valueOf(platformOrderIds.size())); - param.put("synced_order_number", String.valueOf(syncedOrderNumber)); - param.put("requested_order_ids", getHtmlListFromStringList(platformOrderIds)); - List failedToSyncOrderIds = new ArrayList<>(); - for (String platformOrderId : platformOrderIds) { - if (!syncedOrderIds.contains(platformOrderId)) { - failedToSyncOrderIds.add(platformOrderId); + try { + JSONObject res = platformOrderMabangService.syncOrdersFromMabang(platformOrderIds); + String syncedOrderNumber = String.valueOf(res.getInt("synced_order_number")); + List syncedOrderIds = new ArrayList<>(); + JSONArray syncedOrderIdsArray = res.getJSONArray("synced_order_ids"); + for (int i = 0; i < syncedOrderIdsArray.length(); i++) { + syncedOrderIds.add(syncedOrderIdsArray.getString(i)); } + Map param = new HashMap<>(); + param.put("requested_order_number", String.valueOf(platformOrderIds.size())); + param.put("synced_order_number", syncedOrderNumber); + param.put("requested_order_ids", getHtmlListFromStringList(platformOrderIds)); + List failedToSyncOrderIds = new ArrayList<>(); + for (String platformOrderId : platformOrderIds) { + if (!syncedOrderIds.contains(platformOrderId)) { + failedToSyncOrderIds.add(platformOrderId); + } + } + param.put("failed_to_sync_order_ids", getHtmlListFromStringList(failedToSyncOrderIds)); + TemplateMessageDTO message = new TemplateMessageDTO("admin", username == null ? "admin" : username, "马帮订单同步任务", param, "mabang_order_sync_job_result"); + ISysBaseApi.sendTemplateAnnouncement(message); + log.info("Order sync job recap message sent"); + } catch (JSONException e) { + throw new RuntimeException(e); } - param.put("failed_to_sync_order_ids", getHtmlListFromStringList(failedToSyncOrderIds)); - TemplateMessageDTO message = new TemplateMessageDTO("admin", username == null ? "admin" : username, "马帮订单同步任务", param, "mabang_order_sync_job_result"); - ISysBaseApi.sendTemplateAnnouncement(message); - log.info("Order sync job recap message sent"); + } @NotNull diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderMabangService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderMabangService.java index 414cf78c8..bdf6a1121 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderMabangService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/service/IPlatformOrderMabangService.java @@ -1,6 +1,8 @@ package org.jeecg.modules.business.service; import com.baomidou.mybatisplus.extension.service.IService; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; import org.jeecg.modules.business.domain.api.mabang.getorderlist.Order; import org.jeecg.modules.business.domain.api.mabang.getorderlist.OrderListRequestBody; import org.jeecg.modules.business.vo.PlatformOrderOperation; @@ -40,4 +42,6 @@ public interface IPlatformOrderMabangService extends IService { void clearLogisticChannel(List orders, ExecutorService executor); String stripAccents(String input); + + JSONObject syncOrdersFromMabang(List platformOrderIds) throws JSONException; } 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 17555acd1..d5593bec2 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 @@ -1,8 +1,12 @@ package org.jeecg.modules.business.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.jeecg.common.system.api.ISysBaseAPI; import org.jeecg.common.system.vo.LoginUser; import org.jeecg.modules.business.domain.api.mabang.dochangeorder.*; import org.jeecg.modules.business.domain.api.mabang.getorderlist.*; @@ -23,6 +27,7 @@ import java.text.Normalizer; 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.function.Function; import java.util.stream.Collectors; @@ -40,6 +45,8 @@ import static java.util.stream.Collectors.toList; public class PlatformOrderMabangServiceImpl extends ServiceImpl implements IPlatformOrderMabangService { @Autowired private PlatformOrderMabangMapper platformOrderMabangMapper; + @Autowired + private ISysBaseAPI ISysBaseApi; private static final Integer DEFAULT_NUMBER_OF_THREADS = 2; private static final Integer MABANG_API_RATE_LIMIT_PER_MINUTE = 10; @@ -324,4 +331,46 @@ public class PlatformOrderMabangServiceImpl extends ServiceImpl platformOrderIds) throws JSONException { + log.info("Syncing following orders {}", platformOrderIds); + List> platformOrderIdLists = Lists.partition(platformOrderIds, 10); + List requests = new ArrayList<>(); + for (List platformOrderIdList : platformOrderIdLists) { + requests.add(new OrderListRequestBody().setPlatformOrderIds(platformOrderIdList)); + } + List mabangOrders = new ArrayList<>(); + ExecutorService executor = Executors.newFixedThreadPool(10); + 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(); + List syncedOrderIds = mabangOrders.stream().map(Order::getPlatformOrderId).collect(Collectors.toList()); + log.info("{}/{} mabang orders have been retrieved.", syncedOrderNumber, platformOrderIds.size()); + + log.info("{} orders to be updated.", syncedOrderNumber); + saveOrderFromMabang(mabangOrders); + + JSONObject res = new JSONObject(); + res.put("synced_order_number", syncedOrderNumber); + res.put("synced_order_ids", syncedOrderIds); + return res; + } + } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/client/orderManagementNotification.ftl b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/client/orderManagementNotification.ftl index c41d01daf..da72236c7 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/client/orderManagementNotification.ftl +++ b/jeecg-module-system/jeecg-system-biz/src/main/resources/templates/client/orderManagementNotification.ftl @@ -7,7 +7,13 @@ <#if cancelSuccessCount??> - Demandes d'annulations de commande : ${cancelSuccessCount} réussie(s) + Demandes d'annulations de commande : ${cancelSuccessCount} réussie(s) : +
    + <#list cancelSuccesses as success> +
  • ${success}
  • + +
+ <#if cancelFailures?size gt 0 > @@ -23,7 +29,13 @@ <#if suspendSuccessCount??> - Demandes de suspension de commande : ${suspendSuccessCount} réussie(s) + Demandes de suspension de commande : ${suspendSuccessCount} réussie(s) : +
    + <#list suspendSuccesses as success> +
  • ${success}
  • + +
+ <#if suspendFailures?size gt 0 > @@ -39,7 +51,13 @@ <#if editSuccessCount??> - Demandes de modification d'informations de commande : ${editSuccessCount} réussie(s) + Demandes de modification d'informations de commande : ${editSuccessCount} réussie(s) : +
    + <#list editSuccesses as success> +
  • ${success}
  • + +
+ <#if editFailures?size gt 0 > From 964e30f16d08738b5c8dced13cebb81e0ef8d272 Mon Sep 17 00:00:00 2001 From: Gauthier LO Date: Thu, 4 Jul 2024 16:12:50 +0200 Subject: [PATCH 3/5] fix: mabang job, overriding order content --- .../impl/PlatformOrderMabangServiceImpl.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) 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 d5593bec2..14bb51cdf 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 @@ -17,6 +17,7 @@ import org.jeecg.modules.business.domain.job.ThrottlingExecutorService; import org.jeecg.modules.business.entity.PlatformOrder; import org.jeecg.modules.business.mapper.PlatformOrderMabangMapper; import org.jeecg.modules.business.service.IPlatformOrderMabangService; +import org.jeecg.modules.business.service.IPlatformOrderService; import org.jeecg.modules.business.vo.PlatformOrderOperation; import org.jeecg.modules.business.vo.Responses; import org.springframework.beans.factory.annotation.Autowired; @@ -46,6 +47,8 @@ public class PlatformOrderMabangServiceImpl extends ServiceImpl allNewItems = prepareItems(newOrders); try { - if (newOrders.size() != 0) { + if (!newOrders.isEmpty()) { log.info("{} orders to be inserted/updated.", newOrders.size()); platformOrderMabangMapper.insertOrdersFromMabang(newOrders); } - if (allNewItems.size() != 0) { + if (!allNewItems.isEmpty()) { platformOrderMabangMapper.insertOrderItemsFromMabang(allNewItems); log.info("{} order items to be inserted/updated.", allNewItems.size()); } @@ -138,12 +144,12 @@ public class PlatformOrderMabangServiceImpl extends ServiceImpl allNewItemsOfOldItems = prepareItems(oldOrders); try { - if (oldOrders.size() != 0) { + if (!oldOrders.isEmpty()) { log.info("{} orders to be inserted/updated.", oldOrders.size()); platformOrderMabangMapper.batchUpdateById(oldOrders); platformOrderMabangMapper.batchDeleteByMainID(oldOrders.stream().map(Order::getId).collect(toList())); } - if (ordersFromShippedToCompleted.size() != 0) { + if (!ordersFromShippedToCompleted.isEmpty()) { log.info("{} orders to be updated from Shipped to Completed.", ordersFromShippedToCompleted.size()); platformOrderMabangMapper.batchUpdateById(ordersFromShippedToCompleted); log.info("Contents of {} orders to be updated from Shipped to Completed.", ordersFromShippedToCompleted.size()); @@ -151,7 +157,7 @@ public class PlatformOrderMabangServiceImpl extends ServiceImpl Date: Mon, 29 Jul 2024 10:05:31 +0200 Subject: [PATCH 4/5] something --- .../business/domain/job/ArchiveOrderJob.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ArchiveOrderJob.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ArchiveOrderJob.java index 89e9485b8..99591848f 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ArchiveOrderJob.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/job/ArchiveOrderJob.java @@ -7,6 +7,7 @@ import org.codehaus.jettison.json.JSONObject; import org.jeecg.modules.business.domain.api.mabang.dochangeorder.ArchiveOrderRequest; import org.jeecg.modules.business.domain.api.mabang.dochangeorder.ArchiveOrderRequestBody; import org.jeecg.modules.business.domain.api.mabang.dochangeorder.ChangeOrderResponse; +import org.jeecg.modules.business.service.IPlatformOrderMabangService; import org.jeecg.modules.business.service.IPlatformOrderService; import org.quartz.Job; import org.quartz.JobDataMap; @@ -36,6 +37,8 @@ public class ArchiveOrderJob implements Job { @Autowired private IPlatformOrderService platformOrderService; + @Autowired + private IPlatformOrderMabangService platformOrderMabangService; @Override public void execute(JobExecutionContext context) throws JobExecutionException { @@ -86,7 +89,7 @@ public class ArchiveOrderJob implements Job { platformOrderIds.forEach(s -> archiveOrderRequestBodies.add(new ArchiveOrderRequestBody(s))); log.info("{} order archiving requests to be sent to MabangAPI", archiveOrderRequestBodies.size()); - + List platformOrderIdsArchived = new ArrayList<>(); List> changeOrderFutures = archiveOrderRequestBodies.stream() .map(archiveOrderRequestBody -> CompletableFuture.supplyAsync(() -> { boolean success = false; @@ -94,7 +97,9 @@ public class ArchiveOrderJob implements Job { ArchiveOrderRequest archiveOrderRequest = new ArchiveOrderRequest(archiveOrderRequestBody); ChangeOrderResponse response = archiveOrderRequest.send(); success = response.success(); - } catch (RuntimeException e) { + if(success) + platformOrderIdsArchived.add(archiveOrderRequestBody.getPlatformOrderId()); + } catch (RuntimeException e) { log.error("Error communicating with MabangAPI", e); } return success; @@ -103,5 +108,11 @@ public class ArchiveOrderJob implements Job { List results = changeOrderFutures.stream().map(CompletableFuture::join).collect(Collectors.toList()); long nbSuccesses = results.stream().filter(b -> b).count(); log.info("{}/{} order archiving requests have succeeded.", nbSuccesses, archiveOrderRequestBodies.size()); + + try { + platformOrderMabangService.syncOrdersFromMabang(platformOrderIdsArchived); + } catch (JSONException e) { + throw new RuntimeException(e); + } } } From cbb066032eeb4007f982ab080ec29db64153c9ce Mon Sep 17 00:00:00 2001 From: Gauthier LO Date: Mon, 29 Jul 2024 11:56:01 +0200 Subject: [PATCH 5/5] Feat : shipping fee difference --- .../domain/logistic/CostTrialCalculation.java | 31 ++++++++++++++++--- .../mapper/LogisticChannelPriceMapper.java | 2 +- .../mapper/xml/LogisticChannelPriceMapper.xml | 2 +- .../service/ILogisticChannelService.java | 2 +- .../impl/LogisticChannelPriceServiceImpl.java | 7 +++-- .../impl/LogisticChannelServiceImpl.java | 12 +++++-- 6 files changed, 44 insertions(+), 12 deletions(-) diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/logistic/CostTrialCalculation.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/logistic/CostTrialCalculation.java index 2100661e7..9a5cdc5bf 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/logistic/CostTrialCalculation.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/domain/logistic/CostTrialCalculation.java @@ -32,9 +32,19 @@ public class CostTrialCalculation { private final BigDecimal additionalCost; + private final BigDecimal previousUnitPrice; - private CostTrialCalculation(String countryCode, String logisticsChannelName, String logisticChannelCode, BigDecimal unitPrice, BigDecimal shippingCost, - BigDecimal registrationCost, BigDecimal additionalCost, Date effectiveDate) { + private final BigDecimal previousShippingCost; + + private final BigDecimal previousRegistrationCost; + + private final BigDecimal previousAdditionalCost; + + + + private CostTrialCalculation(String countryCode, String logisticsChannelName, String logisticChannelCode, + BigDecimal unitPrice, BigDecimal shippingCost, BigDecimal registrationCost, BigDecimal additionalCost, Date effectiveDate, + BigDecimal previousUnitPrice,BigDecimal previousShippingCost, BigDecimal previousRegistrationCost, BigDecimal previousAdditionalCost) { this.countryCode = countryCode; this.logisticsChannelName = logisticsChannelName; this.logisticChannelCode = logisticChannelCode; @@ -43,15 +53,28 @@ public class CostTrialCalculation { this.registrationCost = registrationCost; this.additionalCost = additionalCost; this.effectiveDate = effectiveDate; + this.previousUnitPrice = previousUnitPrice; + this.previousShippingCost = previousShippingCost; + this.previousRegistrationCost = previousRegistrationCost; + this.previousAdditionalCost = previousAdditionalCost; } - public CostTrialCalculation(LogisticChannelPrice price, int weight, String logisticsChannelName, String code) { + public CostTrialCalculation(LogisticChannelPrice price, LogisticChannelPrice previousPrice,int weight, String logisticsChannelName, String code) { this(price.getEffectiveCountry(), logisticsChannelName, code, price.getCalUnitPrice(), price.calculateShippingPrice(BigDecimal.valueOf(weight)), - price.getRegistrationFee(), price.getAdditionalCost(), price.getEffectiveDate()); + price.getRegistrationFee(), price.getAdditionalCost(), price.getEffectiveDate(), + previousPrice.getCalUnitPrice(), previousPrice.calculateShippingPrice(BigDecimal.valueOf(weight)), previousPrice.getRegistrationFee(), previousPrice.getAdditionalCost() + ); } @JsonProperty("TotalCost") public double getTotalCost() { return shippingCost.add(registrationCost).add(additionalCost).setScale(2, RoundingMode.CEILING).doubleValue(); } + + @JsonProperty("CostDifference") + public double getCostDifference() { + double previousCost = previousShippingCost.add(previousRegistrationCost).add(previousAdditionalCost).setScale(2, RoundingMode.CEILING).doubleValue(); + BigDecimal diff = BigDecimal.valueOf((getTotalCost() - previousCost) / previousCost * 100); + return diff.setScale(2, RoundingMode.CEILING).doubleValue(); + } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/LogisticChannelPriceMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/LogisticChannelPriceMapper.java index 7002cedd9..955969d8f 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/LogisticChannelPriceMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/LogisticChannelPriceMapper.java @@ -34,7 +34,7 @@ public interface LogisticChannelPriceMapper extends BaseMapper findBy( @Param("channelName") String channelName, @Param("date") Date shippingTime, @Param("trueWeight") BigDecimal weight, diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/LogisticChannelPriceMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/LogisticChannelPriceMapper.xml index bdac56ddb..a36890c23 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/LogisticChannelPriceMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/business/mapper/xml/LogisticChannelPriceMapper.xml @@ -33,7 +33,7 @@ AND effective_date <= #{date} AND active = 1 ORDER BY effective_date DESC - LIMIT 1 + LIMIT 2