修改测算逻辑

This commit is contained in:
wuweihua
2026-09-18 17:09:43 +08:00
parent e08a36de91
commit bb240746a6
22 changed files with 435 additions and 44 deletions
@@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
@@ -183,7 +184,17 @@ public class PriceSetController extends BaseController
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('price:set:edit')")
/**
* 版本明细搜索下拉选项:按版本去重后的 产品/国家/分区
*/
@PreAuthorize("@ss.hasPermi('price:set:list')")
@GetMapping("/detail/options")
public AjaxResult detailOptions(@RequestParam("psvId") Long psvId)
{
return success(priceSetService.selectDetailOptions(psvId));
}
@PreAuthorize("@ss.hasPermi('price:set:edit') or @ss.hasPermi('price:set:forceEdit')")
@Log(title = "套餐明细", businessType = BusinessType.INSERT)
@PostMapping("/detail")
public AjaxResult addDetail(@RequestBody PrcPriceSetDetail detail)
@@ -191,7 +202,7 @@ public class PriceSetController extends BaseController
return toAjax(priceSetService.insertDetail(detail));
}
@PreAuthorize("@ss.hasPermi('price:set:edit')")
@PreAuthorize("@ss.hasPermi('price:set:edit') or @ss.hasPermi('price:set:forceEdit')")
@Log(title = "套餐明细", businessType = BusinessType.UPDATE)
@PutMapping("/detail")
public AjaxResult editDetail(@RequestBody PrcPriceSetDetail detail)
@@ -199,7 +210,7 @@ public class PriceSetController extends BaseController
return toAjax(priceSetService.updateDetail(detail));
}
@PreAuthorize("@ss.hasPermi('price:set:edit')")
@PreAuthorize("@ss.hasPermi('price:set:edit') or @ss.hasPermi('price:set:forceEdit')")
@Log(title = "套餐明细", businessType = BusinessType.DELETE)
@DeleteMapping("/detail/{psdIds}")
public AjaxResult removeDetail(@PathVariable Long[] psdIds)
@@ -80,6 +80,17 @@ public class ProductController extends BaseController
return toAjax(productService.updateBmsProduct(product));
}
/**
* 修改产品国家明细行(重量段/运费/挂号费/尺寸/尾程/时效/生效失效日期)
*/
@PreAuthorize("@ss.hasPermi('price:product:edit')")
@Log(title = "产品国家明细", businessType = BusinessType.UPDATE)
@PutMapping("/country")
public AjaxResult editCountry(@RequestBody BmsProductCountry country)
{
return toAjax(productService.updateBmsProductCountry(country));
}
@PreAuthorize("@ss.hasPermi('price:product:remove')")
@Log(title = "产品列表", businessType = BusinessType.DELETE)
@DeleteMapping("/{productIds}")
@@ -128,6 +128,7 @@ price.quote.requestBodyRequired=请求体为空
price.quote.customerIdRequired=客户ID为空
price.quote.customerCodeRequired=客户代码不能为空
price.quote.customerCodeNotFound=客户代码不存在
price.quote.customerDisabled=客户已停用,不可计费
price.quote.productCodeRequired=产品代码为空
price.quote.countryRequired=国家代码或国家名称为空
price.quote.weightInvalid=重量必须大于0
@@ -17,6 +17,9 @@ public interface BmsProductCountryMapper
public int insertBmsProductCountry(BmsProductCountry country);
/** 按明细行主键更新可编辑字段(重量段/运费/挂号费/尺寸/尾程/时效/生效失效日期) */
public int updateBmsProductCountry(BmsProductCountry country);
public int deleteByProductId(Long productId);
public int deleteByProductCode(String productCode);
@@ -16,6 +16,9 @@ public interface PrcPriceSetDetailMapper
public List<PrcPriceSetDetail> selectPrcPriceSetDetailList(PrcPriceSetDetail detail);
/** 版本内去重后的 产品/国家/维度组合行(用于明细搜索下拉选项) */
public List<PrcPriceSetDetail> selectDetailOptionRows(@Param("psvId") Long psvId);
public int insertPrcPriceSetDetail(PrcPriceSetDetail detail);
public int updatePrcPriceSetDetail(PrcPriceSetDetail detail);
@@ -21,6 +21,11 @@ public interface IBmsProductService
public int updateBmsProduct(BmsProduct product);
/**
* 修改产品国家明细行(重量段/运费/挂号费/尺寸/尾程/时效/生效失效日期),状态按日期重算
*/
public int updateBmsProductCountry(BmsProductCountry country);
public int deleteBmsProductByIds(Long[] productIds);
public List<BmsProductCountry> selectCountryListByProductCode(String productCode);
@@ -2,6 +2,7 @@ package com.ruoyi.price.service;
import java.util.Date;
import java.util.List;
import java.util.Map;
import com.ruoyi.price.domain.PrcCustomerPriceSet;
import com.ruoyi.price.domain.PrcPriceSet;
import com.ruoyi.price.domain.PrcPriceSetCheckItem;
@@ -55,6 +56,12 @@ public interface IPrcPriceSetService
public List<PrcPriceSetDetail> selectDetailList(PrcPriceSetDetail detail);
/**
* 版本明细搜索下拉选项:按版本去重后的 产品/国家/分区 列表。
* 返回 { products: [{code,name}], countries: [{code,name}], zones: [{code,name}] }
*/
public Map<String, Object> selectDetailOptions(Long psvId);
public int insertDetail(PrcPriceSetDetail detail);
public int updateDetail(PrcPriceSetDetail detail);
@@ -136,6 +136,22 @@ public class BmsProductServiceImpl implements IBmsProductService
return productMapper.updateBmsProduct(product);
}
@Override
public int updateBmsProductCountry(BmsProductCountry country)
{
if (country == null || country.getDetailId() == null)
{
throw new ServiceException("明细行主键缺失,无法修改");
}
int rows = countryMapper.updateBmsProductCountry(country);
if (rows > 0)
{
// 生效/失效日期可能变化,状态按日期重算
countryMapper.refreshStatusByDates();
}
return rows;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int deleteBmsProductByIds(Long[] productIds)
@@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -636,6 +637,52 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
return list;
}
@Override
public Map<String, Object> selectDetailOptions(Long psvId)
{
List<PrcPriceSetDetail> rows = detailMapper.selectDetailOptionRows(psvId);
Map<String, Map<String, String>> products = new LinkedHashMap<String, Map<String, String>>();
Map<String, Map<String, String>> countries = new LinkedHashMap<String, Map<String, String>>();
Map<String, Map<String, String>> zones = new LinkedHashMap<String, Map<String, String>>();
for (PrcPriceSetDetail d : rows)
{
if (d == null)
{
continue;
}
if (StringUtils.isNotBlank(d.getProductCode()))
{
Map<String, String> item = new LinkedHashMap<String, String>();
item.put("code", d.getProductCode());
item.put("name", StringUtils.isNotBlank(d.getProductName()) ? d.getProductName() : d.getProductCode());
products.putIfAbsent(d.getProductCode(), item);
}
String countryCode = StringUtils.isNotBlank(d.getCountryCode()) ? d.getCountryCode() : null;
String countryName = StringUtils.isNotBlank(d.getCountryName()) ? d.getCountryName() : null;
if (countryCode != null || countryName != null)
{
Map<String, String> item = new LinkedHashMap<String, String>();
item.put("code", countryCode);
item.put("name", countryName);
countries.putIfAbsent(countryCode != null ? countryCode : countryName, item);
}
String zoneCode = StringUtils.isNotBlank(d.getZoneCode()) ? d.getZoneCode() : null;
String zoneName = StringUtils.isNotBlank(d.getZoneName()) ? d.getZoneName() : null;
if (zoneCode != null || zoneName != null)
{
Map<String, String> item = new LinkedHashMap<String, String>();
item.put("code", zoneCode);
item.put("name", zoneName);
zones.putIfAbsent(zoneCode != null ? zoneCode : zoneName, item);
}
}
Map<String, Object> result = new HashMap<String, Object>();
result.put("products", new ArrayList<Map<String, String>>(products.values()));
result.put("countries", new ArrayList<Map<String, String>>(countries.values()));
result.put("zones", new ArrayList<Map<String, String>>(zones.values()));
return result;
}
/** Attach version surcharge snapshots to a page of details (for drawer list). */
private void fillDetailSurcharges(List<PrcPriceSetDetail> details)
{
@@ -354,6 +354,11 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
throw new ServiceException(MessageUtils.message("price.quote.customerCodeNotFound"));
}
BmsCustomer hit = list.get(0);
// is_enable: 0 normal, 1 disabled — stopped customers cannot quote/bill
if ("1".equals(hit.getIsEnable()))
{
throw new ServiceException(MessageUtils.message("price.quote.customerDisabled"));
}
request.setCustomerId(hit.getCustomerId());
if (StringUtils.isNotEmpty(hit.getCustomerCode()))
{
@@ -11,7 +11,7 @@ import com.ruoyi.price.service.IPrcPriceSetService;
/**
* Refresh prc_price_set_version status (draft/pending/effect/expired).
* Startup + every 5 minutes so PENDING becomes EFFECT when effective_time is reached.
* Startup + every 3 hours so PENDING becomes EFFECT when effective_time is reached.
*/
@Component
public class BmsStatusRefreshTask implements ApplicationRunner
@@ -27,7 +27,7 @@ public class BmsStatusRefreshTask implements ApplicationRunner
refresh("startup");
}
@Scheduled(cron = "0 0/5 * * * ?")
@Scheduled(cron = "0 0 0/3 * * ?")
public void scheduledRefresh()
{
refresh("scheduled");
@@ -179,6 +179,9 @@ public class BmsRegionSyncServiceImpl implements IBmsRegionSyncService
region.setCountryNameEn((String) name.get("common"));
}
// ISO代码(先取,后续用于港/澳/台中文名归一)
String cca2 = (String) country.get("cca2");
// 中文名 translations.zho.common(mledoze/countries 标准字段名为 zho)
Map<String, Object> translations = (Map<String, Object>) country.get("translations");
if (translations != null)
@@ -192,6 +195,21 @@ public class BmsRegionSyncServiceImpl implements IBmsRegionSyncService
// 注:取不到中文名时不再用英文名兜底,避免污染业务匹配。
// 若确需兜底,可改为 region.setCountryNameCn(StringUtils.EMPTY);
// 中国香港/中国澳门/中国台湾:数据源中文名为繁体「台灣」等,强制归一为规范简体名,
// 避免同步覆盖后页面显示不规范、且每次同步都被繁体名刷回。
if ("HK".equals(cca2))
{
region.setCountryNameCn("中国香港");
}
else if ("MO".equals(cca2))
{
region.setCountryNameCn("中国澳门");
}
else if ("TW".equals(cca2))
{
region.setCountryNameCn("中国台湾");
}
// ISO代码
region.setCountryCode2((String) country.get("cca2"));
region.setCountryCode3((String) country.get("cca3"));
@@ -93,6 +93,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
)
</insert>
<!-- 仅服务于明细编辑弹窗:前端每次提交全量可编辑字段,
重量上限/失效日期允许写 null(= 不封顶 / 长期),故不用 <if> 守卫 -->
<update id="updateBmsProductCountry" parameterType="BmsProductCountry">
update bms_product_country
set weight_min = #{weightMin},
weight_max = #{weightMax},
freight_price = #{freightPrice},
registration_fee = #{registrationFee},
size_limit = #{sizeLimit},
last_mile = #{lastMile},
lead_time = #{leadTime},
effective_date = #{effectiveDate},
expire_date = #{expireDate},
update_time = sysdate()
where detail_id = #{detailId}
</update>
<delete id="deleteByProductId" parameterType="Long">
delete from bms_product_country where product_id = #{productId}
</delete>
@@ -108,6 +108,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select count(1) from prc_price_set_detail where psv_id = #{psvId}
</select>
<select id="selectDetailOptionRows" resultMap="PrcPriceSetDetailResult">
select distinct product_code, product_name, country_code, country_name, zone_code, zone_name
from prc_price_set_detail
where psv_id = #{psvId}
order by product_code, country_name, zone_code
</select>
<!-- FIXED: join active products + country by product_id only (avoid OR-join row explosion) -->
<insert id="insertFixedDetailsFromLibrary">
insert ignore into prc_price_set_detail (
@@ -0,0 +1,10 @@
-- price:set:forceEdit: edit any version status (design highest privilege)
SET NAMES utf8mb4;
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2207, N'任意版本编辑', 2201, 6, '', NULL, '', '', 1, 0, 'F', '0', '0', 'price:set:forceEdit', '#', 'admin', sysdate(), N'设计最高权限:任意状态版本可编辑价格明细'
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2207 OR perms = 'price:set:forceEdit');
INSERT INTO sys_role_menu (role_id, menu_id)
SELECT 1, 2207 FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM sys_role_menu WHERE role_id = 1 AND menu_id = 2207);