diff --git a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/BillingController.java b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/BillingController.java index e36f5bfb..7be4dd32 100644 --- a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/BillingController.java +++ b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/BillingController.java @@ -111,21 +111,32 @@ public class BillingController extends BaseController @GetMapping("/bill/orderNos") public AjaxResult orderNoOptions(@RequestParam(value = "keyword", required = false) String keyword) { - return success(prcOrderBillService.listOrderNoOptions(keyword)); + return success(prcOrderBillService.listOrderNoOptions(buildBillOptionQuery(keyword))); } @PreAuthorize("@ss.hasPermi('price:billing:bill')") @GetMapping("/bill/trackingNos") public AjaxResult trackingNoOptions(@RequestParam(value = "keyword", required = false) String keyword) { - return success(prcOrderBillService.listTrackingNoOptions(keyword)); + return success(prcOrderBillService.listTrackingNoOptions(buildBillOptionQuery(keyword))); } @PreAuthorize("@ss.hasPermi('price:billing:bill')") @GetMapping("/bill/transferNos") public AjaxResult transferNoOptions(@RequestParam(value = "keyword", required = false) String keyword) { - return success(prcOrderBillService.listTransferNoOptions(keyword)); + return success(prcOrderBillService.listTransferNoOptions(buildBillOptionQuery(keyword))); + } + + /** 下拉搜索:keyword 放入 params,供 @DataScope 与 Mapper 使用 */ + private PrcOrderBill buildBillOptionQuery(String keyword) + { + PrcOrderBill query = new PrcOrderBill(); + if (StringUtils.isNotEmpty(keyword)) + { + query.getParams().put("optionKeyword", keyword.trim()); + } + return query; } @PreAuthorize("@ss.hasPermi('price:billing:bill')") diff --git a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/PriceSetController.java b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/PriceSetController.java index 173c72f0..44f2504b 100644 --- a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/PriceSetController.java +++ b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/PriceSetController.java @@ -145,6 +145,15 @@ public class PriceSetController extends BaseController return success(newPsvId); } + @PreAuthorize("@ss.hasPermi('price:set:add')") + @Log(title = "Price set version create", businessType = BusinessType.INSERT) + @PostMapping("/version/create/{priceSetId}") + public AjaxResult createVersion(@PathVariable Long priceSetId) + { + Long newPsvId = priceSetService.createVersion(priceSetId, getUsername()); + return success(newPsvId); + } + @PreAuthorize("@ss.hasPermi('price:set:edit')") @Log(title = "Price set version delete", businessType = BusinessType.DELETE) @DeleteMapping("/version/{psvId}") diff --git a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/ProductController.java b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/ProductController.java index 6cf7032f..bf2bcd4e 100644 --- a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/ProductController.java +++ b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/ProductController.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.format.annotation.DateTimeFormat; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; @@ -49,6 +50,17 @@ public class ProductController extends BaseController return getDataTable(list); } + /** + * 产品下拉选项(非分页)。 + * 供计费列表、客户绑定等场景选择产品;不做权限控制(仍需登录)。 + */ + @GetMapping("/optionselect") + public AjaxResult optionselect(BmsProduct product) + { + List list = productService.selectBmsProductList(product); + return success(list); + } + @PreAuthorize("@ss.hasPermi('price:product:import')") @GetMapping("/import/task/{taskId}") public AjaxResult getImportTask(@PathVariable String taskId) @@ -114,13 +126,15 @@ public class ProductController extends BaseController /** * Async import Weishi B2C workbook. Returns taskId; poll /import/task/{taskId}. + * effectiveDate is required: written to product / product_country; previous open rows expire at this date. */ @Log(title = "\u4ea7\u54c1\u5217\u8868", businessType = BusinessType.IMPORT) @PreAuthorize("@ss.hasPermi('price:product:import')") @PostMapping("/importData") - public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception + public AjaxResult importData(MultipartFile file, boolean updateSupport, + @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date effectiveDate) throws Exception { - String taskId = productService.submitImportProductExcelAsync(file, updateSupport, getUsername()); + String taskId = productService.submitImportProductExcelAsync(file, updateSupport, getUsername(), effectiveDate); Map payload = new HashMap(); payload.put("taskId", taskId); return success(payload); @@ -128,13 +142,16 @@ public class ProductController extends BaseController /** * Async single-country cost-sheet import. Returns taskId; poll /import/task/{taskId}. + * effectiveDate is required: written to product / product_country; previous open rows expire at this date. */ @Log(title = "\u4ea7\u54c1\u5217\u8868", businessType = BusinessType.IMPORT) @PreAuthorize("@ss.hasPermi('price:product:import')") @PostMapping("/importCountryData") - public AjaxResult importCountryData(MultipartFile file, String countryCode) throws Exception + public AjaxResult importCountryData(MultipartFile file, String countryCode, + @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date effectiveDate) throws Exception { - String taskId = productService.submitImportCountryProductExcelAsync(file, countryCode, getUsername()); + String taskId = productService.submitImportCountryProductExcelAsync(file, countryCode, getUsername(), + effectiveDate); Map payload = new HashMap(); payload.put("taskId", taskId); return success(payload); diff --git a/bms-back/bms-admin/src/main/resources/i18n/messages.properties b/bms-back/bms-admin/src/main/resources/i18n/messages.properties index 25136454..1c284c33 100644 --- a/bms-back/bms-admin/src/main/resources/i18n/messages.properties +++ b/bms-back/bms-admin/src/main/resources/i18n/messages.properties @@ -111,13 +111,14 @@ price.zone.countryCode.empty=国家编码不能为空,请检查 region.country price.product.codeDate.exists=同一产品代码与生效日期已存在,不能覆盖历史数据 price.product.effectiveDate.empty=生效日期不能为空 price.product.import.effEmpty=缺少生效日期,已跳过 +price.product.import.effRequired=请选择生效时间 price.product.import.fileEmpty=上传文件不能为空 price.product.import.fileType=仅支持 xls / xlsx 文件 price.product.import.sheetNotFound=未找到「产品目录」sheet,请上传威狮B2C小包价表格格式文件 price.product.import.noData=产品目录无有效数据行 price.product.import.regionEmpty=region 无可用国家数据,请先同步/维护国家表后再导入 price.product.import.partialFail=导入完成但存在失败项:新增 {0},跳过 {1};失败明细:{2} -price.product.import.effTooEarly=生效日期 {0} 早于当前开放版 {1},请使用更晚的生效日期导入 +price.product.import.effTooEarly=产品{0}({1})导入生效时间{2}早于该产品上一版生效时间{3},不允许导入 price.product.import.needFeeAlter=请先执行 SQL:bms-back/sql/price/product_country_fee_alter.sql(缺少运费/挂号费字段) price.product.import.needExpireAlter=请先执行 SQL:bms-back/sql/price/product_country_expire_alter.sql(缺少失效日期/版本唯一键) price.product.import.needCodeEffUnique=无法新增「同代码、不同生效日」的产品。请先执行 SQL:bms-back/sql/price/product_code_eff_unique_alter.sql(去掉 product_code 单列唯一,改为代码+生效日唯一) @@ -181,10 +182,12 @@ price.bill.fee.alreadyBilled=费用已生成账单,不可编辑或删除 price.bill.fee.idRequired=费用ID不能为空 price.set.version.effectiveTime.empty=版本生效时间不能为空 +price.set.version.effectiveTime.beforePrev=生效时间不能早于上一版本的生效时间 price.set.version.notExists=套餐版本不存在 price.set.version.activate.statusNotAllowed=仅草稿或待生效版本可设置生效时间 price.set.version.delete.statusNotAllowed=仅草稿版本可删除 price.set.version.copy.draftExists=已有草稿版本,请先启动或删除后再复制 +price.set.version.create.draftExists=已有草稿版本,请先启动或删除后再新建 price.set.save.task.notExists=保存任务不存在或已过期 price.set.library.empty=产品库无可用价格明细,请检查产品国家配置 price.set.detail.duplicate.fixed=产品{0} 国家{1} 重量段{2} {3}(共{4}条) diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/BmsProduct.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/BmsProduct.java index 4023e142..ea6c0d22 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/BmsProduct.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/BmsProduct.java @@ -23,9 +23,9 @@ public class BmsProduct extends BaseEntity private String updateNote; /** TAX_INCLUDED / TAX_EXCLUDED */ private String taxMode; - @JsonFormat(pattern = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date effectiveDate; - @JsonFormat(pattern = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date expireDate; /** 0 pending, 1 active, 2 expired */ public static final String STATUS_PENDING = "0"; diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/BmsProductCountry.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/BmsProductCountry.java index ec8e98b8..91f2982d 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/BmsProductCountry.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/BmsProductCountry.java @@ -31,10 +31,10 @@ public class BmsProductCountry implements Serializable private String sizeLimit; private String lastMile; private String leadTime; - @JsonFormat(pattern = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date effectiveDate; /** null=open; closed to next import effective_date */ - @JsonFormat(pattern = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date expireDate; /** 0 pending, 1 active, 2 expired */ private String status; diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcIncomeBillFee.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcIncomeBillFee.java index 506bb6df..3f007200 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcIncomeBillFee.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcIncomeBillFee.java @@ -20,6 +20,10 @@ public class PrcIncomeBillFee implements Serializable private String feeName; private Long scId; private BigDecimal amount; + /** 产品价(目录价,基础运费/挂号费明细对应分摊) */ + private BigDecimal productAmount; + /** 红线价(预留) */ + private BigDecimal redlineAmount; private String currency; private String roundMode; private String remark; diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcOrderBill.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcOrderBill.java index 06500635..4b4f3dad 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcOrderBill.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcOrderBill.java @@ -37,6 +37,8 @@ public class PrcOrderBill extends BaseEntity private String settlementManCode; /** 客服员 */ private String serviceMan; + /** 客服员编码 */ + private String serviceManCode; private Long customerId; private String customerCode; private String customerName; diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TmsPriceBillRequest.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TmsPriceBillRequest.java index b3bd347c..a80337d2 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TmsPriceBillRequest.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TmsPriceBillRequest.java @@ -33,6 +33,8 @@ public class TmsPriceBillRequest extends TmsPriceQuoteRequest private String settlementManCode; /** 客服员 */ private String serviceMan; + /** 客服员编码 */ + private String serviceManCode; private String customerName; private Integer pieces; private BigDecimal actualWeight; diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TmsPriceQuoteFeeLine.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TmsPriceQuoteFeeLine.java index 4fe5bd58..6da3fffb 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TmsPriceQuoteFeeLine.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TmsPriceQuoteFeeLine.java @@ -16,6 +16,10 @@ public class TmsPriceQuoteFeeLine implements Serializable /** surcharge config id, 0 for freight/registration */ private Long scId; private BigDecimal amount; + /** 产品价(目录价分摊) */ + private BigDecimal productAmount; + /** 红线价(预留) */ + private BigDecimal redlineAmount; private String currency; private String roundMode; private String remark; diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TmsPriceQuoteResult.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TmsPriceQuoteResult.java index 6ac2818d..579fe744 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TmsPriceQuoteResult.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TmsPriceQuoteResult.java @@ -91,6 +91,8 @@ public class TmsPriceQuoteResult implements Serializable private String settlementManCode; /** 客服员 */ private String serviceMan; + /** 客服员编码 */ + private String serviceManCode; private String customerCode; private String customerName; /** ACTIVE / MISSING / DISABLED */ diff --git a/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcOrderBillMapper.java b/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcOrderBillMapper.java index a3c34aa4..7c572de5 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcOrderBillMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcOrderBillMapper.java @@ -20,14 +20,14 @@ public interface PrcOrderBillMapper public List selectPrcOrderBillList(PrcOrderBill bill); - /** 订单号下拉搜索:按关键词模糊匹配,返回去重后的订单号(按最近创建排序,限量返回) */ - public List selectOrderNoOptions(@Param("keyword") String keyword, @Param("limit") int limit); + /** 订单号下拉搜索(带数据权限) */ + public List selectOrderNoOptions(@Param("query") PrcOrderBill query, @Param("limit") int limit); - /** 运单号下拉搜索:按关键词模糊匹配,返回去重后的运单号(按最近创建排序,限量返回) */ - public List selectTrackingNoOptions(@Param("keyword") String keyword, @Param("limit") int limit); + /** 运单号下拉搜索(带数据权限) */ + public List selectTrackingNoOptions(@Param("query") PrcOrderBill query, @Param("limit") int limit); - /** 转单号下拉搜索:按关键词模糊匹配,返回去重后的转单号(按最近创建排序,限量返回) */ - public List selectTransferNoOptions(@Param("keyword") String keyword, @Param("limit") int limit); + /** 转单号下拉搜索(带数据权限) */ + public List selectTransferNoOptions(@Param("query") PrcOrderBill query, @Param("limit") int limit); /** 应收账单生成读取指定客户截止日期前仍存在未出账费用的订单计费快照。 */ public List selectPrcOrderBillByCustomerPeriod(@Param("customerId") Long customerId, diff --git a/bms-back/bms-system/src/main/java/com/bms/price/oracle/OracleOrderBillMapper.java b/bms-back/bms-system/src/main/java/com/bms/price/oracle/OracleOrderBillMapper.java index 2cd89704..4d8f93ea 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/oracle/OracleOrderBillMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/oracle/OracleOrderBillMapper.java @@ -26,11 +26,12 @@ public class OracleOrderBillMapper req.setOrderNo(firstStr(row, "ORDER_ID", "ORG_ORDER_ID", "TRANSFER_ORDER_ID")); req.setTrackingNo(firstStr(row, "ORG_ORDER_ID", "TRACK_ID", "BARCODE_NUMBER", "CUSTOMER_TRACK_ID")); req.setTransferNo(firstStr(row, "TRANSFER_ORDER_ID")); - req.setBelongSaler(firstStr(row, "BELONG_SALER_OLD")); + // Oracle 人员字段为中文名;编码在落库前按 sys_user.nick_name 反查 + req.setBelongSaler(firstStr(row, "BELONG_SALER_OLD", "BELONG_SALER_NAME", "BELONG_SALER")); req.setBelongSalerCode(firstStr(row, "BELONG_SALER_CODE", "SALER_CODE")); - req.setSettlementMan(firstStr(row, "SETTLEMENT_MAN_OLD")); + req.setSettlementMan(firstStr(row, "SETTLEMENT_MAN_OLD", "SETTLEMENT_MAN_NAME", "SETTLEMENT_MAN")); req.setSettlementManCode(firstStr(row, "SETTLEMENT_MAN_CODE", "SETTLEMENT_CODE")); - req.setServiceMan(firstStr(row, "SERVICE_MAN_OLD")); + req.setServiceMan(firstStr(row, "SERVICE_MAN_OLD", "SERVICE_MAN_NAME", "SERVICE_MAN")); req.setUpstreamRow(row); req.setCustomerCode(firstStr(row, "CUSTOMER_CODE")); req.setCustomerName(firstStr(row, "CUSTOMER_NAME")); diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/IBmsProductService.java b/bms-back/bms-system/src/main/java/com/bms/price/service/IBmsProductService.java index 1aa8333f..f91e57b8 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/IBmsProductService.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/IBmsProductService.java @@ -32,24 +32,24 @@ public interface IBmsProductService public List 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> parseQuoteExcelByProduct(MultipartFile file) throws Exception; diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcOrderBillService.java b/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcOrderBillService.java index e7cfaaff..6edec522 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcOrderBillService.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcOrderBillService.java @@ -23,14 +23,14 @@ public interface IPrcOrderBillService List selectBillList(PrcOrderBill query); - /** 订单号下拉搜索选项(模糊匹配,去重限量) */ - List listOrderNoOptions(String keyword); + /** 订单号下拉搜索选项(模糊匹配,去重限量,带数据权限) */ + List listOrderNoOptions(PrcOrderBill query); - /** 运单号下拉搜索选项(模糊匹配,去重限量) */ - List listTrackingNoOptions(String keyword); + /** 运单号下拉搜索选项(模糊匹配,去重限量,带数据权限) */ + List listTrackingNoOptions(PrcOrderBill query); - /** 转单号下拉搜索选项(模糊匹配,去重限量) */ - List listTransferNoOptions(String keyword); + /** 转单号下拉搜索选项(模糊匹配,去重限量,带数据权限) */ + List listTransferNoOptions(PrcOrderBill query); TmsPriceQuoteResult getBill(String billId); diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceSetService.java b/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceSetService.java index a1482912..fca616e4 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceSetService.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceSetService.java @@ -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); diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/BmsProductServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/BmsProductServiceImpl.java index edb5b081..f3a085d5 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/BmsProductServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/BmsProductServiceImpl.java @@ -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 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 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 countries = stampSelectedCountry(block.rows, region, product.getEffectiveDate()); + List 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 regionByNameCn, List euRegions, - Map zoneByCountryAndCode, Set unmatchedCountries) + Map zoneByCountryAndCode, Set 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 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 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 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 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 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) { diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcOrderBillServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcOrderBillServiceImpl.java index 941092d2..c297b1ba 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcOrderBillServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcOrderBillServiceImpl.java @@ -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 selectBillList(PrcOrderBill query) { query.setOrderNos(normalizeCodeList(query.getOrderNos())); @@ -248,33 +264,39 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService } @Override - public List listOrderNoOptions(String keyword) + @DataScope(deptAlias = "su", deptField = "dept_id", userAlias = "su", userField = "user_id", permission = "price:billing:bill") + public List 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 listTrackingNoOptions(String keyword) + @DataScope(deptAlias = "su", deptField = "dept_id", userAlias = "su", userField = "user_id", permission = "price:billing:bill") + public List 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 listTransferNoOptions(String keyword) + @DataScope(deptAlias = "su", deptField = "dept_id", userAlias = "su", userField = "user_id", permission = "price:billing:bill") + public List 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 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()); diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceSetServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceSetServiceImpl.java index 4d91b8c1..55096802 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceSetServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceSetServiceImpl.java @@ -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 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) diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/TmsPriceQuoteServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/TmsPriceQuoteServiceImpl.java index e2b5e1c2..6accd715 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/TmsPriceQuoteServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/TmsPriceQuoteServiceImpl.java @@ -957,8 +957,12 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService r.setPayTotal(productAmount); String currency = normalizeCurrency(r.getCurrency()); List payLines = new ArrayList(); - 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 rels = loadMatchedSurcharges(result); List lines = new ArrayList(); - 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 surchargeLines = new LinkedHashMap(); @@ -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 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) { diff --git a/bms-back/bms-system/src/main/java/com/bms/price/task/BmsProductImportAsyncRunner.java b/bms-back/bms-system/src/main/java/com/bms/price/task/BmsProductImportAsyncRunner.java index c7f8dc74..c5c13ac3 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/task/BmsProductImportAsyncRunner.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/task/BmsProductImportAsyncRunner.java @@ -1,5 +1,6 @@ package com.bms.price.task; +import java.util.Date; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,12 +31,14 @@ public class BmsProductImportAsyncRunner /** Background all-country (Weishi catalog) import. */ @Async("threadPoolTaskExecutor") - public void runImportAll(String taskId, byte[] bytes, String filename, boolean updateSupport, String operName) + public void runImportAll(String taskId, byte[] bytes, String filename, boolean updateSupport, String operName, + Date effectiveDate) { try { put(taskId, BmsProductImportTask.STATUS_RUNNING, 5, "parsing excel", null); - String message = productService.importProductExcel(bytes, filename, updateSupport, operName, taskId); + String message = productService.importProductExcel(bytes, filename, updateSupport, operName, taskId, + effectiveDate); put(taskId, BmsProductImportTask.STATUS_SUCCESS, 100, message, null); log.info("async product import done, taskId={}", taskId); } @@ -48,12 +51,14 @@ public class BmsProductImportAsyncRunner /** Background single-country cost-sheet import. */ @Async("threadPoolTaskExecutor") - public void runImportCountry(String taskId, byte[] bytes, String filename, String countryCode, String operName) + public void runImportCountry(String taskId, byte[] bytes, String filename, String countryCode, String operName, + Date effectiveDate) { try { put(taskId, BmsProductImportTask.STATUS_RUNNING, 5, "parsing excel", null); - String message = productService.importCountryProductExcel(bytes, filename, countryCode, operName, taskId); + String message = productService.importCountryProductExcel(bytes, filename, countryCode, operName, taskId, + effectiveDate); put(taskId, BmsProductImportTask.STATUS_SUCCESS, 100, message, null); log.info("async product country import done, taskId={}, country={}", taskId, countryCode); } diff --git a/bms-back/bms-system/src/main/java/com/bms/system/mapper/SysUserMapper.java b/bms-back/bms-system/src/main/java/com/bms/system/mapper/SysUserMapper.java index 358028d6..045ffb8a 100644 --- a/bms-back/bms-system/src/main/java/com/bms/system/mapper/SysUserMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/system/mapper/SysUserMapper.java @@ -51,6 +51,14 @@ public interface SysUserMapper */ public SysUser selectUserByUserName(String userName); + /** + * 通过中文昵称(nick_name)精确查用户(未删除,优先启用) + * + * @param nickName 中文名称 + * @return 用户对象信息 + */ + public SysUser selectUserByNickName(String nickName); + /** * 通过用户ID查询用户 * diff --git a/bms-back/bms-system/src/main/resources/mapper/price/BmsProductCountryMapper.xml b/bms-back/bms-system/src/main/resources/mapper/price/BmsProductCountryMapper.xml index b225abf9..155c143e 100644 --- a/bms-back/bms-system/src/main/resources/mapper/price/BmsProductCountryMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/price/BmsProductCountryMapper.xml @@ -191,8 +191,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" update product_country set status = case - when expire_date is not null and expire_date <= curdate() then '2' - when effective_date is null or effective_date > curdate() then '0' + when expire_date is not null and expire_date <= now() then '2' + when effective_date is null or effective_date > now() then '0' else '1' end diff --git a/bms-back/bms-system/src/main/resources/mapper/price/BmsProductMapper.xml b/bms-back/bms-system/src/main/resources/mapper/price/BmsProductMapper.xml index 392edde0..93466b8b 100644 --- a/bms-back/bms-system/src/main/resources/mapper/price/BmsProductMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/price/BmsProductMapper.xml @@ -206,8 +206,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" update product set status = case - when expire_date is not null and expire_date <= curdate() then '2' - when effective_date is null or effective_date > curdate() then '0' + when expire_date is not null and expire_date <= now() then '2' + when effective_date is null or effective_date > now() then '0' else '1' end diff --git a/bms-back/bms-system/src/main/resources/mapper/price/PrcIncomeBillFeeMapper.xml b/bms-back/bms-system/src/main/resources/mapper/price/PrcIncomeBillFeeMapper.xml index 8ad21e01..3bee21c7 100644 --- a/bms-back/bms-system/src/main/resources/mapper/price/PrcIncomeBillFeeMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/price/PrcIncomeBillFeeMapper.xml @@ -12,6 +12,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + @@ -21,7 +23,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + + + AND EXISTS ( + SELECT 1 FROM sys_user su + WHERE su.del_flag = '0' + AND ( + (p.belong_saler_code IS NOT NULL AND p.belong_saler_code != '' + AND (su.user_name = p.belong_saler_code COLLATE utf8mb4_general_ci + OR su.user_id = p.belong_saler_code + 0)) + OR + (p.settlement_man_code IS NOT NULL AND p.settlement_man_code != '' + AND (su.user_name = p.settlement_man_code COLLATE utf8mb4_general_ci + OR su.user_id = p.settlement_man_code + 0)) + ) + ${params.dataScope} + ) + + + + + + + AND EXISTS ( + SELECT 1 FROM sys_user su + WHERE su.del_flag = '0' + AND ( + (p.belong_saler_code IS NOT NULL AND p.belong_saler_code != '' + AND (su.user_name = p.belong_saler_code COLLATE utf8mb4_general_ci + OR su.user_id = p.belong_saler_code + 0)) + OR + (p.settlement_man_code IS NOT NULL AND p.settlement_man_code != '' + AND (su.user_name = p.settlement_man_code COLLATE utf8mb4_general_ci + OR su.user_id = p.settlement_man_code + 0)) + ) + ${query.params.dataScope} + ) + + + @@ -449,7 +498,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" insert into prc_order_bill ( bill_id, bill_key, order_no, tracking_no, transfer_no, - belong_saler, belong_saler_code, settlement_man, settlement_man_code, service_man, + belong_saler, belong_saler_code, settlement_man, settlement_man_code, service_man, service_man_code, customer_id, customer_code, customer_name, pieces, actual_weight, volume, volume_weight, pkg_length, pkg_width, pkg_height, shipper_name, consignee_name, dest_postcode, warehouse_code, order_time, order_remark, @@ -463,7 +512,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" create_time ) values ( #{billId}, #{billKey}, #{orderNo}, #{trackingNo}, #{transferNo}, - #{belongSaler}, #{belongSalerCode}, #{settlementMan}, #{settlementManCode}, #{serviceMan}, + #{belongSaler}, #{belongSalerCode}, #{settlementMan}, #{settlementManCode}, #{serviceMan}, #{serviceManCode}, #{customerId}, #{customerCode}, #{customerName}, #{pieces}, #{actualWeight}, #{volume}, #{volumeWeight}, #{pkgLength}, #{pkgWidth}, #{pkgHeight}, #{shipperName}, #{consigneeName}, #{destPostcode}, #{warehouseCode}, #{orderTime}, #{orderRemark}, @@ -488,6 +537,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" settlement_man = #{settlementMan}, settlement_man_code = #{settlementManCode}, service_man = #{serviceMan}, + service_man_code = #{serviceManCode}, customer_id = #{customerId}, customer_code = #{customerCode}, customer_name = #{customerName}, diff --git a/bms-back/bms-system/src/main/resources/mapper/system/SysUserMapper.xml b/bms-back/bms-system/src/main/resources/mapper/system/SysUserMapper.xml index bc76000e..afc532e9 100644 --- a/bms-back/bms-system/src/main/resources/mapper/system/SysUserMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -137,6 +137,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where u.user_name = #{userName} and u.del_flag = '0' + +