|
|
@@ -1,6 +1,10 @@
|
|
|
package com.fs.his.service.impl;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
+import java.net.URL;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@@ -40,6 +44,7 @@ import com.fs.his.utils.ConfigUtil;
|
|
|
import com.fs.his.vo.*;
|
|
|
import com.fs.hisStore.vo.FsStoreProductListVO;
|
|
|
import com.fs.live.domain.LiveGoods;
|
|
|
+import com.fs.system.oss.OSSFactory;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
@@ -57,6 +62,9 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
*/
|
|
|
@Service
|
|
|
public class FsStoreProductServiceImpl implements IFsStoreProductService {
|
|
|
+ private static final DateTimeFormatter ERP_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
+ private static final int MAX_QUERY_RANGE_DAYS = 7;
|
|
|
+ private static final int DEFAULT_ERP_PAGE_SIZE = 100;
|
|
|
@Autowired
|
|
|
private FsStoreProductMapper fsStoreProductMapper;
|
|
|
|
|
|
@@ -890,9 +898,261 @@ public class FsStoreProductServiceImpl implements IFsStoreProductService {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 批量获取商品编码 获取erp商品信息更新商品及属性等信息
|
|
|
- * @return
|
|
|
+ * 按ERP修改时间区间同步商品,自动拆分7天窗口并处理分页。
|
|
|
+ * 同步字段与 updateStoreProductByErpProductCode 保持一致:
|
|
|
+ * 商品:productName、price、costPrice、otPrice、imgUrl、unitName、brand、prescribeSpec、prescribeFactory
|
|
|
+ * 规格:price、cost、otPrice、image、weight
|
|
|
*/
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public int syncProductFromErp(String modifiedBegin, String modifiedEnd, Integer pageSize) {
|
|
|
+ LocalDateTime begin = parseDateTime(modifiedBegin);
|
|
|
+ LocalDateTime end = parseDateTime(modifiedEnd);
|
|
|
+ if (begin.isAfter(end)) {
|
|
|
+ throw new ServiceException("modified_begin 不能大于 modified_end");
|
|
|
+ }
|
|
|
+
|
|
|
+ int actualPageSize = normalizePageSize(pageSize);
|
|
|
+ int totalSyncCount = 0;
|
|
|
+ LocalDateTime windowBegin = begin;
|
|
|
+
|
|
|
+ while (!windowBegin.isAfter(end)) {
|
|
|
+ LocalDateTime windowEnd = windowBegin.plusDays(MAX_QUERY_RANGE_DAYS).minusSeconds(1);
|
|
|
+ if (windowEnd.isAfter(end)) {
|
|
|
+ windowEnd = end;
|
|
|
+ }
|
|
|
+
|
|
|
+ totalSyncCount += syncProductWindow(windowBegin, windowEnd, actualPageSize);
|
|
|
+ windowBegin = windowEnd.plusSeconds(1);
|
|
|
+ }
|
|
|
+ return totalSyncCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int syncProductWindow(LocalDateTime windowBegin, LocalDateTime windowEnd, int pageSize) {
|
|
|
+ int pageIndex = 1;
|
|
|
+ int syncCount = 0;
|
|
|
+ boolean hasNext = true;
|
|
|
+
|
|
|
+ while (hasNext) {
|
|
|
+ ProductQueryRequestDTO queryDTO = new ProductQueryRequestDTO();
|
|
|
+ queryDTO.setModifiedBegin(formatDateTime(windowBegin));
|
|
|
+ queryDTO.setModifiedEnd(formatDateTime(windowEnd));
|
|
|
+ queryDTO.setPageIndex(pageIndex);
|
|
|
+ queryDTO.setPageSize(pageSize);
|
|
|
+ queryDTO.setDateField("modified");
|
|
|
+
|
|
|
+ ProductResponseDTO response = jstErpHttpService.queryGoods(queryDTO);
|
|
|
+ if (response == null || response.getDatas() == null || response.getDatas().isEmpty()) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (ProductResponseDTO.ProductInfo erpProduct : response.getDatas()) {
|
|
|
+ if (StringUtils.isBlank(erpProduct.getSkuId())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ syncCount += syncSingleProductFromErp(erpProduct);
|
|
|
+ }
|
|
|
+
|
|
|
+ hasNext = Boolean.TRUE.equals(response.getHasNext());
|
|
|
+ pageIndex++;
|
|
|
+ }
|
|
|
+ return syncCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int syncSingleProductFromErp(ProductResponseDTO.ProductInfo erpProduct) {
|
|
|
+ FsStoreProductAttrValue attrQuery = new FsStoreProductAttrValue();
|
|
|
+ attrQuery.setBarCode(erpProduct.getSkuId());
|
|
|
+ List<FsStoreProductAttrValue> attrList = fsStoreProductAttrValueMapper.selectFsStoreProductAttrValueList(attrQuery);
|
|
|
+ if (attrList == null || attrList.isEmpty()) {
|
|
|
+ return insertProductByErpData(erpProduct);
|
|
|
+ }
|
|
|
+
|
|
|
+ int updateCount = 0;
|
|
|
+ for (FsStoreProductAttrValue attr : attrList) {
|
|
|
+ FsStoreProduct product = fsStoreProductMapper.selectFsStoreProductByProductId(attr.getProductId());
|
|
|
+ if (product == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ updateProductByErpData(product, erpProduct);
|
|
|
+ updateAttrValueByErpData(product,attr, erpProduct);
|
|
|
+ updatePackageProductJson(product.getProductId(), erpProduct);
|
|
|
+ updateCount++;
|
|
|
+ }
|
|
|
+ return updateCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int insertProductByErpData(ProductResponseDTO.ProductInfo erpProduct) {
|
|
|
+ FsStoreProduct newProduct = new FsStoreProduct();
|
|
|
+ newProduct.setStoreId(20191853L);
|
|
|
+ newProduct.setBarCode(erpProduct.getSkuId());
|
|
|
+ newProduct.setProductName(erpProduct.getName());
|
|
|
+ newProduct.setPrice(erpProduct.getSalePrice());
|
|
|
+ newProduct.setCostPrice(erpProduct.getCostPrice());
|
|
|
+ newProduct.setOtPrice(erpProduct.getMarketPrice());
|
|
|
+ newProduct.setImgUrl(normalizeErpImageUrl(erpProduct.getPic()));
|
|
|
+ newProduct.setUnitName(erpProduct.getUnit());
|
|
|
+ newProduct.setBrand(erpProduct.getBrand());
|
|
|
+ newProduct.setPrescribeSpec(erpProduct.getPropertiesValue());
|
|
|
+ newProduct.setPrescribeFactory(erpProduct.getSupplierName());
|
|
|
+ newProduct.setStock(0);
|
|
|
+ newProduct.setSales(0);
|
|
|
+ newProduct.setSort(0L);
|
|
|
+ newProduct.setSpecType(0);
|
|
|
+ newProduct.setIsShow(1);
|
|
|
+ newProduct.setIsDisplay(1);
|
|
|
+ newProduct.setIsDel(0);
|
|
|
+ newProduct.setIsBest(0);
|
|
|
+ newProduct.setIsBenefit(0);
|
|
|
+ newProduct.setIsHot(0);
|
|
|
+ newProduct.setIsNew(0);
|
|
|
+ newProduct.setIsPostage(0);
|
|
|
+ newProduct.setViews(0L);
|
|
|
+ newProduct.setGiveIntegral(BigDecimal.ZERO);
|
|
|
+ newProduct.setCreateTime(DateUtils.getNowDate());
|
|
|
+ newProduct.setUpdateTime(DateUtils.getNowDate());
|
|
|
+ fsStoreProductMapper.insertFsStoreProduct(newProduct);
|
|
|
+
|
|
|
+ FsStoreProductAttrValue newAttr = new FsStoreProductAttrValue();
|
|
|
+ newAttr.setProductId(newProduct.getProductId());
|
|
|
+ newAttr.setSku(erpProduct.getName());
|
|
|
+ newAttr.setStock(0);
|
|
|
+ newAttr.setSales(0);
|
|
|
+ newAttr.setPrice(erpProduct.getSalePrice());
|
|
|
+ newAttr.setImage(newProduct.getImgUrl());
|
|
|
+ newAttr.setCost(erpProduct.getCostPrice());
|
|
|
+ newAttr.setBarCode(erpProduct.getSkuId());
|
|
|
+ newAttr.setOtPrice(erpProduct.getMarketPrice());
|
|
|
+ newAttr.setWeight(erpProduct.getWeight());
|
|
|
+ newAttr.setVolume(BigDecimal.ZERO);
|
|
|
+ newAttr.setBrokerage(BigDecimal.ZERO);
|
|
|
+ newAttr.setBrokerageTwo(BigDecimal.ZERO);
|
|
|
+ newAttr.setBrokerageThree(BigDecimal.ZERO);
|
|
|
+ newAttr.setDoctorBrokerage(BigDecimal.ZERO);
|
|
|
+ newAttr.setGiveIntegral(0);
|
|
|
+ fsStoreProductAttrValueMapper.insertFsStoreProductAttrValue(newAttr);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void updateProductByErpData(FsStoreProduct product, ProductResponseDTO.ProductInfo erpProduct) {
|
|
|
+ FsStoreProduct updateProduct = new FsStoreProduct();
|
|
|
+ updateProduct.setProductId(product.getProductId());
|
|
|
+ updateProduct.setProductName(erpProduct.getName());
|
|
|
+ updateProduct.setPrice(erpProduct.getSalePrice());
|
|
|
+ updateProduct.setCostPrice(erpProduct.getCostPrice());
|
|
|
+ updateProduct.setOtPrice(erpProduct.getMarketPrice());
|
|
|
+ updateProduct.setImgUrl(normalizeErpImageUrl(erpProduct.getPic()));
|
|
|
+ updateProduct.setUnitName(erpProduct.getUnit());
|
|
|
+ updateProduct.setBrand(erpProduct.getBrand());
|
|
|
+ updateProduct.setPrescribeSpec(erpProduct.getPropertiesValue());
|
|
|
+ updateProduct.setPrescribeFactory(erpProduct.getSupplierName());
|
|
|
+ fsStoreProductMapper.updateFsStoreProduct(updateProduct);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void updateAttrValueByErpData(FsStoreProduct product,FsStoreProductAttrValue attr, ProductResponseDTO.ProductInfo erpProduct) {
|
|
|
+ FsStoreProductAttrValue updateAttr = new FsStoreProductAttrValue();
|
|
|
+ updateAttr.setId(attr.getId());
|
|
|
+ updateAttr.setPrice(erpProduct.getSalePrice());
|
|
|
+ updateAttr.setCost(erpProduct.getCostPrice());
|
|
|
+ updateAttr.setOtPrice(erpProduct.getMarketPrice());
|
|
|
+ updateAttr.setImage(product.getImgUrl());
|
|
|
+ updateAttr.setWeight(erpProduct.getWeight());
|
|
|
+ fsStoreProductAttrValueMapper.updateFsStoreProductAttrValue(updateAttr);
|
|
|
+ }
|
|
|
+
|
|
|
+ private LocalDateTime parseDateTime(String time) {
|
|
|
+ try {
|
|
|
+ return LocalDateTime.parse(time, ERP_TIME_FORMATTER);
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new ServiceException("时间格式错误,请使用 yyyy-MM-dd HH:mm:ss");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private String formatDateTime(LocalDateTime time) {
|
|
|
+ return time.truncatedTo(ChronoUnit.SECONDS).format(ERP_TIME_FORMATTER);
|
|
|
+ }
|
|
|
+
|
|
|
+ private int normalizePageSize(Integer pageSize) {
|
|
|
+ if (pageSize == null || pageSize <= 0) {
|
|
|
+ return DEFAULT_ERP_PAGE_SIZE;
|
|
|
+ }
|
|
|
+ return Math.min(pageSize, DEFAULT_ERP_PAGE_SIZE);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String normalizeErpImageUrl(String imageUrl) {
|
|
|
+ if (StringUtils.isBlank(imageUrl)) {
|
|
|
+ return imageUrl;
|
|
|
+ }
|
|
|
+ if (imageUrl.contains("obs.hbhdt.top")) {
|
|
|
+ return imageUrl;
|
|
|
+ }
|
|
|
+ if (!imageUrl.startsWith("http://") && !imageUrl.startsWith("https://")) {
|
|
|
+ return imageUrl;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ if (OSSFactory.build() == null) {
|
|
|
+ return imageUrl;
|
|
|
+ }
|
|
|
+ String suffix = getImageSuffix(imageUrl);
|
|
|
+ return OSSFactory.build().uploadSuffix(new URL(imageUrl).openStream(), suffix);
|
|
|
+ } catch (Exception e) {
|
|
|
+ return imageUrl;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public int replaceErpImageUrls() {
|
|
|
+ int count = 0;
|
|
|
+
|
|
|
+ List<FsStoreProduct> products = fsStoreProductMapper.selectFsStoreProductList(new FsStoreProduct());
|
|
|
+ if (products != null && !products.isEmpty()) {
|
|
|
+ for (FsStoreProduct product : products) {
|
|
|
+ if (StringUtils.isBlank(product.getImgUrl()) || product.getImgUrl().contains("obs.hbhdt.top")) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String newImgUrl = normalizeErpImageUrl(product.getImgUrl());
|
|
|
+ if (!StringUtils.equals(product.getImgUrl(), newImgUrl)) {
|
|
|
+ FsStoreProduct updateProduct = new FsStoreProduct();
|
|
|
+ updateProduct.setProductId(product.getProductId());
|
|
|
+ updateProduct.setImgUrl(newImgUrl);
|
|
|
+ fsStoreProductMapper.updateFsStoreProduct(updateProduct);
|
|
|
+ count++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ List<FsStoreProductAttrValue> attrValues = fsStoreProductAttrValueMapper.selectFsStoreProductAttrValueList(new FsStoreProductAttrValue());
|
|
|
+ if (attrValues != null && !attrValues.isEmpty()) {
|
|
|
+ for (FsStoreProductAttrValue attrValue : attrValues) {
|
|
|
+ if (StringUtils.isBlank(attrValue.getImage()) || attrValue.getImage().contains("obs.hbhdt.top")) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String newImage = normalizeErpImageUrl(attrValue.getImage());
|
|
|
+ if (!StringUtils.equals(attrValue.getImage(), newImage)) {
|
|
|
+ FsStoreProductAttrValue updateAttr = new FsStoreProductAttrValue();
|
|
|
+ updateAttr.setId(attrValue.getId());
|
|
|
+ updateAttr.setImage(newImage);
|
|
|
+ fsStoreProductAttrValueMapper.updateFsStoreProductAttrValue(updateAttr);
|
|
|
+ count++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return count;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getImageSuffix(String imageUrl) {
|
|
|
+ String url = imageUrl;
|
|
|
+ int queryIndex = url.indexOf('?');
|
|
|
+ if (queryIndex >= 0) {
|
|
|
+ url = url.substring(0, queryIndex);
|
|
|
+ }
|
|
|
+ int dotIndex = url.lastIndexOf('.');
|
|
|
+ if (dotIndex < 0) {
|
|
|
+ return ".jpg";
|
|
|
+ }
|
|
|
+ return url.substring(dotIndex);
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public int updateStoreProductByErpProductCode() {
|
|
|
List<FsStoreProduct> productList = fsStoreProductMapper.selectFsStoreProductList(new FsStoreProduct());
|
|
|
@@ -939,19 +1199,7 @@ public class FsStoreProductServiceImpl implements IFsStoreProductService {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- FsStoreProduct updateProduct = new FsStoreProduct();
|
|
|
- updateProduct.setProductId(product.getProductId());
|
|
|
- updateProduct.setProductName(erpProduct.getName());
|
|
|
- updateProduct.setPrice(erpProduct.getSalePrice());
|
|
|
- updateProduct.setCostPrice(erpProduct.getCostPrice());
|
|
|
- updateProduct.setOtPrice(erpProduct.getMarketPrice());
|
|
|
- updateProduct.setImgUrl(erpProduct.getPic());
|
|
|
- updateProduct.setUnitName(erpProduct.getUnit());
|
|
|
- updateProduct.setBrand(erpProduct.getBrand());
|
|
|
- updateProduct.setPrescribeSpec(erpProduct.getPropertiesValue());
|
|
|
- updateProduct.setPrescribeFactory(erpProduct.getSupplierName());
|
|
|
-
|
|
|
- fsStoreProductMapper.updateFsStoreProduct(updateProduct);
|
|
|
+ updateProductByErpData(product, erpProduct);
|
|
|
updateCount++;
|
|
|
|
|
|
FsStoreProductAttrValue attrQuery = new FsStoreProductAttrValue();
|
|
|
@@ -961,15 +1209,7 @@ public class FsStoreProductServiceImpl implements IFsStoreProductService {
|
|
|
|
|
|
if (attrList != null && !attrList.isEmpty()) {
|
|
|
for (FsStoreProductAttrValue attr : attrList) {
|
|
|
- FsStoreProductAttrValue updateAttr = new FsStoreProductAttrValue();
|
|
|
- updateAttr.setId(attr.getId());
|
|
|
- updateAttr.setPrice(erpProduct.getSalePrice());
|
|
|
- updateAttr.setCost(erpProduct.getCostPrice());
|
|
|
- updateAttr.setOtPrice(erpProduct.getMarketPrice());
|
|
|
- updateAttr.setImage(erpProduct.getPic());
|
|
|
- updateAttr.setWeight(erpProduct.getWeight());
|
|
|
-
|
|
|
- fsStoreProductAttrValueMapper.updateFsStoreProductAttrValue(updateAttr);
|
|
|
+ updateAttrValueByErpData(null,attr, erpProduct);
|
|
|
}
|
|
|
}
|
|
|
|