Implement product Excel file import functionality, including new service methods for handling Excel attachments. Update the ProductController to list imported Excel files by product code. Enhance BmsProduct and related entities to store references to the imported Excel files. Update front-end components to support displaying and managing Excel file attachments for products.
This commit is contained in:
+25
@@ -0,0 +1,25 @@
|
||||
package com.bms.price.service;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import com.bms.price.domain.PrcPriceExcelFile;
|
||||
|
||||
/**
|
||||
* Import quote Excel attachment service
|
||||
*/
|
||||
public interface IPrcPriceExcelFileService
|
||||
{
|
||||
public PrcPriceExcelFile selectPrcPriceExcelFileById(Long pefId);
|
||||
|
||||
/** Import Excel attachments linked to this product_code via product.pef_id */
|
||||
public List<PrcPriceExcelFile> selectByProductCode(String productCode);
|
||||
|
||||
/**
|
||||
* Persist uploaded Excel under upload/price/excel and insert metadata row.
|
||||
*
|
||||
* @param excelType PRODUCT / REDLINE / SALES
|
||||
* @return inserted row with pefId
|
||||
*/
|
||||
public PrcPriceExcelFile saveImportExcel(String excelType, Date effectiveTime, byte[] bytes,
|
||||
String filename, String operName) throws Exception;
|
||||
}
|
||||
+30
@@ -41,7 +41,9 @@ import com.bms.price.domain.PrcZone;
|
||||
import com.bms.price.mapper.BmsProductCountryMapper;
|
||||
import com.bms.price.mapper.BmsProductMapper;
|
||||
import com.bms.price.mapper.PrcZoneMapper;
|
||||
import com.bms.price.domain.PrcPriceExcelFile;
|
||||
import com.bms.price.service.IBmsProductService;
|
||||
import com.bms.price.service.IPrcPriceExcelFileService;
|
||||
import com.bms.price.service.IPrcSurchargeRelService;
|
||||
import com.bms.price.task.BmsProductImportAsyncRunner;
|
||||
import com.bms.price.util.ZoneCodeAbbrevs;
|
||||
@@ -94,6 +96,9 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
@Autowired
|
||||
private BmsProductImportAsyncRunner importAsyncRunner;
|
||||
|
||||
@Autowired
|
||||
private IPrcPriceExcelFileService priceExcelFileService;
|
||||
|
||||
@Override
|
||||
public BmsProduct selectBmsProductById(Long productId)
|
||||
{
|
||||
@@ -313,6 +318,10 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
assertImportProductsNoDupCountryWeight(workbook, products, regionByNameCn, euRegions,
|
||||
zoneByCountryAndCode);
|
||||
|
||||
PrcPriceExcelFile excelFile = priceExcelFileService.saveImportExcel(
|
||||
PrcPriceExcelFile.TYPE_PRODUCT, forcedEff, bytes, filename, operName);
|
||||
Long pefId = excelFile != null ? excelFile.getPefId() : null;
|
||||
|
||||
int successNum = 0;
|
||||
int skipNum = 0;
|
||||
int countryNum = 0;
|
||||
@@ -331,6 +340,7 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
try
|
||||
{
|
||||
product.setEffectiveDate(forcedEff);
|
||||
product.setPefId(pefId);
|
||||
int[] nums = importOneProduct(workbook, product, operName, regionByNameCn, euRegions,
|
||||
zoneByCountryAndCode, unmatchedCountries, forcedEff);
|
||||
transactionManager.commit(tx);
|
||||
@@ -431,6 +441,10 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
// Pre-check all products: reject whole import before any write if any is earlier than prev version
|
||||
assertImportProductsEffectiveNotBeforePrev(products, forcedEff);
|
||||
|
||||
PrcPriceExcelFile excelFile = priceExcelFileService.saveImportExcel(
|
||||
PrcPriceExcelFile.TYPE_PRODUCT, forcedEff, bytes, filename, operName);
|
||||
Long pefId = excelFile != null ? excelFile.getPefId() : null;
|
||||
|
||||
int successNum = 0;
|
||||
int skipNum = 0;
|
||||
int countryNum = 0;
|
||||
@@ -458,6 +472,7 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
product.setDestRegion(countryLabel);
|
||||
product.setSourceSheet(block.sheetName);
|
||||
product.setEffectiveDate(forcedEff);
|
||||
product.setPefId(pefId);
|
||||
if (StringUtils.isEmpty(product.getTaxMode()))
|
||||
{
|
||||
product.setTaxMode(resolveTaxMode(product.getProductName()));
|
||||
@@ -649,6 +664,7 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
if (existing != null)
|
||||
{
|
||||
product.setProductId(existing.getProductId());
|
||||
patchProductPefId(product, operName);
|
||||
int countryRows = saveCountries(product, countries);
|
||||
return new int[] { 0, 1, countryRows };
|
||||
}
|
||||
@@ -672,6 +688,19 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
return new int[] { 1, 0, countryRows };
|
||||
}
|
||||
|
||||
private void patchProductPefId(BmsProduct product, String operName)
|
||||
{
|
||||
if (product == null || product.getProductId() == null || product.getPefId() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
BmsProduct pefPatch = new BmsProduct();
|
||||
pefPatch.setProductId(product.getProductId());
|
||||
pefPatch.setPefId(product.getPefId());
|
||||
pefPatch.setUpdateBy(operName);
|
||||
productMapper.updateBmsProduct(pefPatch);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save country rows by effective_date.
|
||||
@@ -2159,6 +2188,7 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
if (existing != null)
|
||||
{
|
||||
product.setProductId(existing.getProductId());
|
||||
patchProductPefId(product, operName);
|
||||
int countryRows = saveCountries(product, countries);
|
||||
return new int[] { 0, 1, countryRows };
|
||||
}
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
package com.bms.price.service.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.bms.common.config.BmsConfig;
|
||||
import com.bms.common.exception.ServiceException;
|
||||
import com.bms.common.utils.DateUtils;
|
||||
import com.bms.common.utils.StringUtils;
|
||||
import com.bms.common.utils.file.FileUploadUtils;
|
||||
import com.bms.common.utils.uuid.IdUtils;
|
||||
import com.bms.price.domain.PrcPriceExcelFile;
|
||||
import com.bms.price.mapper.PrcPriceExcelFileMapper;
|
||||
import com.bms.price.service.IPrcPriceExcelFileService;
|
||||
|
||||
/**
|
||||
* Persist import Excel bytes and metadata
|
||||
*/
|
||||
@Service
|
||||
public class PrcPriceExcelFileServiceImpl implements IPrcPriceExcelFileService
|
||||
{
|
||||
private static final String SUB_DIR = "price/excel";
|
||||
|
||||
@Autowired
|
||||
private PrcPriceExcelFileMapper excelFileMapper;
|
||||
|
||||
@Override
|
||||
public PrcPriceExcelFile selectPrcPriceExcelFileById(Long pefId)
|
||||
{
|
||||
return excelFileMapper.selectPrcPriceExcelFileById(pefId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PrcPriceExcelFile> selectByProductCode(String productCode)
|
||||
{
|
||||
if (StringUtils.isEmpty(productCode))
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<PrcPriceExcelFile> list = excelFileMapper.selectByProductCode(productCode.trim());
|
||||
return list == null ? Collections.emptyList() : list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrcPriceExcelFile saveImportExcel(String excelType, Date effectiveTime, byte[] bytes,
|
||||
String filename, String operName) throws Exception
|
||||
{
|
||||
if (StringUtils.isEmpty(excelType))
|
||||
{
|
||||
throw new ServiceException("excelType required");
|
||||
}
|
||||
if (bytes == null || bytes.length == 0)
|
||||
{
|
||||
throw new ServiceException("excel empty");
|
||||
}
|
||||
if (effectiveTime == null)
|
||||
{
|
||||
effectiveTime = new Date();
|
||||
}
|
||||
String originalName = StringUtils.isNotEmpty(filename) ? filename : "import.xlsx";
|
||||
String ext = FilenameUtils.getExtension(originalName);
|
||||
if (StringUtils.isEmpty(ext))
|
||||
{
|
||||
ext = "xlsx";
|
||||
}
|
||||
ext = ext.toLowerCase(Locale.ROOT);
|
||||
|
||||
String uploadDir = BmsConfig.getUploadPath() + File.separator + SUB_DIR;
|
||||
String pathName = DateUtils.datePath() + "/" + IdUtils.fastSimpleUUID() + "." + ext;
|
||||
File dest = FileUploadUtils.getAbsoluteFile(uploadDir, pathName);
|
||||
FileOutputStream fos = null;
|
||||
try
|
||||
{
|
||||
fos = new FileOutputStream(dest);
|
||||
fos.write(bytes);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.close(fos);
|
||||
}
|
||||
String storedPath = FileUploadUtils.getPathFileName(uploadDir, pathName);
|
||||
|
||||
PrcPriceExcelFile row = new PrcPriceExcelFile();
|
||||
row.setExcelType(excelType.trim().toUpperCase(Locale.ROOT));
|
||||
row.setEffectiveTime(effectiveTime);
|
||||
row.setFileName(originalName);
|
||||
row.setFilePath(storedPath);
|
||||
row.setFileSize(Long.valueOf(bytes.length));
|
||||
row.setContentType(resolveContentType(ext));
|
||||
row.setFileExtension(ext);
|
||||
row.setCreateBy(operName);
|
||||
excelFileMapper.insertPrcPriceExcelFile(row);
|
||||
return row;
|
||||
}
|
||||
|
||||
private static String resolveContentType(String ext)
|
||||
{
|
||||
if ("xls".equals(ext))
|
||||
{
|
||||
return "application/vnd.ms-excel";
|
||||
}
|
||||
if ("xlsx".equals(ext))
|
||||
{
|
||||
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
+66
-2
@@ -22,10 +22,12 @@ import com.bms.common.exception.ServiceException;
|
||||
import com.bms.common.utils.DateUtils;
|
||||
import com.bms.common.utils.MessageUtils;
|
||||
import com.bms.common.utils.StringUtils;
|
||||
import com.bms.common.utils.SecurityUtils;
|
||||
import com.bms.common.utils.uuid.IdUtils;
|
||||
import com.bms.price.domain.BmsProduct;
|
||||
import com.bms.price.domain.BmsProductCountry;
|
||||
import com.bms.price.domain.PrcCustomerPriceSet;
|
||||
import com.bms.price.domain.PrcPriceExcelFile;
|
||||
import com.bms.price.domain.PrcPriceSet;
|
||||
import com.bms.price.domain.PrcPriceSetCheckItem;
|
||||
import com.bms.price.domain.PrcPriceSetDetail;
|
||||
@@ -46,6 +48,7 @@ import com.bms.price.mapper.PrcPriceSetVersionSurchargeMapper;
|
||||
import com.bms.price.mapper.PrcSurchargeMapper;
|
||||
import com.bms.price.mapper.PrcSurchargeRelMapper;
|
||||
import com.bms.price.service.IBmsProductService;
|
||||
import com.bms.price.service.IPrcPriceExcelFileService;
|
||||
import com.bms.price.service.IPrcPriceSetService;
|
||||
import com.bms.price.task.PrcPriceSetSaveAsyncRunner;
|
||||
|
||||
@@ -117,6 +120,9 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
@Autowired
|
||||
private PrcPriceSetSaveAsyncRunner saveAsyncRunner;
|
||||
|
||||
@Autowired
|
||||
private IPrcPriceExcelFileService priceExcelFileService;
|
||||
|
||||
@Override
|
||||
public PrcPriceSet selectPrcPriceSetById(Long priceSetId)
|
||||
{
|
||||
@@ -1071,6 +1077,18 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
{
|
||||
assertUpdateOnlyWeightBandsMatch(byProduct, detailIndex);
|
||||
}
|
||||
String operName = null;
|
||||
try
|
||||
{
|
||||
operName = SecurityUtils.getUsername();
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
operName = null;
|
||||
}
|
||||
PrcPriceExcelFile excelFile = priceExcelFileService.saveImportExcel(
|
||||
PrcPriceExcelFile.TYPE_SALES, new Date(), bytes, filename, operName);
|
||||
Long pefId = excelFile != null ? excelFile.getPefId() : null;
|
||||
|
||||
Map<String, PrcPriceSetProduct> productMap = new LinkedHashMap<String, PrcPriceSetProduct>();
|
||||
int updated = 0;
|
||||
@@ -1172,9 +1190,20 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
throw new ServiceException(MessageUtils.message("price.set.import.noDetailWritten"));
|
||||
}
|
||||
|
||||
if (pefId != null)
|
||||
{
|
||||
for (PrcPriceSetProduct sp : productMap.values())
|
||||
{
|
||||
if (sp != null)
|
||||
{
|
||||
sp.setPefId(pefId);
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
result.put("products", new ArrayList<PrcPriceSetProduct>(productMap.values()));
|
||||
result.put("details", details);
|
||||
result.put("pefId", pefId);
|
||||
if (updateOnly)
|
||||
{
|
||||
result.put("message", MessageUtils.message("price.set.import.updateSuccess",
|
||||
@@ -1291,6 +1320,12 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
{
|
||||
assertUpdateOnlyWeightBandsMatch(byProduct, detailIndex);
|
||||
}
|
||||
PrcPriceSetVersion verForFile = versionMapper.selectPrcPriceSetVersionById(psvId);
|
||||
Date excelEff = verForFile != null && verForFile.getEffectiveTime() != null
|
||||
? verForFile.getEffectiveTime() : new Date();
|
||||
PrcPriceExcelFile excelFile = priceExcelFileService.saveImportExcel(
|
||||
PrcPriceExcelFile.TYPE_SALES, excelEff, bytes, filename, operName);
|
||||
Long pefId = excelFile != null ? excelFile.getPefId() : null;
|
||||
|
||||
int updated = 0;
|
||||
int inserted = 0;
|
||||
@@ -1321,7 +1356,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
Long pspId = null;
|
||||
if (!updateOnly)
|
||||
{
|
||||
pspId = ensureSetProduct(priceSetId, psvId, productCode, productName);
|
||||
pspId = ensureSetProduct(priceSetId, psvId, productCode, productName, pefId);
|
||||
}
|
||||
for (BmsProductCountry row : e.getValue())
|
||||
{
|
||||
@@ -1385,6 +1420,11 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
{
|
||||
setProductMapper.bindDetailPspByPsvId(psvId);
|
||||
}
|
||||
if (pefId != null && (inserted > 0 || updated > 0))
|
||||
{
|
||||
List<String> codes = new ArrayList<String>(byProduct.keySet());
|
||||
setProductMapper.updatePefIdByPsvId(psvId, pefId, codes);
|
||||
}
|
||||
reportImportProgress(taskId, priceSetId, 95, "finishing");
|
||||
if (inserted == 0 && updated == 0)
|
||||
{
|
||||
@@ -2935,7 +2975,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
d.setPriceSetId(set.getPriceSetId());
|
||||
d.setPsvId(version.getPsvId());
|
||||
Long pspId = ensureSetProduct(set.getPriceSetId(), version.getPsvId(),
|
||||
d.getProductCode(), d.getProductName());
|
||||
d.getProductCode(), d.getProductName(), set.getPefId());
|
||||
if (pspId != null)
|
||||
{
|
||||
d.setPspId(pspId);
|
||||
@@ -3059,6 +3099,12 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
* Uses request-scoped cache during bulk upsert to avoid N selects on same code.
|
||||
*/
|
||||
private Long ensureSetProduct(Long priceSetId, Long psvId, String productCode, String productNameHint)
|
||||
{
|
||||
return ensureSetProduct(priceSetId, psvId, productCode, productNameHint, null);
|
||||
}
|
||||
|
||||
private Long ensureSetProduct(Long priceSetId, Long psvId, String productCode, String productNameHint,
|
||||
Long pefId)
|
||||
{
|
||||
if (psvId == null || StringUtils.isEmpty(productCode))
|
||||
{
|
||||
@@ -3069,15 +3115,32 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
Map<String, Long> cache = setProductCacheTl.get();
|
||||
if (cache != null && cache.containsKey(key))
|
||||
{
|
||||
if (pefId != null)
|
||||
{
|
||||
PrcPriceSetProduct pefPatch = new PrcPriceSetProduct();
|
||||
pefPatch.setPspId(cache.get(key));
|
||||
pefPatch.setPefId(pefId);
|
||||
setProductMapper.updatePrcPriceSetProduct(pefPatch);
|
||||
}
|
||||
return cache.get(key);
|
||||
}
|
||||
PrcPriceSetProduct existing = setProductMapper.selectByPsvIdAndCode(psvId, code);
|
||||
if (existing != null)
|
||||
{
|
||||
boolean needUpdate = false;
|
||||
if (StringUtils.isEmpty(existing.getProductName()) && StringUtils.isNotEmpty(productNameHint)
|
||||
&& !code.equals(productNameHint))
|
||||
{
|
||||
existing.setProductName(productNameHint);
|
||||
needUpdate = true;
|
||||
}
|
||||
if (pefId != null && (existing.getPefId() == null || !pefId.equals(existing.getPefId())))
|
||||
{
|
||||
existing.setPefId(pefId);
|
||||
needUpdate = true;
|
||||
}
|
||||
if (needUpdate)
|
||||
{
|
||||
setProductMapper.updatePrcPriceSetProduct(existing);
|
||||
}
|
||||
if (cache != null)
|
||||
@@ -3090,6 +3153,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
row.setPriceSetId(priceSetId);
|
||||
row.setPsvId(psvId);
|
||||
row.setProductCode(code);
|
||||
row.setPefId(pefId);
|
||||
BmsProduct lib = null;
|
||||
try
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user