增加产品价编辑
This commit is contained in:
@@ -116,6 +116,17 @@ public interface BmsProductCountryMapper
|
|||||||
@Param("weight") BigDecimal weight,
|
@Param("weight") BigDecimal weight,
|
||||||
@Param("bizDate") Date bizDate);
|
@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 */
|
/** Count product-country rows that have a zone for this product+country+bizDate */
|
||||||
public int countZonedByProductCountry(
|
public int countZonedByProductCountry(
|
||||||
@Param("productCode") String productCode,
|
@Param("productCode") String productCode,
|
||||||
|
|||||||
@@ -71,6 +71,17 @@ public interface PrcPriceSetDetailMapper
|
|||||||
@Param("zoneCode") String zoneCode,
|
@Param("zoneCode") String zoneCode,
|
||||||
@Param("weight") BigDecimal weight);
|
@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(
|
public int countZonedByPsvProductCountry(
|
||||||
@Param("psvId") Long psvId,
|
@Param("psvId") Long psvId,
|
||||||
@Param("productCode") String productCode,
|
@Param("productCode") String productCode,
|
||||||
|
|||||||
+75
-6
@@ -520,13 +520,28 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
|||||||
else if (TYPE_DISCOUNT.equals(setType))
|
else if (TYPE_DISCOUNT.equals(setType))
|
||||||
{
|
{
|
||||||
// DISCOUNT still needs catalog as base rate; do not soft-fail as 产品价未匹配 for now.
|
// 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,
|
// catalogMissCode = Math.max(catalogMissCode,
|
||||||
// diagnoseCatalogMiss(productCode, cc, cn, zone.zoneCode, bizDate));
|
// diagnoseCatalogMiss(productCode, cc, cn, zone.zoneCode, bizDate));
|
||||||
continue;
|
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)
|
if (hit != null)
|
||||||
{
|
{
|
||||||
stampRequestMeta(request, hit);
|
stampRequestMeta(request, hit);
|
||||||
@@ -971,6 +986,21 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
|||||||
PrcPriceSetDetail detail = detailMapper.selectFixedMatch(
|
PrcPriceSetDetail detail = detailMapper.selectFixedMatch(
|
||||||
psvId, productCode,
|
psvId, productCode,
|
||||||
countryCode, countryName, zoneCode, weight);
|
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)
|
if (detail == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
@@ -979,16 +1009,55 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
TmsPriceQuoteResult r = buildFromPackageDetail(SRC_FIXED, detail, catalog, resolvedZone,
|
BmsProductCountry useCatalog = catalog;
|
||||||
productCode, productName, weight, detail.getFvValue(), null, null, detail.getFvRegistrationFee(), bizDate);
|
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);
|
fillPackage(r, bind, set);
|
||||||
stampVersion(r, version, detail.getPsdId());
|
stampVersion(r, version, detail.getPsdId());
|
||||||
r.setMatchMessage(MessageUtils.message("price.quote.hitCustomerFixedPackageDetail")
|
String verLabel = version.getVersionNo() == null ? ("psv=" + psvId) : version.getVersionNo();
|
||||||
+ " [" + (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());
|
r.setCustomerId(bind.getCustomerId());
|
||||||
return r;
|
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,
|
private TmsPriceQuoteResult tryDiscount(PrcCustomerPriceSet bind, PrcPriceSet set, PrcPriceSetVersion version,
|
||||||
BmsProductCountry base, String productCode, String productName, BigDecimal weight, Date bizDate)
|
BmsProductCountry base, String productCode, String productName, BigDecimal weight, Date bizDate)
|
||||||
{
|
{
|
||||||
|
|||||||
+4
-4
@@ -446,8 +446,7 @@ public class CatalogVersionSupport
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Catalog version that can accept preview apply / Excel attach / edit.
|
* Catalog force-edit: draft, pending, effect, and expired are writable.
|
||||||
* Same as sales force-edit: draft, pending, and effect are writable.
|
|
||||||
*/
|
*/
|
||||||
public PrcPriceSetVersion requireEditableCatalogVersion(Long psvId, String priceType)
|
public PrcPriceSetVersion requireEditableCatalogVersion(Long psvId, String priceType)
|
||||||
{
|
{
|
||||||
@@ -467,9 +466,10 @@ public class CatalogVersionSupport
|
|||||||
}
|
}
|
||||||
if (!STATUS_DRAFT.equals(ver.getStatus())
|
if (!STATUS_DRAFT.equals(ver.getStatus())
|
||||||
&& !STATUS_PENDING.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;
|
return ver;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -357,6 +357,36 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
limit 1
|
limit 1
|
||||||
</select>
|
</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 id="countZonedByProductCountry" resultType="int">
|
||||||
select count(1)
|
select count(1)
|
||||||
from prc_price_set_detail c
|
from prc_price_set_detail c
|
||||||
|
|||||||
@@ -490,6 +490,35 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
limit 1
|
limit 1
|
||||||
</select>
|
</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 id="countZonedByPsvProductCountry" resultType="int">
|
||||||
select count(1)
|
select count(1)
|
||||||
from prc_price_set_detail
|
from prc_price_set_detail
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ import {
|
|||||||
isDraftVersion,
|
isDraftVersion,
|
||||||
isPendingVersion,
|
isPendingVersion,
|
||||||
isEffectVersion,
|
isEffectVersion,
|
||||||
|
isExpiredVersion,
|
||||||
isPriceEditableVersion
|
isPriceEditableVersion
|
||||||
} from '@/views/price/set/utils/priceSet'
|
} from '@/views/price/set/utils/priceSet'
|
||||||
import { checkPermi } from '@/utils/permission'
|
import { checkPermi } from '@/utils/permission'
|
||||||
@@ -152,8 +153,8 @@ const filteredVersions = computed(() => {
|
|||||||
|
|
||||||
function showEditButton(row) {
|
function showEditButton(row) {
|
||||||
if (!checkPermi([props.editPerm])) return false
|
if (!checkPermi([props.editPerm])) return false
|
||||||
// Align with sales force-edit: draft / pending / effect can edit
|
// draft / pending / effect / expired can edit
|
||||||
return isPriceEditableVersion(row) || isEffectVersion(row)
|
return isPriceEditableVersion(row) || isEffectVersion(row) || isExpiredVersion(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isRemoving(row) {
|
function isRemoving(row) {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ import { listProduct, listProductVersions, activateProductVersion, deleteProduct
|
|||||||
|
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
|
|
||||||
const alertTitle = "按版本管理产品价(与套餐版本一致)。点击版本可查看产品与明细;待生效(含草稿)可编辑、启动或硬删;已生效可软删(上一版自动恢复生效并清空失效时间)。建价请点「新建产品价格」。"
|
const alertTitle = "按版本管理产品价(与套餐版本一致)。点击版本可查看产品与明细;待生效(含草稿)可编辑、启动或硬删;已生效、已失效可编辑;已生效可软删(上一版自动恢复生效并清空失效时间)。建价请点「新建产品价格」。"
|
||||||
const verTitle = '产品价版本'
|
const verTitle = '产品价版本'
|
||||||
const createLabel = '新建产品价格'
|
const createLabel = '新建产品价格'
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ import { listRedline, listRedlineVersions, activateRedlineVersion, deleteRedline
|
|||||||
|
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
|
|
||||||
const alertTitle = "按版本管理红线价(与套餐版本一致)。点击版本可查看产品与明细;待生效(含草稿)可编辑、启动或硬删;已生效可软删(上一版自动恢复生效并清空失效时间)。建价请点「新建红线价」。"
|
const alertTitle = "按版本管理红线价(与套餐版本一致)。点击版本可查看产品与明细;待生效(含草稿)可编辑、启动或硬删;已生效、已失效可编辑;已生效可软删(上一版自动恢复生效并清空失效时间)。建价请点「新建红线价」。"
|
||||||
const verTitle = '红线价版本'
|
const verTitle = '红线价版本'
|
||||||
const createLabel = '新建红线价'
|
const createLabel = '新建红线价'
|
||||||
|
|
||||||
|
|||||||
@@ -105,6 +105,10 @@ export function isEffectVersion(row) {
|
|||||||
return !!row && String(row.status) === VER_STATUS.EFFECT
|
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 */
|
/** Draft or pending: may continue editing price details */
|
||||||
export function isPriceEditableVersion(row) {
|
export function isPriceEditableVersion(row) {
|
||||||
return isDraftVersion(row) || isPendingVersion(row)
|
return isDraftVersion(row) || isPendingVersion(row)
|
||||||
|
|||||||
Reference in New Issue
Block a user