增加产品价编辑

This commit is contained in:
wuweihua
2026-11-02 09:00:38 +08:00
parent d185995dc7
commit 9d4dbdcbe6
10 changed files with 169 additions and 14 deletions
@@ -116,6 +116,17 @@ public interface BmsProductCountryMapper
@Param("weight") BigDecimal weight,
@Param("bizDate") Date bizDate);
/**
* Lowest PRODUCT catalog weight band for product/country/zone (ignore weight).
* Used when charge weight is below the minimum band.
*/
public BmsProductCountry selectMinBandByProductCountry(
@Param("productCode") String productCode,
@Param("countryCode") String countryCode,
@Param("countryName") String countryName,
@Param("zoneCode") String zoneCode,
@Param("bizDate") Date bizDate);
/** Count product-country rows that have a zone for this product+country+bizDate */
public int countZonedByProductCountry(
@Param("productCode") String productCode,
@@ -71,6 +71,17 @@ public interface PrcPriceSetDetailMapper
@Param("zoneCode") String zoneCode,
@Param("weight") BigDecimal weight);
/**
* Lowest FIXED weight band for product/country/zone (ignore weight).
* Used when charge weight is below the minimum band.
*/
public PrcPriceSetDetail selectFixedMinBand(
@Param("psvId") Long psvId,
@Param("productCode") String productCode,
@Param("countryCode") String countryCode,
@Param("countryName") String countryName,
@Param("zoneCode") String zoneCode);
public int countZonedByPsvProductCountry(
@Param("psvId") Long psvId,
@Param("productCode") String productCode,
@@ -520,13 +520,28 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
else if (TYPE_DISCOUNT.equals(setType))
{
// DISCOUNT still needs catalog as base rate; do not soft-fail as 产品价未匹配 for now.
if (!hasProductCatalogPrice(catalog))
BmsProductCountry discCatalog = catalog;
BigDecimal discWeight = weight;
if (!hasProductCatalogPrice(discCatalog))
{
// Below min catalog band: snap charge weight to lowest band min.
BigDecimal snapped = snapWeightToCatalogMinBand(
productCode, cc, cn, zone.zoneCode, weight, bizDate);
if (snapped != null)
{
discWeight = snapped;
discCatalog = softMatchCatalog(
productCode, cc, cn, zone.zoneCode, discWeight, bizDate, zone.zone);
}
}
if (!hasProductCatalogPrice(discCatalog))
{
// catalogMissCode = Math.max(catalogMissCode,
// diagnoseCatalogMiss(productCode, cc, cn, zone.zoneCode, bizDate));
continue;
}
TmsPriceQuoteResult hit = tryDiscount(bind, set, version, catalog, productCode, productName, weight, bizDate);
TmsPriceQuoteResult hit = tryDiscount(bind, set, version, discCatalog,
productCode, productName, discWeight, bizDate);
if (hit != null)
{
stampRequestMeta(request, hit);
@@ -971,6 +986,21 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
PrcPriceSetDetail detail = detailMapper.selectFixedMatch(
psvId, productCode,
countryCode, countryName, zoneCode, weight);
BigDecimal billWeight = weight;
boolean snappedToMinBand = false;
// Miss: if charge weight is below the lowest band, bill at that band's weight_min.
if (detail == null)
{
PrcPriceSetDetail minBand = detailMapper.selectFixedMinBand(
psvId, productCode, countryCode, countryName, zoneCode);
if (minBand != null && minBand.getWeightMin() != null
&& weight.compareTo(minBand.getWeightMin()) < 0)
{
detail = minBand;
billWeight = minBand.getWeightMin().setScale(3, RoundingMode.HALF_UP);
snappedToMinBand = true;
}
}
if (detail == null)
{
return null;
@@ -979,16 +1009,55 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
{
return null;
}
TmsPriceQuoteResult r = buildFromPackageDetail(SRC_FIXED, detail, catalog, resolvedZone,
productCode, productName, weight, detail.getFvValue(), null, null, detail.getFvRegistrationFee(), bizDate);
BmsProductCountry useCatalog = catalog;
if (snappedToMinBand)
{
BmsProductCountry rematched = softMatchCatalog(
productCode, countryCode, countryName, zoneCode, billWeight, bizDate, resolvedZone);
if (hasProductCatalogPrice(rematched))
{
useCatalog = rematched;
}
}
TmsPriceQuoteResult r = buildFromPackageDetail(SRC_FIXED, detail, useCatalog, resolvedZone,
productCode, productName, billWeight, detail.getFvValue(), null, null, detail.getFvRegistrationFee(), bizDate);
fillPackage(r, bind, set);
stampVersion(r, version, detail.getPsdId());
r.setMatchMessage(MessageUtils.message("price.quote.hitCustomerFixedPackageDetail")
+ " [" + (version.getVersionNo() == null ? ("psv=" + psvId) : version.getVersionNo()) + "]");
String verLabel = version.getVersionNo() == null ? ("psv=" + psvId) : version.getVersionNo();
String msg = MessageUtils.message("price.quote.hitCustomerFixedPackageDetail") + " [" + verLabel + "]";
if (snappedToMinBand)
{
msg = msg + "; chargeWeight raised to min band " + billWeight.toPlainString();
}
r.setMatchMessage(msg);
r.setCustomerId(bind.getCustomerId());
return r;
}
/**
* When weight misses catalog bands but is below the lowest band, return that band's weight_min.
* Otherwise null (caller keeps original miss).
*/
private BigDecimal snapWeightToCatalogMinBand(String productCode, String countryCode, String countryName,
String zoneCode, BigDecimal weight, Date bizDate)
{
if (weight == null || StringUtils.isEmpty(productCode))
{
return null;
}
BmsProductCountry minBand = productCountryMapper.selectMinBandByProductCountry(
productCode, countryCode, countryName, zoneCode, bizDate);
if (minBand == null || minBand.getWeightMin() == null)
{
return null;
}
if (weight.compareTo(minBand.getWeightMin()) < 0)
{
return minBand.getWeightMin().setScale(3, RoundingMode.HALF_UP);
}
return null;
}
private TmsPriceQuoteResult tryDiscount(PrcCustomerPriceSet bind, PrcPriceSet set, PrcPriceSetVersion version,
BmsProductCountry base, String productCode, String productName, BigDecimal weight, Date bizDate)
{
@@ -446,8 +446,7 @@ public class CatalogVersionSupport
}
/**
* Catalog version that can accept preview apply / Excel attach / edit.
* Same as sales force-edit: draft, pending, and effect are writable.
* Catalog force-edit: draft, pending, effect, and expired are writable.
*/
public PrcPriceSetVersion requireEditableCatalogVersion(Long psvId, String priceType)
{
@@ -467,9 +466,10 @@ public class CatalogVersionSupport
}
if (!STATUS_DRAFT.equals(ver.getStatus())
&& !STATUS_PENDING.equals(ver.getStatus())
&& !STATUS_EFFECT.equals(ver.getStatus()))
&& !STATUS_EFFECT.equals(ver.getStatus())
&& !STATUS_EXPIRED.equals(ver.getStatus()))
{
throw new ServiceException("仅草稿、待生效或已生效版本可以编辑");
throw new ServiceException("仅草稿、待生效、已生效或已失效版本可以编辑");
}
return ver;
}
@@ -357,6 +357,36 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
limit 1
</select>
<select id="selectMinBandByProductCountry" resultMap="BmsProductCountryResult">
<include refid="selectVo"/>
where c.price_type = 'PRODUCT'
and ifnull(c.is_del, '0') = '0'
and c.product_code = #{productCode}
and c.weight_min is not null
<include refid="catalogBizWindow"/>
<choose>
<when test="countryCode != null and countryCode != ''">
and upper(c.country_code) = upper(#{countryCode})
</when>
<when test="countryName != null and countryName != ''">
and c.country_name = #{countryName}
</when>
<otherwise>
and 1 = 0
</otherwise>
</choose>
<choose>
<when test="zoneCode != null and zoneCode != ''">
and upper(ifnull(c.zone_code,'')) = upper(#{zoneCode})
</when>
<otherwise>
and (c.zone_code is null or c.zone_code = '')
</otherwise>
</choose>
order by v.effective_time desc, c.weight_min asc, c.psd_id asc
limit 1
</select>
<select id="countZonedByProductCountry" resultType="int">
select count(1)
from prc_price_set_detail c
@@ -490,6 +490,35 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
limit 1
</select>
<select id="selectFixedMinBand" resultMap="PrcPriceSetDetailResult">
<include refid="selectPrcPriceSetDetailVo"/>
where psv_id = #{psvId}
and ifnull(is_del, '0') = '0'
and product_code = #{productCode}
and weight_min is not null
<choose>
<when test="countryCode != null and countryCode != ''">
and upper(ifnull(country_code,'')) = upper(#{countryCode})
</when>
<when test="countryName != null and countryName != ''">
and country_name = #{countryName}
</when>
<otherwise>
and 1 = 0
</otherwise>
</choose>
<choose>
<when test="zoneCode != null and zoneCode != ''">
and upper(ifnull(zone_code,'')) = upper(#{zoneCode})
</when>
<otherwise>
and (zone_code is null or zone_code = '')
</otherwise>
</choose>
order by weight_min asc, psd_id asc
limit 1
</select>
<select id="countZonedByPsvProductCountry" resultType="int">
select count(1)
from prc_price_set_detail
@@ -81,6 +81,7 @@ import {
isDraftVersion,
isPendingVersion,
isEffectVersion,
isExpiredVersion,
isPriceEditableVersion
} from '@/views/price/set/utils/priceSet'
import { checkPermi } from '@/utils/permission'
@@ -152,8 +153,8 @@ const filteredVersions = computed(() => {
function showEditButton(row) {
if (!checkPermi([props.editPerm])) return false
// Align with sales force-edit: draft / pending / effect can edit
return isPriceEditableVersion(row) || isEffectVersion(row)
// draft / pending / effect / expired can edit
return isPriceEditableVersion(row) || isEffectVersion(row) || isExpiredVersion(row)
}
function isRemoving(row) {
@@ -51,7 +51,7 @@ import { listProduct, listProductVersions, activateProductVersion, deleteProduct
const { proxy } = getCurrentInstance()
const alertTitle = "按版本管理产品价(与套餐版本一致)。点击版本可查看产品与明细;待生效(含草稿)可编辑、启动或硬删;已生效可软删(上一版自动恢复生效并清空失效时间)。建价请点「新建产品价格」。"
const alertTitle = "按版本管理产品价(与套餐版本一致)。点击版本可查看产品与明细;待生效(含草稿)可编辑、启动或硬删;已生效、已失效可编辑;已生效可软删(上一版自动恢复生效并清空失效时间)。建价请点「新建产品价格」。"
const verTitle = '产品价版本'
const createLabel = '新建产品价格'
@@ -51,7 +51,7 @@ import { listRedline, listRedlineVersions, activateRedlineVersion, deleteRedline
const { proxy } = getCurrentInstance()
const alertTitle = "按版本管理红线价(与套餐版本一致)。点击版本可查看产品与明细;待生效(含草稿)可编辑、启动或硬删;已生效可软删(上一版自动恢复生效并清空失效时间)。建价请点「新建红线价」。"
const alertTitle = "按版本管理红线价(与套餐版本一致)。点击版本可查看产品与明细;待生效(含草稿)可编辑、启动或硬删;已生效、已失效可编辑;已生效可软删(上一版自动恢复生效并清空失效时间)。建价请点「新建红线价」。"
const verTitle = '红线价版本'
const createLabel = '新建红线价'
@@ -105,6 +105,10 @@ export function isEffectVersion(row) {
return !!row && String(row.status) === VER_STATUS.EFFECT
}
export function isExpiredVersion(row) {
return !!row && String(row.status) === VER_STATUS.EXPIRED
}
/** Draft or pending: may continue editing price details */
export function isPriceEditableVersion(row) {
return isDraftVersion(row) || isPendingVersion(row)