Refactor billing options retrieval to include data permissions and add effective date handling for product imports
This commit is contained in:
@@ -32,24 +32,24 @@ public interface IBmsProductService
|
||||
|
||||
public List<BmsProductCountry> selectCountryListByProductCode(String productCode, Date effectiveDate, Long productId);
|
||||
|
||||
public String importProductExcel(MultipartFile file, boolean updateSupport, String operName) throws Exception;
|
||||
public String importProductExcel(MultipartFile file, boolean updateSupport, String operName, Date effectiveDate) throws Exception;
|
||||
|
||||
public String importCountryProductExcel(MultipartFile file, String countryCode, String operName) throws Exception;
|
||||
public String importCountryProductExcel(MultipartFile file, String countryCode, String operName, Date effectiveDate) throws Exception;
|
||||
|
||||
/** Submit async all-country import; returns taskId for polling getImportTask. */
|
||||
public String submitImportProductExcelAsync(MultipartFile file, boolean updateSupport, String operName) throws Exception;
|
||||
public String submitImportProductExcelAsync(MultipartFile file, boolean updateSupport, String operName, Date effectiveDate) throws Exception;
|
||||
|
||||
/** Submit async single-country import; returns taskId for polling getImportTask. */
|
||||
public String submitImportCountryProductExcelAsync(MultipartFile file, String countryCode, String operName) throws Exception;
|
||||
public String submitImportCountryProductExcelAsync(MultipartFile file, String countryCode, String operName, Date effectiveDate) throws Exception;
|
||||
|
||||
/** Poll Redis progress for product import task. */
|
||||
public BmsProductImportTask getImportTask(String taskId);
|
||||
|
||||
/** Sync import from bytes (used by async runner; taskId may be null). */
|
||||
public String importProductExcel(byte[] bytes, String filename, boolean updateSupport, String operName, String taskId) throws Exception;
|
||||
public String importProductExcel(byte[] bytes, String filename, boolean updateSupport, String operName, String taskId, Date effectiveDate) throws Exception;
|
||||
|
||||
/** Sync country import from bytes (used by async runner; taskId may be null). */
|
||||
public String importCountryProductExcel(byte[] bytes, String filename, String countryCode, String operName, String taskId) throws Exception;
|
||||
public String importCountryProductExcel(byte[] bytes, String filename, String countryCode, String operName, String taskId, Date effectiveDate) throws Exception;
|
||||
|
||||
public java.util.Map<String, List<BmsProductCountry>> parseQuoteExcelByProduct(MultipartFile file) throws Exception;
|
||||
|
||||
|
||||
@@ -23,14 +23,14 @@ public interface IPrcOrderBillService
|
||||
|
||||
List<PrcOrderBill> selectBillList(PrcOrderBill query);
|
||||
|
||||
/** 订单号下拉搜索选项(模糊匹配,去重限量) */
|
||||
List<String> listOrderNoOptions(String keyword);
|
||||
/** 订单号下拉搜索选项(模糊匹配,去重限量,带数据权限) */
|
||||
List<String> listOrderNoOptions(PrcOrderBill query);
|
||||
|
||||
/** 运单号下拉搜索选项(模糊匹配,去重限量) */
|
||||
List<String> listTrackingNoOptions(String keyword);
|
||||
/** 运单号下拉搜索选项(模糊匹配,去重限量,带数据权限) */
|
||||
List<String> listTrackingNoOptions(PrcOrderBill query);
|
||||
|
||||
/** 转单号下拉搜索选项(模糊匹配,去重限量) */
|
||||
List<String> listTransferNoOptions(String keyword);
|
||||
/** 转单号下拉搜索选项(模糊匹配,去重限量,带数据权限) */
|
||||
List<String> listTransferNoOptions(PrcOrderBill query);
|
||||
|
||||
TmsPriceQuoteResult getBill(String billId);
|
||||
|
||||
|
||||
@@ -51,6 +51,12 @@ public interface IPrcPriceSetService
|
||||
*/
|
||||
public Long copyVersion(Long sourcePsvId, String createBy);
|
||||
|
||||
/**
|
||||
* Create an empty draft version under the package (no detail copy).
|
||||
* @return new psvId
|
||||
*/
|
||||
public Long createVersion(Long priceSetId, String createBy);
|
||||
|
||||
/** Delete a draft version and its details / surcharge snapshots */
|
||||
public int deleteVersion(Long psvId, String updateBy);
|
||||
|
||||
|
||||
+156
-47
@@ -244,21 +244,25 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
|
||||
@Override
|
||||
public String importProductExcel(MultipartFile file, boolean updateSupport, String operName) throws Exception
|
||||
public String importProductExcel(MultipartFile file, boolean updateSupport, String operName, Date effectiveDate)
|
||||
throws Exception
|
||||
{
|
||||
validateImportFile(file);
|
||||
return importProductExcel(file.getBytes(), file.getOriginalFilename(), updateSupport, operName, null);
|
||||
return importProductExcel(file.getBytes(), file.getOriginalFilename(), updateSupport, operName, null,
|
||||
effectiveDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String submitImportProductExcelAsync(MultipartFile file, boolean updateSupport, String operName) throws Exception
|
||||
public String submitImportProductExcelAsync(MultipartFile file, boolean updateSupport, String operName,
|
||||
Date effectiveDate) throws Exception
|
||||
{
|
||||
validateImportFile(file);
|
||||
Date eff = requireImportEffectiveDate(effectiveDate);
|
||||
byte[] bytes = file.getBytes();
|
||||
String filename = file.getOriginalFilename();
|
||||
String taskId = IdUtils.fastSimpleUUID();
|
||||
importAsyncRunner.put(taskId, BmsProductImportTask.STATUS_PENDING, 0, "queued", null);
|
||||
importAsyncRunner.runImportAll(taskId, bytes, filename, updateSupport, operName);
|
||||
importAsyncRunner.runImportAll(taskId, bytes, filename, updateSupport, operName, eff);
|
||||
return taskId;
|
||||
}
|
||||
|
||||
@@ -273,9 +277,11 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
|
||||
@Override
|
||||
public String importProductExcel(byte[] bytes, String filename, boolean updateSupport, String operName, String taskId) throws Exception
|
||||
public String importProductExcel(byte[] bytes, String filename, boolean updateSupport, String operName,
|
||||
String taskId, Date effectiveDate) throws Exception
|
||||
{
|
||||
validateImportBytes(bytes, filename);
|
||||
Date forcedEff = requireImportEffectiveDate(effectiveDate);
|
||||
reportImportProgress(taskId, 10, "parsing excel");
|
||||
|
||||
try (InputStream is = new java.io.ByteArrayInputStream(bytes); Workbook workbook = WorkbookFactory.create(is))
|
||||
@@ -293,6 +299,8 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
products = dedupeCatalogProducts(products);
|
||||
reportImportProgress(taskId, 20, "parsing excel");
|
||||
// Pre-check all products: reject whole import before any write if any is earlier than prev version
|
||||
assertImportProductsEffectiveNotBeforePrev(products, forcedEff);
|
||||
|
||||
Map<String, BmsRegion> regionByNameCn = loadRegionByNameCn();
|
||||
if (regionByNameCn.isEmpty())
|
||||
@@ -319,8 +327,9 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
TransactionStatus tx = transactionManager.getTransaction(def);
|
||||
try
|
||||
{
|
||||
product.setEffectiveDate(forcedEff);
|
||||
int[] nums = importOneProduct(workbook, product, operName, regionByNameCn, euRegions,
|
||||
zoneByCountryAndCode, unmatchedCountries);
|
||||
zoneByCountryAndCode, unmatchedCountries, forcedEff);
|
||||
transactionManager.commit(tx);
|
||||
successNum += nums[0];
|
||||
skipNum += nums[1];
|
||||
@@ -357,32 +366,38 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
|
||||
@Override
|
||||
public String importCountryProductExcel(MultipartFile file, String countryCode, String operName) throws Exception
|
||||
public String importCountryProductExcel(MultipartFile file, String countryCode, String operName, Date effectiveDate)
|
||||
throws Exception
|
||||
{
|
||||
validateImportFile(file);
|
||||
return importCountryProductExcel(file.getBytes(), file.getOriginalFilename(), countryCode, operName, null);
|
||||
return importCountryProductExcel(file.getBytes(), file.getOriginalFilename(), countryCode, operName, null,
|
||||
effectiveDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String submitImportCountryProductExcelAsync(MultipartFile file, String countryCode, String operName) throws Exception
|
||||
public String submitImportCountryProductExcelAsync(MultipartFile file, String countryCode, String operName,
|
||||
Date effectiveDate) throws Exception
|
||||
{
|
||||
validateImportFile(file);
|
||||
if (StringUtils.isEmpty(countryCode))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.countryRequired"));
|
||||
}
|
||||
Date eff = requireImportEffectiveDate(effectiveDate);
|
||||
byte[] bytes = file.getBytes();
|
||||
String filename = file.getOriginalFilename();
|
||||
String taskId = IdUtils.fastSimpleUUID();
|
||||
importAsyncRunner.put(taskId, BmsProductImportTask.STATUS_PENDING, 0, "queued", null);
|
||||
importAsyncRunner.runImportCountry(taskId, bytes, filename, countryCode, operName);
|
||||
importAsyncRunner.runImportCountry(taskId, bytes, filename, countryCode, operName, eff);
|
||||
return taskId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String importCountryProductExcel(byte[] bytes, String filename, String countryCode, String operName, String taskId) throws Exception
|
||||
public String importCountryProductExcel(byte[] bytes, String filename, String countryCode, String operName,
|
||||
String taskId, Date effectiveDate) throws Exception
|
||||
{
|
||||
validateImportBytes(bytes, filename);
|
||||
Date forcedEff = requireImportEffectiveDate(effectiveDate);
|
||||
if (StringUtils.isEmpty(countryCode))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.countryRequired"));
|
||||
@@ -410,6 +425,8 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
products = dedupeCatalogProducts(products);
|
||||
Map<String, PriceBlock> priceBlocks = parseCountryPriceBlocks(workbook);
|
||||
reportImportProgress(taskId, 20, "parsing excel");
|
||||
// Pre-check all products: reject whole import before any write if any is earlier than prev version
|
||||
assertImportProductsEffectiveNotBeforePrev(products, forcedEff);
|
||||
|
||||
int successNum = 0;
|
||||
int skipNum = 0;
|
||||
@@ -437,11 +454,12 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
product.setDestRegion(countryLabel);
|
||||
product.setSourceSheet(block.sheetName);
|
||||
product.setEffectiveDate(forcedEff);
|
||||
if (StringUtils.isEmpty(product.getTaxMode()))
|
||||
{
|
||||
product.setTaxMode(resolveTaxMode(product.getProductName()));
|
||||
}
|
||||
List<BmsProductCountry> countries = stampSelectedCountry(block.rows, region, product.getEffectiveDate());
|
||||
List<BmsProductCountry> countries = stampSelectedCountry(block.rows, region, forcedEff);
|
||||
int[] nums = persistImportedProduct(product, countries, operName);
|
||||
transactionManager.commit(tx);
|
||||
successNum += nums[0];
|
||||
@@ -594,7 +612,7 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
/** @return int[]{added, skipped, countryRows} */
|
||||
private int[] importOneProduct(Workbook workbook, BmsProduct product, String operName,
|
||||
Map<String, BmsRegion> regionByNameCn, List<BmsRegion> euRegions,
|
||||
Map<String, PrcZone> zoneByCountryAndCode, Set<String> unmatchedCountries)
|
||||
Map<String, PrcZone> zoneByCountryAndCode, Set<String> unmatchedCountries, Date forcedEffectiveDate)
|
||||
{
|
||||
product.setSourceSheet(product.getProductName());
|
||||
product.setCreateBy(operName);
|
||||
@@ -614,13 +632,11 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.noCountry",
|
||||
productSheet.getSheetName()));
|
||||
}
|
||||
Date sheetEff = resolveImportEffectiveDate(countries);
|
||||
Date newEff = toDateOnly(sheetEff != null ? sheetEff : product.getEffectiveDate());
|
||||
product.setEffectiveDate(newEff);
|
||||
if (newEff == null)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.effEmpty"));
|
||||
}
|
||||
// UI-selected effective date wins over Excel; previous open product/country rows expire at this date
|
||||
Date newEff = requireImportEffectiveDate(forcedEffectiveDate != null ? forcedEffectiveDate
|
||||
: product.getEffectiveDate());
|
||||
applyForcedEffectiveDate(product, countries, newEff);
|
||||
assertImportEffectiveNotBeforePrev(product, newEff);
|
||||
BmsProduct existing = productMapper.selectBmsProductByCodeAndDate(
|
||||
product.getProductCode(), newEff);
|
||||
|
||||
@@ -657,7 +673,7 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
* - expire all earlier open weight bands under that country
|
||||
* - delete same-day open weight bands (unique key blocks insert if only expired)
|
||||
* - insert Excel weight bands only (no copy / merge of old bands)
|
||||
* Reject when newEff < last open effective_date.
|
||||
* Reject when newEff is earlier than the product's previous version effective time.
|
||||
*/
|
||||
private int saveCountries(BmsProduct product, List<BmsProductCountry> countries)
|
||||
{
|
||||
@@ -667,22 +683,16 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
String productCode = product.getProductCode();
|
||||
Long productId = product.getProductId();
|
||||
Date newEff = toDateOnly(resolveImportEffectiveDate(countries));
|
||||
Date newEff = normalizeToHour(product.getEffectiveDate());
|
||||
if (newEff == null)
|
||||
{
|
||||
newEff = toDateOnly(product.getEffectiveDate());
|
||||
newEff = normalizeToHour(resolveImportEffectiveDate(countries));
|
||||
}
|
||||
if (newEff == null)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.effEmpty"));
|
||||
}
|
||||
|
||||
Date lastOpenEff = toDateOnly(countryMapper.selectMaxOpenEffectiveDate(productCode));
|
||||
if (lastOpenEff != null && newEff.before(lastOpenEff))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.effTooEarly",
|
||||
formatDate(newEff), formatDate(lastOpenEff)));
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.effRequired"));
|
||||
}
|
||||
assertImportEffectiveNotBeforePrev(product, newEff);
|
||||
|
||||
Set<String> replacedCountries = new HashSet<>();
|
||||
String rowStatus = resolveStoredStatus(newEff, null);
|
||||
@@ -776,6 +786,15 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
return new SimpleDateFormat("yyyy-MM-dd").format(d);
|
||||
}
|
||||
|
||||
private String formatDateTime(Date d)
|
||||
{
|
||||
if (d == null)
|
||||
{
|
||||
return "-";
|
||||
}
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(d);
|
||||
}
|
||||
|
||||
private Date toDateOnly(Date d)
|
||||
{
|
||||
if (d == null)
|
||||
@@ -792,17 +811,35 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
}
|
||||
|
||||
/** 0 pending / 1 active / 2 expired from dates vs today */
|
||||
/** Truncate to hour precision (mm:ss = 00). */
|
||||
private Date normalizeToHour(Date d)
|
||||
{
|
||||
if (d == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
String s = new SimpleDateFormat("yyyy-MM-dd HH").format(d) + ":00:00";
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(s);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
/** 0 pending / 1 active / 2 expired from datetime vs now */
|
||||
private String resolveStoredStatus(Date effectiveDate, Date expireDate)
|
||||
{
|
||||
Date today = toDateOnly(new Date());
|
||||
Date expire = toDateOnly(expireDate);
|
||||
Date eff = toDateOnly(effectiveDate);
|
||||
if (expire != null && today != null && !expire.after(today))
|
||||
Date now = new Date();
|
||||
Date expire = expireDate;
|
||||
Date eff = effectiveDate;
|
||||
if (expire != null && !expire.after(now))
|
||||
{
|
||||
return BmsProduct.STATUS_EXPIRED;
|
||||
}
|
||||
if (eff == null || (today != null && eff.after(today)))
|
||||
if (eff == null || eff.after(now))
|
||||
{
|
||||
return BmsProduct.STATUS_PENDING;
|
||||
}
|
||||
@@ -1893,6 +1930,85 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Require import effective time (hour precision). */
|
||||
private Date requireImportEffectiveDate(Date effectiveDate)
|
||||
{
|
||||
Date d = normalizeToHour(effectiveDate);
|
||||
if (d == null)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.effRequired"));
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject import when selected effective time is earlier than the product's latest previous version.
|
||||
* Same effective time (re-import that version) is allowed.
|
||||
*/
|
||||
private void assertImportEffectiveNotBeforePrev(BmsProduct product, Date newEff)
|
||||
{
|
||||
if (product == null || StringUtils.isEmpty(product.getProductCode()) || newEff == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
BmsProduct latest = productMapper.selectBmsProductByCode(product.getProductCode());
|
||||
if (latest == null || latest.getEffectiveDate() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Date prevEff = normalizeToHour(latest.getEffectiveDate());
|
||||
if (prevEff == null || !newEff.before(prevEff))
|
||||
{
|
||||
return;
|
||||
}
|
||||
String code = product.getProductCode();
|
||||
String name = StringUtils.isNotEmpty(product.getProductName())
|
||||
? product.getProductName()
|
||||
: (StringUtils.isNotEmpty(latest.getProductName()) ? latest.getProductName() : "-");
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.effTooEarly",
|
||||
code, name, formatDateTime(newEff), formatDateTime(prevEff)));
|
||||
}
|
||||
|
||||
/** Batch pre-check: fail whole import before any DB write. */
|
||||
private void assertImportProductsEffectiveNotBeforePrev(List<BmsProduct> products, Date forcedEff)
|
||||
{
|
||||
Date newEff = requireImportEffectiveDate(forcedEff);
|
||||
if (products == null || products.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (BmsProduct product : products)
|
||||
{
|
||||
if (product == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
product.setEffectiveDate(newEff);
|
||||
assertImportEffectiveNotBeforePrev(product, newEff);
|
||||
}
|
||||
}
|
||||
|
||||
/** Stamp product + all country detail rows with the same effective date. */
|
||||
private void applyForcedEffectiveDate(BmsProduct product, List<BmsProductCountry> countries, Date newEff)
|
||||
{
|
||||
Date eff = requireImportEffectiveDate(newEff);
|
||||
if (product != null)
|
||||
{
|
||||
product.setEffectiveDate(eff);
|
||||
}
|
||||
if (countries == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (BmsProductCountry c : countries)
|
||||
{
|
||||
if (c != null)
|
||||
{
|
||||
c.setEffectiveDate(eff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return int[]{added, skipped, countryRows} */
|
||||
private int[] persistImportedProduct(BmsProduct product, List<BmsProductCountry> countries, String operName)
|
||||
{
|
||||
@@ -1902,16 +2018,9 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
{
|
||||
product.setSourceSheet(product.getProductName());
|
||||
}
|
||||
Date newEff = toDateOnly(product.getEffectiveDate());
|
||||
if (newEff == null)
|
||||
{
|
||||
newEff = toDateOnly(resolveImportEffectiveDate(countries));
|
||||
}
|
||||
product.setEffectiveDate(newEff);
|
||||
if (newEff == null)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.effEmpty"));
|
||||
}
|
||||
Date newEff = requireImportEffectiveDate(product.getEffectiveDate());
|
||||
applyForcedEffectiveDate(product, countries, newEff);
|
||||
assertImportEffectiveNotBeforePrev(product, newEff);
|
||||
BmsProduct existing = productMapper.selectBmsProductByCodeAndDate(product.getProductCode(), newEff);
|
||||
if (existing != null)
|
||||
{
|
||||
|
||||
+86
-13
@@ -13,6 +13,7 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
@@ -21,6 +22,8 @@ import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.bms.ar.enums.ArIncomeBillFeeStatus;
|
||||
import com.bms.ar.enums.ArOrderBillStatus;
|
||||
import com.bms.common.annotation.DataScope;
|
||||
import com.bms.common.core.domain.entity.SysUser;
|
||||
import com.bms.common.exception.ServiceException;
|
||||
import com.bms.common.utils.DictUtils;
|
||||
import com.bms.common.utils.MessageUtils;
|
||||
@@ -29,6 +32,7 @@ import com.bms.common.utils.StringUtils;
|
||||
import com.bms.common.utils.sign.Md5Utils;
|
||||
import com.bms.customer.customerinfo.domain.BmsCustomer;
|
||||
import com.bms.customer.customerinfo.mapper.BmsCustomerMapper;
|
||||
import com.bms.system.mapper.SysUserMapper;
|
||||
import com.bms.price.domain.PrcIncomeBill;
|
||||
import com.bms.price.domain.PrcIncomeBillFee;
|
||||
import com.bms.price.domain.PrcOrderBill;
|
||||
@@ -70,6 +74,10 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
private static final String DICT_FEE_TYPE = "bms_fee_type";
|
||||
private static final String FEE_TYPE_REFUND = "REFUND";
|
||||
|
||||
@Autowired
|
||||
@Lazy
|
||||
private IPrcOrderBillService self;
|
||||
|
||||
@Autowired
|
||||
private ITmsPriceQuoteService tmsPriceQuoteService;
|
||||
|
||||
@@ -80,6 +88,9 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
@Autowired
|
||||
private BmsCustomerMapper bmsCustomerMapper;
|
||||
|
||||
@Autowired
|
||||
private SysUserMapper sysUserMapper;
|
||||
|
||||
@Autowired
|
||||
private PrcOrderBillExtMapper orderBillExtMapper;
|
||||
|
||||
@@ -236,7 +247,12 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计费列表:按销售员/结算员字段做数据权限(仅本人/本部门等)。
|
||||
* 编码口径同客户:belong_saler_code / settlement_man_code = sys_user.user_name(工号)或 user_id。
|
||||
*/
|
||||
@Override
|
||||
@DataScope(deptAlias = "su", deptField = "dept_id", userAlias = "su", userField = "user_id", permission = "price:billing:bill")
|
||||
public List<PrcOrderBill> selectBillList(PrcOrderBill query)
|
||||
{
|
||||
query.setOrderNos(normalizeCodeList(query.getOrderNos()));
|
||||
@@ -248,33 +264,39 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listOrderNoOptions(String keyword)
|
||||
@DataScope(deptAlias = "su", deptField = "dept_id", userAlias = "su", userField = "user_id", permission = "price:billing:bill")
|
||||
public List<String> listOrderNoOptions(PrcOrderBill query)
|
||||
{
|
||||
if (StringUtils.isBlank(keyword))
|
||||
if (query == null || query.getParams() == null
|
||||
|| StringUtils.isBlank((String) query.getParams().get("optionKeyword")))
|
||||
{
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return orderBillMapper.selectOrderNoOptions(keyword.trim(), 20);
|
||||
return orderBillMapper.selectOrderNoOptions(query, 20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listTrackingNoOptions(String keyword)
|
||||
@DataScope(deptAlias = "su", deptField = "dept_id", userAlias = "su", userField = "user_id", permission = "price:billing:bill")
|
||||
public List<String> listTrackingNoOptions(PrcOrderBill query)
|
||||
{
|
||||
if (StringUtils.isBlank(keyword))
|
||||
if (query == null || query.getParams() == null
|
||||
|| StringUtils.isBlank((String) query.getParams().get("optionKeyword")))
|
||||
{
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return orderBillMapper.selectTrackingNoOptions(keyword.trim(), 20);
|
||||
return orderBillMapper.selectTrackingNoOptions(query, 20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listTransferNoOptions(String keyword)
|
||||
@DataScope(deptAlias = "su", deptField = "dept_id", userAlias = "su", userField = "user_id", permission = "price:billing:bill")
|
||||
public List<String> listTransferNoOptions(PrcOrderBill query)
|
||||
{
|
||||
if (StringUtils.isBlank(keyword))
|
||||
if (query == null || query.getParams() == null
|
||||
|| StringUtils.isBlank((String) query.getParams().get("optionKeyword")))
|
||||
{
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return orderBillMapper.selectTransferNoOptions(keyword.trim(), 20);
|
||||
return orderBillMapper.selectTransferNoOptions(query, 20);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -303,13 +325,17 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.bill.billIdRequired"));
|
||||
}
|
||||
PrcOrderBill bill = orderBillMapper.selectPrcOrderBillById(billId);
|
||||
if (bill == null)
|
||||
PrcOrderBill query = new PrcOrderBill();
|
||||
query.setBillId(billId.trim());
|
||||
// 走 selectBillList,复用销售员/结算员数据权限,避免越权查详情
|
||||
List<PrcOrderBill> list = self.selectBillList(query);
|
||||
if (list == null || list.isEmpty())
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.bill.notFound"));
|
||||
}
|
||||
return toResult(bill, incomeBillFeeMapper.selectByBillId(billId),
|
||||
payBillFeeMapper.selectByBillId(billId));
|
||||
PrcOrderBill bill = list.get(0);
|
||||
return toResult(bill, incomeBillFeeMapper.selectByBillId(bill.getBillId()),
|
||||
payBillFeeMapper.selectByBillId(bill.getBillId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -774,6 +800,45 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
return StringUtils.isEmpty(normalized) ? null : normalized.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步订单:Oracle 销售员/结算员/客服为中文名,按 sys_user.nick_name 反查。
|
||||
* 名称写 nick_name,编码写 user_name(工号,供数据权限);落到 prc_order_bill / prc_income_bill。
|
||||
*/
|
||||
private void resolveOrderStaffFromSysUser(TmsPriceBillRequest request)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SysUser saler = findUserByChineseName(request.getBelongSaler());
|
||||
if (saler != null)
|
||||
{
|
||||
request.setBelongSaler(saler.getNickName());
|
||||
request.setBelongSalerCode(saler.getUserName());
|
||||
}
|
||||
SysUser settlement = findUserByChineseName(request.getSettlementMan());
|
||||
if (settlement != null)
|
||||
{
|
||||
request.setSettlementMan(settlement.getNickName());
|
||||
request.setSettlementManCode(settlement.getUserName());
|
||||
}
|
||||
SysUser service = findUserByChineseName(request.getServiceMan());
|
||||
if (service != null)
|
||||
{
|
||||
request.setServiceMan(service.getNickName());
|
||||
request.setServiceManCode(service.getUserName());
|
||||
}
|
||||
}
|
||||
|
||||
private SysUser findUserByChineseName(String chineseName)
|
||||
{
|
||||
if (StringUtils.isBlank(chineseName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return sysUserMapper.selectUserByNickName(chineseName.trim());
|
||||
}
|
||||
|
||||
private void persistBill(TmsPriceBillRequest request, BigDecimal weight, Date bizDate,
|
||||
TmsPriceQuoteResult result)
|
||||
{
|
||||
@@ -804,11 +869,14 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
bill.setCustomerName(request.getCustomerName());
|
||||
bill.setTrackingNo(request.getTrackingNo());
|
||||
bill.setTransferNo(request.getTransferNo());
|
||||
// Oracle 中文人员名 -> sys_user.nick_name,*_code 写 user_name(数据权限)
|
||||
resolveOrderStaffFromSysUser(request);
|
||||
bill.setBelongSaler(request.getBelongSaler());
|
||||
bill.setBelongSalerCode(request.getBelongSalerCode());
|
||||
bill.setSettlementMan(request.getSettlementMan());
|
||||
bill.setSettlementManCode(request.getSettlementManCode());
|
||||
bill.setServiceMan(request.getServiceMan());
|
||||
bill.setServiceManCode(request.getServiceManCode());
|
||||
String customerActiveStatus = result == null ? null : result.getCustomerActiveStatus();
|
||||
if (StringUtils.isEmpty(customerActiveStatus))
|
||||
{
|
||||
@@ -1109,6 +1177,8 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
fee.setFeeName(line.getFeeName());
|
||||
fee.setScId(line.getScId() == null ? 0L : line.getScId());
|
||||
fee.setAmount(line.getAmount() == null ? BigDecimal.ZERO : line.getAmount());
|
||||
fee.setProductAmount(line.getProductAmount());
|
||||
fee.setRedlineAmount(line.getRedlineAmount());
|
||||
fee.setCurrency(line.getCurrency());
|
||||
fee.setRoundMode(line.getRoundMode());
|
||||
fee.setRemark(line.getRemark());
|
||||
@@ -1301,6 +1371,8 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
line.setFeeName(fee.getFeeName());
|
||||
line.setScId(fee.getScId());
|
||||
line.setAmount(fee.getAmount());
|
||||
line.setProductAmount(fee.getProductAmount());
|
||||
line.setRedlineAmount(fee.getRedlineAmount());
|
||||
line.setCurrency(fee.getCurrency());
|
||||
line.setRoundMode(fee.getRoundMode());
|
||||
line.setRemark(fee.getRemark());
|
||||
@@ -1342,6 +1414,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService
|
||||
r.setSettlementMan(bill.getSettlementMan());
|
||||
r.setSettlementManCode(bill.getSettlementManCode());
|
||||
r.setServiceMan(bill.getServiceMan());
|
||||
r.setServiceManCode(bill.getServiceManCode());
|
||||
r.setCustomerName(bill.getCustomerName());
|
||||
r.setCustomerActiveStatus(bill.getCustomerActiveStatus());
|
||||
r.setCreditArrearsStatus(bill.getCreditArrearsStatus());
|
||||
|
||||
+73
@@ -374,6 +374,11 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.set.edit.stopped"));
|
||||
}
|
||||
Date prevEffective = findPrevVersionEffectiveTime(version);
|
||||
if (prevEffective != null && effectiveTime.before(prevEffective))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.set.version.effectiveTime.beforePrev"));
|
||||
}
|
||||
// Set schedule; refreshVersionStatus decides PENDING(3) vs EFFECT(1) and chains expire_time
|
||||
version.setEffectiveTime(effectiveTime);
|
||||
version.setExpireTime(null);
|
||||
@@ -383,6 +388,45 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Previous version (lower version_seq) effective_time; null if none. */
|
||||
private Date findPrevVersionEffectiveTime(PrcPriceSetVersion version)
|
||||
{
|
||||
if (version == null || version.getPriceSetId() == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
int curSeq = version.getVersionSeq() == null ? 0 : version.getVersionSeq().intValue();
|
||||
PrcPriceSetVersion q = new PrcPriceSetVersion();
|
||||
q.setPriceSetId(version.getPriceSetId());
|
||||
List<PrcPriceSetVersion> list = versionMapper.selectPrcPriceSetVersionList(q);
|
||||
if (list == null || list.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
PrcPriceSetVersion prev = null;
|
||||
for (PrcPriceSetVersion v : list)
|
||||
{
|
||||
if (v == null || v.getEffectiveTime() == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (version.getPsvId() != null && version.getPsvId().equals(v.getPsvId()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int vs = v.getVersionSeq() == null ? 0 : v.getVersionSeq().intValue();
|
||||
if (vs >= curSeq)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (prev == null || vs > (prev.getVersionSeq() == null ? 0 : prev.getVersionSeq().intValue()))
|
||||
{
|
||||
prev = v;
|
||||
}
|
||||
}
|
||||
return prev == null ? null : prev.getEffectiveTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Long copyVersion(Long sourcePsvId, String createBy)
|
||||
@@ -430,6 +474,35 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
return nv.getPsvId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Long createVersion(Long priceSetId, String createBy)
|
||||
{
|
||||
PrcPriceSet set = requireSet(priceSetId);
|
||||
if (STATUS_STOP.equals(set.getStatus()))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.set.edit.stopped"));
|
||||
}
|
||||
if (hasDraftVersion(set.getPriceSetId()))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.set.version.create.draftExists"));
|
||||
}
|
||||
Integer maxSeq = versionMapper.selectMaxVersionSeq(set.getPriceSetId());
|
||||
int seq = maxSeq == null ? 1 : maxSeq.intValue() + 1;
|
||||
PrcPriceSetVersion nv = new PrcPriceSetVersion();
|
||||
nv.setPriceSetId(set.getPriceSetId());
|
||||
nv.setVersionSeq(Integer.valueOf(seq));
|
||||
nv.setVersionNo("V" + seq);
|
||||
nv.setStatus(VER_DRAFT);
|
||||
nv.setEffectiveTime(null);
|
||||
nv.setExpireTime(null);
|
||||
nv.setPriceBuildMode(null);
|
||||
nv.setCreateBy(createBy);
|
||||
versionMapper.insertPrcPriceSetVersion(nv);
|
||||
refreshVersionStatus(set.getPriceSetId());
|
||||
return nv.getPsvId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int deleteVersion(Long psvId, String updateBy)
|
||||
|
||||
+31
-4
@@ -957,8 +957,12 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
r.setPayTotal(productAmount);
|
||||
String currency = normalizeCurrency(r.getCurrency());
|
||||
List<TmsPriceQuoteFeeLine> payLines = new ArrayList<TmsPriceQuoteFeeLine>();
|
||||
payLines.add(feeLine(FEE_BASIC, feeNameOf(FEE_BASIC), 0L, productFreight, currency, roundMode, null));
|
||||
payLines.add(feeLine(FEE_REG, feeNameOf(FEE_REG), 0L, baseReg, currency, roundMode, null));
|
||||
TmsPriceQuoteFeeLine payFreight = feeLine(FEE_BASIC, feeNameOf(FEE_BASIC), 0L, productFreight, currency, roundMode, null);
|
||||
payFreight.setProductAmount(productFreight);
|
||||
payLines.add(payFreight);
|
||||
TmsPriceQuoteFeeLine payReg = feeLine(FEE_REG, feeNameOf(FEE_REG), 0L, baseReg.setScale(2, rm), currency, roundMode, null);
|
||||
payReg.setProductAmount(baseReg.setScale(2, rm));
|
||||
payLines.add(payReg);
|
||||
r.setPayFeeDetails(payLines);
|
||||
}
|
||||
|
||||
@@ -971,8 +975,14 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
|
||||
List<PrcSurchargeRel> rels = loadMatchedSurcharges(result);
|
||||
List<TmsPriceQuoteFeeLine> lines = new ArrayList<TmsPriceQuoteFeeLine>();
|
||||
lines.add(feeLine(FEE_BASIC, feeNameOf(FEE_BASIC), 0L, freightAmount, currency, result.getRoundMode(), null));
|
||||
lines.add(feeLine(FEE_REG, feeNameOf(FEE_REG), 0L, registrationFee, currency, result.getRoundMode(), null));
|
||||
BigDecimal productFreight = productAmountOf(result.getPayFeeDetails(), FEE_BASIC);
|
||||
BigDecimal productReg = productAmountOf(result.getPayFeeDetails(), FEE_REG);
|
||||
TmsPriceQuoteFeeLine basicLine = feeLine(FEE_BASIC, feeNameOf(FEE_BASIC), 0L, freightAmount, currency, result.getRoundMode(), null);
|
||||
basicLine.setProductAmount(productFreight);
|
||||
lines.add(basicLine);
|
||||
TmsPriceQuoteFeeLine regLine = feeLine(FEE_REG, feeNameOf(FEE_REG), 0L, registrationFee, currency, result.getRoundMode(), null);
|
||||
regLine.setProductAmount(productReg);
|
||||
lines.add(regLine);
|
||||
|
||||
BigDecimal surchargeTotal = BigDecimal.ZERO;
|
||||
Map<Long, TmsPriceQuoteFeeLine> surchargeLines = new LinkedHashMap<Long, TmsPriceQuoteFeeLine>();
|
||||
@@ -1382,6 +1392,23 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
return Md5Utils.hash(raw);
|
||||
}
|
||||
|
||||
/** Read catalog product amount for a fee type from payFeeDetails. */
|
||||
private static BigDecimal productAmountOf(List<TmsPriceQuoteFeeLine> payLines, String feeType)
|
||||
{
|
||||
if (payLines == null || feeType == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
for (TmsPriceQuoteFeeLine line : payLines)
|
||||
{
|
||||
if (line != null && feeType.equals(line.getFeeType()))
|
||||
{
|
||||
return line.getProductAmount() != null ? line.getProductAmount() : line.getAmount();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static TmsPriceQuoteFeeLine feeLine(String feeType, String feeName, Long scId, BigDecimal amount,
|
||||
String currency, String roundMode, String remark)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user