feat: sku weight update in app and mabang

pull/8040/head
Gauthier LO 2024-12-16 16:05:44 +01:00
parent 74e7df9dda
commit 3a6812c6a3
7 changed files with 135 additions and 60 deletions

View File

@ -1,9 +1,6 @@
package org.jeecg.modules.business.controller.admin;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -15,6 +12,7 @@ import org.jeecg.modules.business.entity.Sku;
import org.jeecg.modules.business.entity.SkuWeight;
import org.jeecg.modules.business.mongoService.SkuMongoService;
import org.jeecg.modules.business.service.ISecurityService;
import org.jeecg.modules.business.service.ISkuListMabangService;
import org.jeecg.modules.business.service.ISkuService;
import org.jeecg.modules.business.service.ISkuWeightService;
@ -24,6 +22,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.modules.business.vo.Responses;
import org.jeecg.modules.business.vo.SkuWeightParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
@ -45,6 +44,8 @@ import org.apache.shiro.authz.annotation.RequiresPermissions;
@RequestMapping("/skuWeight")
@Slf4j
public class SkuWeightController extends JeecgController<SkuWeight, ISkuWeightService> {
@Autowired
private ISkuListMabangService skuListMabangService;
@Autowired
private ISkuService skuService;
@Autowired
@ -164,7 +165,8 @@ public class SkuWeightController extends JeecgController<SkuWeight, ISkuWeightSe
}
/**
* Updating weight of multiple SKUs, creates new sku_weight entries with new effective_date and weight.
* /!\ Not maintained use updateBatch instead.
* Updating weight of a SKU, creates new sku_weight entry with new effective_date and weight.
* @param param
* @return
*/
@ -188,16 +190,23 @@ public class SkuWeightController extends JeecgController<SkuWeight, ISkuWeightSe
skuWeightService.save(skuWeight);
return Result.OK("data.invoice.effectiveDate");
}
/**
* Updating weight of multiple SKUs, creates new sku_weight entries with new effective_date and weight.
* Updates the weight in Mabang.
* Updates the weight in MongoDB.
* @param param
* @return
*/
@Transactional
@PostMapping(value = "/updateBatch")
public Result<String> updateBatch(@RequestBody SkuWeightParam param) {
public Result<?> updateBatch(@RequestBody SkuWeightParam param) {
boolean isEmployee = securityService.checkIsEmployee();
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
if(!isEmployee){
log.info("User {}, tried to access /skuWeight/updateBatch but is not authorized.", sysUser.getUsername());
return Result.error(403,"Forbidden.");
}
List<SkuWeight> skuWeights = new ArrayList<>();
Map<String, SkuWeight> skuWeightsMap = new HashMap<>();
for(String skuId : param.getIds()){
Sku sku = skuService.getById(skuId);
if(sku == null){
@ -208,10 +217,15 @@ public class SkuWeightController extends JeecgController<SkuWeight, ISkuWeightSe
skuWeight.setEffectiveDate(param.getEffectiveDate());
skuWeight.setSkuId(skuId);
skuWeight.setWeight(param.getWeight());
skuWeights.add(skuWeight);
skuMongoService.upsertSkuWeight(skuWeight);
skuWeightsMap.put(sku.getErpCode(), skuWeight);
}
List<SkuWeight> skuWeights = new ArrayList<>(skuWeightsMap.values());
Responses responses = skuListMabangService.mabangSkuWeightUpdate(skuWeights);
List<SkuWeight> skuWeightSuccesses = new ArrayList<>();
responses.getSuccesses().forEach(skuErpCode -> skuWeightSuccesses.add(skuWeightsMap.get(skuErpCode)));
skuWeightSuccesses.forEach(skuWeight -> skuMongoService.upsertSkuWeight(skuWeight));
skuWeightService.saveBatch(skuWeights);
return Result.OK("data.invoice.effectiveDate");
return Result.OK(responses);
}
}

View File

@ -75,7 +75,7 @@ public class SkuData {
@JSONField(name="height")
private String height;
@JSONField(name="weight")
private Double weight;
private Integer weight;
/**
* saleRemark contains the weight
*/

View File

@ -18,15 +18,16 @@ import org.springframework.http.ResponseEntity;
*/
@Slf4j
public class SkuChangeRequest extends Request {
private final SkuChangeRequestBody body;
public SkuChangeRequest(SkuChangeRequestBody body) {
super(body);
this.body = body;
}
@Override
public SkuChangeResponse send() {
ResponseEntity<String> res = rawSend();
return SkuChangeResponse.parse(JSON.parseObject(res.getBody()));
return SkuChangeResponse.parse(JSON.parseObject(res.getBody()), body.getStockSku());
}
}

View File

@ -19,21 +19,12 @@ public class SkuChangeRequestBody implements RequestBody {
private String nameEn;
private Integer status;
private BigDecimal salePrice;
private BigDecimal declareValue;
private String declareName;
private String declareEname;
private String warehouse;
private String remark;
private Integer hasBattery;
private Integer magnetic;
private Integer powder;
private Integer isPaste;
private Integer noLiquidCosmetic;
private Integer isFlammable;
private Integer isKnife;
private Integer weight;
private Integer isGift;
private String supplier;
private String supplierLink;
@Override
public String api() {
@ -48,32 +39,11 @@ public class SkuChangeRequestBody implements RequestBody {
putNonNull(json, "nameEN", nameEn);
putNonNull(json, "status", status);
putNonNull(json, "salePrice", salePrice);
putNonNull(json, "declareValue", declareValue);
putNonNull(json, "declareName", declareName);
putNonNull(json, "declareEname", declareEname);
JSONArray warehouseData = new JSONArray();
JSONObject warehouse = new JSONObject();
warehouse.put("name", this.warehouse);
warehouseData.add(warehouse);
json.put("warehouseData", warehouseData.toJSONString());
putNonNull(json, "weight", remark);
putNonNull(json, "weight", weight);
putNonNull(json, "saleRemark", remark);
putNonNull(json, "hasBattery", hasBattery);
putNonNull(json, "magnetic", magnetic);
putNonNull(json, "powder", powder);
putNonNull(json, "ispaste", isPaste);
putNonNull(json, "noLiquidCosmetic", noLiquidCosmetic);
putNonNull(json, "is_flammable", isFlammable);
putNonNull(json, "is_knife", isKnife);
putNonNull(json, "isGift", isGift);
putNonNull(json, "autoCreateSupplier", 1);
JSONArray supplierData = new JSONArray();
JSONObject supplier = new JSONObject();
supplier.put("name", this.supplier);
supplier.put("productLinkAddress", this.supplierLink);
supplier.put("flag", 1);
supplierData.add(supplier);
json.put("suppliersData", supplierData.toJSONString());
return json;
}
@ -82,21 +52,11 @@ public class SkuChangeRequestBody implements RequestBody {
this.nameCn = data.getNameCN();
this.nameEn = data.getNameEN();
this.salePrice = data.getSalePrice();
this.declareValue = data.getDeclareValue();
this.declareName = data.getDeclareNameZh();
this.declareEname = data.getDeclareNameEn();
this.warehouse = data.getWarehouse();
this.remark = data.getSaleRemark();
this.hasBattery = data.getHasBattery();
this.magnetic = data.getMagnetic();
this.powder = data.getPowder();
this.isPaste = data.getIsPaste();
this.noLiquidCosmetic = data.getNoLiquidCosmetic();
this.isFlammable = data.getIsFlammable();
this.isKnife = data.getIsKnife();
this.weight = data.getWeight();
this.isGift = data.getIsGift();
this.supplier = data.getSupplier();
this.supplierLink = data.getSupplierLink();
}
private <E> void putNonNull(JSONObject json, String key, E value) {

View File

@ -35,7 +35,7 @@ public class SkuChangeResponse extends Response {
* @return Instance
* @throws SkuChangeRequestErrorException if response code represents error.
*/
public static SkuChangeResponse parse(JSONObject json) throws SkuChangeRequestErrorException {
public static SkuChangeResponse parse(JSONObject json, String erpCode) throws SkuChangeRequestErrorException {
log.debug("Constructing a response by json.");
String code = json.getString("code");
if (code.equals(Code.ERROR.value))
@ -43,21 +43,20 @@ public class SkuChangeResponse extends Response {
JSONObject data = json.getJSONObject("data");
String stockId = data.getString("stockId");
String stockSku = data.getString("stockSku");
if(data != null) {
log.info("Constructed response: data contained {}", data);
}
else {
log.info("Data is null");
}
return new SkuChangeResponse(Code.SUCCESS, data, stockId, stockSku);
return new SkuChangeResponse(Code.SUCCESS, data, stockId, erpCode);
}
@Override
public String toString() {
return "SkuListResponse{" +
return "SkuChangeResponse{" +
", data=" + data +
'}';
}

View File

@ -3,6 +3,7 @@ package org.jeecg.modules.business.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.jeecg.modules.business.domain.api.mabang.doSearchSkuListNew.SkuData;
import org.jeecg.modules.business.entity.Sku;
import org.jeecg.modules.business.entity.SkuWeight;
import org.jeecg.modules.business.vo.Responses;
import org.jeecg.modules.business.vo.SkuOrderPage;
@ -38,4 +39,6 @@ public interface ISkuListMabangService extends IService<SkuData> {
void updateSkuId();
void mabangSkuStockUpdate(List<String> erpCodes);
Responses mabangSkuWeightUpdate(List<SkuWeight> skuWeights);
}

View File

@ -1,6 +1,7 @@
package org.jeecg.modules.business.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.SpringContextUtils;
@ -9,10 +10,14 @@ import org.jeecg.modules.business.domain.api.mabang.doSearchSkuListNew.*;
import org.jeecg.modules.business.domain.api.mabang.stockDoAddStock.SkuAddRequest;
import org.jeecg.modules.business.domain.api.mabang.stockDoAddStock.SkuAddRequestBody;
import org.jeecg.modules.business.domain.api.mabang.stockDoAddStock.SkuAddResponse;
import org.jeecg.modules.business.domain.api.mabang.stockDoChangeStock.SkuChangeRequest;
import org.jeecg.modules.business.domain.api.mabang.stockDoChangeStock.SkuChangeRequestBody;
import org.jeecg.modules.business.domain.api.mabang.stockDoChangeStock.SkuChangeResponse;
import org.jeecg.modules.business.domain.api.mabang.stockGetStockQuantity.SkuStockData;
import org.jeecg.modules.business.domain.api.mabang.stockGetStockQuantity.SkuStockRawStream;
import org.jeecg.modules.business.domain.api.mabang.stockGetStockQuantity.SkuStockRequestBody;
import org.jeecg.modules.business.domain.api.mabang.stockGetStockQuantity.SkuStockStream;
import org.jeecg.modules.business.domain.job.ThrottlingExecutorService;
import org.jeecg.modules.business.entity.*;
import org.jeecg.modules.business.mapper.SkuListMabangMapper;
import org.jeecg.modules.business.mongoService.SkuMongoService;
@ -36,6 +41,7 @@ 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.regex.Matcher;
import java.util.regex.Pattern;
@ -73,6 +79,7 @@ public class SkuListMabangServiceImpl extends ServiceImpl<SkuListMabangMapper, S
Environment env;
private static final Integer DEFAULT_NUMBER_OF_THREADS = 10;
private static final Integer MABANG_API_RATE_LIMIT_PER_MINUTE = 10;
private final static String DEFAULT_WAREHOUSE_NAME = "SZBA宝安仓";
@ -626,4 +633,95 @@ public class SkuListMabangServiceImpl extends ServiceImpl<SkuListMabangMapper, S
skuMongoService.updateStock(sku);
}
}
@Override
public Responses mabangSkuWeightUpdate(List<SkuWeight> skuWeights) {
Responses responses = new Responses();
List<String> failures = new ArrayList<>();
List<Sku> skus = skuService.listByIds(skuWeights.stream()
.map(SkuWeight::getSkuId).collect(toList()));
Map<String, String> remarkMappedByErpCode = new HashMap<>();
List<List<String>> skusPartition = Lists.partition(skus.stream().map(Sku::getErpCode).collect(toList()), 50);
for(List<String> skuPartition : skusPartition) {
SkuListRequestBody body = new SkuListRequestBody();
body.setStockSkuList(String.join(",", skuPartition));
SkuListRawStream rawStream = new SkuListRawStream(body);
SkuUpdateListStream stream = new SkuUpdateListStream(rawStream);
List<SkuData> skusFromMabang = stream.all();
log.info("{} skus to be updated.", skusFromMabang.size());
if (skusFromMabang.isEmpty()) {
continue;
}
skusFromMabang.stream()
.filter(skuData -> skuData.getSaleRemark() != null)
.forEach(skuData -> {
String erpCode = skuData.getErpCode();
String remark = skuData.getSaleRemark();
remarkMappedByErpCode.put(erpCode, remark);
});
}
List<SkuData> skuDataList = skuWeights.stream()
.map(skuWeight -> {
Sku sku = skus.stream()
.filter(s -> s.getId().equals(skuWeight.getSkuId()))
.findFirst()
.orElse(null);
if(null == sku) {
log.error("Sku not found : {}", skuWeight.getSkuId());
failures.add(skuWeight.getSkuId());
return null;
}
SkuData skuData = new SkuData();
skuData.setErpCode(sku.getErpCode());
if(remarkMappedByErpCode.containsKey(sku.getErpCode())) {
StringBuilder remark = new StringBuilder();
remark.append(skuWeight.getWeight());
Matcher saleRemarkMatcher = saleRemarkPattern.matcher(remarkMappedByErpCode.get(sku.getErpCode()));
if(saleRemarkMatcher.matches() && !saleRemarkMatcher.group(2).isEmpty()) {
log.info("Sku {} has remark from Mabang : {}", sku.getErpCode(), saleRemarkMatcher.group(2));
String saleRemarkNotWeight = saleRemarkMatcher.group(2);
remark.append(saleRemarkNotWeight);
}
skuData.setSaleRemark(remark.toString());
}
else {
skuData.setSaleRemark(String.valueOf(skuWeight.getWeight()));
}
skuData.setWeight(skuWeight.getWeight());
return skuData;
})
.filter(Objects::nonNull)
.collect(toList());
ExecutorService executor = ThrottlingExecutorService.createExecutorService(DEFAULT_NUMBER_OF_THREADS, MABANG_API_RATE_LIMIT_PER_MINUTE, TimeUnit.MINUTES);
List<CompletableFuture<SkuChangeResponse>> futures = skuDataList.stream()
.map(skuData -> CompletableFuture.supplyAsync(() -> {
try {
SkuChangeRequestBody body = new SkuChangeRequestBody(skuData);
SkuChangeRequest request = new SkuChangeRequest(body);
return request.send();
} catch (Exception e) {
log.error("Error updating weight for sku {} : {}", skuData.getErpCode(), e.getMessage());
return new SkuChangeResponse(Response.Code.ERROR, null, null, skuData.getErpCode());
}
}, executor))
.collect(toList());
List<SkuChangeResponse> results = futures.stream().map(CompletableFuture::join).collect(toList());
long successCount = results.stream().filter(SkuChangeResponse::success).count();
log.info("{}/{} skus updated successfully.", successCount, skuDataList.size());
List<String> successes = results.stream()
.filter(SkuChangeResponse::success)
.map(SkuChangeResponse::getStockSku)
.collect(toList());
failures.addAll(results.stream()
.filter(response -> !response.success())
.map(SkuChangeResponse::getStockSku)
.collect(toList()));
responses.setSuccesses(successes);
responses.setFailures(failures);
return responses;
}
}