修改分区功能

This commit is contained in:
wuweihua
2026-09-15 16:55:11 +08:00
parent 7679a7d091
commit ccf85ebefc
17 changed files with 394 additions and 18 deletions
@@ -53,7 +53,8 @@ public class TmsPriceController extends BaseController
private IBillSearchStore billSearchStore;
/**
* Quote by customerId + productCode + country + weight.
* Quote by customer + product + country + weight (+ destPostcode when country has zones).
* Zone resolve: destPostcode -> prc_zone_detail/prc_zone -> bms_product_country.zone_code.
* Match: customer package FIXED > DISCOUNT > product default.
*/
@PostMapping("/quote")
@@ -117,6 +117,9 @@ price.product.import.noCountry=产品明细sheet无有效国家/重量段数据
price.product.import.euEmpty=国家表无欧盟成员(is_eu=1),无法展开「欧盟」
price.product.import.success.unmatched=未匹配国家表(country_code 为空):{0}
# 报价试算 TmsPriceQuote(对外 TMS API 错误码,保持英文契约)
price.quote.postcodeRequired=该国家/产品有分区,请填写目的邮编
price.quote.postcodeZoneNotFound=邮编未匹配到分区,请核对目的邮编
price.quote.zonePriceNotHit=已匹配分区,但该分区无对应产品重量段价格
price.quote.priceNotHit=没有产品/国家/重量段绑定,暂无价格
price.quote.freightMissing1=产品默认运费为空
price.quote.freightMissing2=产品默认运费或挂号费为空
@@ -22,6 +22,7 @@ public class PrcQuote extends BaseEntity
private String productName;
private String countryCode;
private String countryName;
private String destPostcode;
private BigDecimal weight;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date bizDate;
@@ -30,7 +30,6 @@ public class TmsPriceBillRequest extends TmsPriceQuoteRequest
private BigDecimal pkgHeight;
private String shipperName;
private String consigneeName;
private String destPostcode;
private String warehouseCode;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date orderTime;
@@ -19,11 +19,14 @@ public class TmsPriceQuoteRequest implements Serializable
@NotBlank(message = "productCode is required")
private String productCode;
/** ISO2;与 countryName 二选一 */
/** ISO2; countryName alternative */
private String countryCode;
/** 国家中文名;与 countryCode 二选一 */
/** country display name; countryCode alternative */
private String countryName;
/** Dest postcode; required when product-country has zones */
private String destPostcode;
@NotNull(message = "weight is required")
private BigDecimal weight;
@@ -30,6 +30,9 @@ public class TmsPriceQuoteResult implements Serializable
private String productName;
private String countryCode;
private String countryName;
private Long zoneId;
private String zoneCode;
private String zoneName;
private Long productCountryId;
private BigDecimal weightMin;
private BigDecimal weightMax;
@@ -42,13 +42,22 @@ public interface BmsProductCountryMapper
@Param("effectiveDate") Date effectiveDate);
/**
* Match by product + country + weight + bizDate.
* effective_date <= bizDate and (expire_date is null or expire_date > bizDate).
* Match by product + country + weight + bizDate (+ optional zoneCode).
* When zoneCode is empty, prefer rows without zone.
* When zoneCode is set, require matching zone_code.
*/
public BmsProductCountry selectMatchByProductCountryWeight(
@Param("productCode") String productCode,
@Param("countryCode") String countryCode,
@Param("countryName") String countryName,
@Param("zoneCode") String zoneCode,
@Param("weight") BigDecimal weight,
@Param("bizDate") Date bizDate);
/** Count product-country rows that have a zone for this product+country+bizDate */
public int countZonedByProductCountry(
@Param("productCode") String productCode,
@Param("countryCode") String countryCode,
@Param("countryName") String countryName,
@Param("bizDate") Date bizDate);
}
@@ -2,6 +2,7 @@ package com.ruoyi.price.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.ruoyi.price.domain.PrcZone;
import com.ruoyi.price.domain.PrcZoneDetail;
public interface PrcZoneDetailMapper
@@ -25,4 +26,11 @@ public interface PrcZoneDetailMapper
public int deletePrcZoneDetailByZoneId(Long zoneId);
public int deletePrcZoneDetailByRegionId(Long regionId);
/**
* Resolve zone by country ISO2 + postcode (exact first, then longest prefix).
*/
public PrcZone selectZoneByCountryPostcode(
@Param("countryCode") String countryCode,
@Param("postcode") String postcode);
}
@@ -28,6 +28,8 @@ import com.ruoyi.price.domain.PrcPriceSetDetail;
import com.ruoyi.price.domain.PrcQuote;
import com.ruoyi.price.domain.PrcQuoteFee;
import com.ruoyi.price.domain.PrcSurchargeRel;
import com.ruoyi.price.domain.PrcZone;
import com.ruoyi.price.mapper.PrcZoneDetailMapper;
import com.ruoyi.price.domain.vo.TmsPriceQuoteFeeLine;
import com.ruoyi.price.domain.vo.TmsPriceQuoteRequest;
import com.ruoyi.price.domain.vo.TmsPriceQuoteResult;
@@ -87,6 +89,9 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
@Autowired
private PrcQuoteFeeMapper quoteFeeMapper;
@Autowired
private PrcZoneDetailMapper zoneDetailMapper;
@Autowired
private IBillSearchStore billSearchStore;
@@ -178,11 +183,55 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
}
BigDecimal weight = request.getWeight();
String destPostcode = emptyToNull(request.getDestPostcode());
String zoneCode = null;
PrcZone resolvedZone = null;
int zonedCount = productCountryMapper.countZonedByProductCountry(
productCode, countryCode, countryName, bizDate);
if (zonedCount > 0)
{
if (StringUtils.isEmpty(destPostcode))
{
throw new ServiceException(MessageUtils.message("price.quote.postcodeRequired"));
}
String iso2 = resolveCountryIso2(productCode, countryCode, countryName);
if (StringUtils.isEmpty(iso2))
{
throw new ServiceException(MessageUtils.message("price.quote.countryRequired"));
}
resolvedZone = zoneDetailMapper.selectZoneByCountryPostcode(iso2, normalizePostcode(destPostcode));
if (resolvedZone == null || StringUtils.isEmpty(resolvedZone.getZoneCode()))
{
throw new ServiceException(MessageUtils.message("price.quote.postcodeZoneNotFound"));
}
zoneCode = resolvedZone.getZoneCode();
if (countryCode == null)
{
countryCode = iso2;
}
}
BmsProductCountry base = productCountryMapper.selectMatchByProductCountryWeight(
productCode, countryCode, countryName, weight, bizDate);
productCode, countryCode, countryName, zoneCode, weight, bizDate);
if (base == null)
{
throw new ServiceException(MessageUtils.message("price.quote.priceNotHit"));
throw new ServiceException(MessageUtils.message(
zonedCount > 0 ? "price.quote.zonePriceNotHit" : "price.quote.priceNotHit"));
}
if (resolvedZone != null)
{
if (base.getZoneId() == null)
{
base.setZoneId(resolvedZone.getZoneId());
}
if (StringUtils.isEmpty(base.getZoneCode()))
{
base.setZoneCode(resolvedZone.getZoneCode());
}
if (StringUtils.isEmpty(base.getZoneName()))
{
base.setZoneName(resolvedZone.getZoneName());
}
}
String productName = resolveProductName(productCode, bizDate);
@@ -213,6 +262,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
TmsPriceQuoteResult hit = tryFixed(bind, set, base, productCode, productName, weight);
if (hit != null)
{
stampRequestMeta(request, hit);
return hit;
}
}
@@ -221,14 +271,67 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
TmsPriceQuoteResult hit = tryDiscount(bind, set, base, productCode, productName, weight);
if (hit != null)
{
stampRequestMeta(request, hit);
return hit;
}
}
}
}
return buildDefault(request.getCustomerId(), base, productCode, productName, weight,
TmsPriceQuoteResult fallback = buildDefault(request.getCustomerId(), base, productCode, productName, weight,
MessageUtils.message("price.quote.noCustomerPackageOverride"));
stampRequestMeta(request, fallback);
return fallback;
}
private void stampRequestMeta(TmsPriceQuoteRequest request, TmsPriceQuoteResult result)
{
if (result == null || request == null)
{
return;
}
if (StringUtils.isEmpty(result.getDestPostcode()))
{
result.setDestPostcode(emptyToNull(request.getDestPostcode()));
}
}
private String resolveCountryIso2(String productCode, String countryCode, String countryName)
{
if (StringUtils.isNotEmpty(countryCode))
{
return countryCode.toUpperCase();
}
BmsProductCountry query = new BmsProductCountry();
query.setProductCode(productCode);
query.setCountryName(countryName);
List<BmsProductCountry> rows = productCountryMapper.selectBmsProductCountryList(query);
if (rows == null)
{
return null;
}
for (BmsProductCountry row : rows)
{
if (StringUtils.isNotEmpty(row.getCountryCode()))
{
return row.getCountryCode().toUpperCase();
}
}
return null;
}
private static String normalizePostcode(String postcode)
{
if (StringUtils.isEmpty(postcode))
{
return postcode;
}
String n = postcode.trim().replace(" ", "");
if (n.endsWith(".0") && n.matches("\\d+\\.0"))
{
return n.substring(0, n.length() - 2);
}
return n;
}
private TmsPriceQuoteResult tryFixed(PrcCustomerPriceSet bind, PrcPriceSet set,
@@ -359,6 +462,9 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
r.setProductName(productName);
r.setCountryCode(base.getCountryCode());
r.setCountryName(base.getCountryName());
r.setZoneId(base.getZoneId());
r.setZoneCode(base.getZoneCode());
r.setZoneName(base.getZoneName());
r.setProductCountryId(base.getDetailId());
r.setWeightMin(base.getWeightMin());
r.setWeightMax(base.getWeightMax());
@@ -506,6 +612,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
quote.setProductName(result.getProductName());
quote.setCountryCode(result.getCountryCode());
quote.setCountryName(result.getCountryName());
quote.setDestPostcode(result.getDestPostcode());
quote.setWeight(weight);
quote.setBizDate(bizDate);
quote.setTmsId(request.getTmsId() == null ? null : Long.valueOf(request.getTmsId()));
@@ -637,6 +744,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
r.setProductName(quote.getProductName());
r.setCountryCode(quote.getCountryCode());
r.setCountryName(quote.getCountryName());
r.setDestPostcode(quote.getDestPostcode());
r.setProductCountryId(quote.getProductCountryId());
r.setWeightMin(quote.getWeightMin());
r.setWeightMax(quote.getWeightMax());
@@ -683,6 +791,10 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
to.setProductName(from.getProductName());
to.setCountryCode(from.getCountryCode());
to.setCountryName(from.getCountryName());
to.setDestPostcode(from.getDestPostcode());
to.setZoneId(from.getZoneId());
to.setZoneCode(from.getZoneCode());
to.setZoneName(from.getZoneName());
to.setProductCountryId(from.getProductCountryId());
to.setWeightMin(from.getWeightMin());
to.setWeightMax(from.getWeightMax());
@@ -716,6 +828,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
+ request.getProductCode().trim() + "|"
+ nvlStr(countryCode) + "|"
+ nvlStr(countryName) + "|"
+ nvlStr(emptyToNull(request.getDestPostcode())) + "|"
+ weight.toPlainString() + "|"
+ biz + "|"
+ (request.getTmsId() == null ? "" : request.getTmsId());
@@ -167,6 +167,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
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>
<if test="bizDate != null">
and (effective_date is null or effective_date &lt;= #{bizDate})
and (expire_date is null or expire_date &gt; #{bizDate})
@@ -174,10 +182,33 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="bizDate == null">
and expire_date is null
</if>
order by
case when zone_code is null or zone_code = '' then 0 else 1 end,
effective_date desc, weight_min asc, detail_id asc
order by effective_date desc, weight_min asc, detail_id asc
limit 1
</select>
<select id="countZonedByProductCountry" resultType="int">
select count(1)
from bms_product_country
where product_code = #{productCode}
and zone_code is not null and zone_code &lt;&gt; ''
<choose>
<when test="countryCode != null and countryCode != ''">
and upper(country_code) = upper(#{countryCode})
</when>
<when test="countryName != null and countryName != ''">
and country_name = #{countryName}
</when>
<otherwise>
and 1 = 0
</otherwise>
</choose>
<if test="bizDate != null">
and (effective_date is null or effective_date &lt;= #{bizDate})
and (expire_date is null or expire_date &gt; #{bizDate})
</if>
<if test="bizDate == null">
and expire_date is null
</if>
</select>
</mapper>
@@ -28,7 +28,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="productCode" column="product_code" />
<result property="productName" column="product_name" />
<result property="countryCode" column="country_code" />
<result property="countryName" column="country_name" />
<result property="countryName" column="country_name" />
<result property="weight" column="weight" />
<result property="bizDate" column="biz_date" />
<result property="tmsId" column="tms_id" />
@@ -172,7 +172,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
product_code = #{productCode},
product_name = #{productName},
country_code = #{countryCode},
country_name = #{countryName},
country_name = #{countryName},
weight = #{weight},
@@ -12,6 +12,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="productName" column="product_name" />
<result property="countryCode" column="country_code" />
<result property="countryName" column="country_name" />
<result property="destPostcode" column="dest_postcode" />
<result property="weight" column="weight" />
<result property="bizDate" column="biz_date" />
<result property="tmsId" column="tms_id" />
@@ -46,7 +47,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<sql id="selectPrcQuoteVo">
select quote_id, quote_key, customer_id, product_code, product_name,
country_code, country_name, weight, biz_date, tms_id,
country_code, country_name, dest_postcode, weight, biz_date, tms_id,
match_source, match_message, price_set_id, price_set_code, price_set_name,
set_type, bind_priority, customer_priceset_id, product_country_id,
weight_min, weight_max, weight_label, effective_date, charge_weight,
@@ -103,7 +104,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<insert id="insertPrcQuote" parameterType="PrcQuote">
insert into prc_quote (
quote_id, quote_key, customer_id, product_code, product_name,
country_code, country_name, weight, biz_date, tms_id,
country_code, country_name, dest_postcode, weight, biz_date, tms_id,
match_source, match_message, price_set_id, price_set_code, price_set_name,
set_type, bind_priority, customer_priceset_id, product_country_id,
weight_min, weight_max, weight_label, effective_date, charge_weight,
@@ -112,7 +113,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
create_time
) values (
#{quoteId}, #{quoteKey}, #{customerId}, #{productCode}, #{productName},
#{countryCode}, #{countryName}, #{weight}, #{bizDate}, #{tmsId},
#{countryCode}, #{countryName}, #{destPostcode}, #{weight}, #{bizDate}, #{tmsId},
#{matchSource}, #{matchMessage}, #{priceSetId}, #{priceSetCode}, #{priceSetName},
#{setType}, #{bindPriority}, #{customerPricesetId}, #{productCountryId},
#{weightMin}, #{weightMax}, #{weightLabel}, #{effectiveDate}, #{chargeWeight},
@@ -91,4 +91,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where z.region_id = #{regionId}
</delete>
<select id="selectZoneByCountryPostcode" resultType="com.ruoyi.price.domain.PrcZone">
select z.zone_id as zoneId,
z.region_id as regionId,
z.country_code as countryCode,
z.zone_code as zoneCode,
z.zone_name as zoneName,
z.zone_sort as zoneSort,
z.remark as remark,
z.create_time as createTime,
z.update_time as updateTime
from prc_zone_detail d
inner join prc_zone z on z.zone_id = d.zone_id
where upper(ifnull(z.country_code,'')) = upper(#{countryCode})
and (
replace(upper(ifnull(d.postcode,'')), ' ', '') = replace(upper(#{postcode}), ' ', '')
or replace(upper(#{postcode}), ' ', '') like concat(replace(upper(ifnull(d.postcode,'')), ' ', ''), '%')
)
order by
case when replace(upper(ifnull(d.postcode,'')), ' ', '') = replace(upper(#{postcode}), ' ', '') then 0 else 1 end,
char_length(replace(ifnull(d.postcode,''), ' ', '')) desc,
d.detail_id asc
limit 1
</select>
</mapper>
@@ -0,0 +1,22 @@
# Billing quote / order sync: postcode -> zone
## Rule
- Whether a country needs a zone is decided by `bms_product_country` (rows with `zone_code`).
- If the product+country has zones: request **must** include `destPostcode`.
- Zone is resolved at runtime: `destPostcode` -> `prc_zone_detail` + `prc_zone` -> `zone_code`, then match `bms_product_country`.
- Billing tables store **postcode only**, not zone columns:
- `prc_quote.dest_postcode`
- `prc_order_bill.dest_postcode` (already existed)
## SQL
Run: `bms-back/sql/price/billing_postcode_alter.sql`
## API fields
- Request: `destPostcode` on `/api/tms/price/quote` and `/api/tms/price/bill` (and console `/price/billing/quote`).
- Response may include `zoneId` / `zoneCode` / `zoneName` for display only (not persisted on bill/quote tables).
## Errors (i18n)
- `price.quote.postcodeRequired`
- `price.quote.postcodeZoneNotFound`
- `price.quote.zonePriceNotHit`
- `price.quote.priceNotHit`
@@ -0,0 +1,28 @@
-- prc_quote: add dest_postcode only (zone resolved at runtime by postcode)
-- billing tables do NOT store zone_* columns
SET NAMES utf8mb4;
SET @db := DATABASE();
SET @has := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='prc_quote' AND COLUMN_NAME='dest_postcode');
SET @sql := IF(@has=0, 'ALTER TABLE prc_quote ADD COLUMN dest_postcode VARCHAR(20) DEFAULT NULL COMMENT ''dest postcode'' AFTER country_name', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @has := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='prc_quote' AND COLUMN_NAME='zone_id');
SET @sql := IF(@has>0, 'ALTER TABLE prc_quote DROP COLUMN zone_id', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @has := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='prc_quote' AND COLUMN_NAME='zone_code');
SET @sql := IF(@has>0, 'ALTER TABLE prc_quote DROP COLUMN zone_code', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @has := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='prc_quote' AND COLUMN_NAME='zone_name');
SET @sql := IF(@has>0, 'ALTER TABLE prc_quote DROP COLUMN zone_name', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @has := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='prc_order_bill' AND COLUMN_NAME='zone_id');
SET @sql := IF(@has>0, 'ALTER TABLE prc_order_bill DROP COLUMN zone_id', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @has := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='prc_order_bill' AND COLUMN_NAME='zone_code');
SET @sql := IF(@has>0, 'ALTER TABLE prc_order_bill DROP COLUMN zone_code', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @has := (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='prc_order_bill' AND COLUMN_NAME='zone_name');
SET @sql := IF(@has>0, 'ALTER TABLE prc_order_bill DROP COLUMN zone_name', 'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+89
View File
@@ -0,0 +1,89 @@
-- Add zone + dest_postcode to prc_quote / zone to prc_order_bill
-- Idempotent
-- charset: utf8mb4
SET NAMES utf8mb4;
SET @db := DATABASE();
-- ========== prc_quote ==========
SET @has := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_quote' AND COLUMN_NAME = 'dest_postcode'
);
SET @sql := IF(@has = 0,
'ALTER TABLE prc_quote ADD COLUMN dest_postcode VARCHAR(20) DEFAULT NULL COMMENT ''dest postcode'' AFTER country_name',
'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @has := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_quote' AND COLUMN_NAME = 'zone_id'
);
SET @sql := IF(@has = 0,
'ALTER TABLE prc_quote ADD COLUMN zone_id BIGINT(20) DEFAULT NULL COMMENT ''prc_zone.zone_id'' AFTER dest_postcode',
'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @has := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_quote' AND COLUMN_NAME = 'zone_code'
);
SET @sql := IF(@has = 0,
'ALTER TABLE prc_quote ADD COLUMN zone_code VARCHAR(50) DEFAULT NULL COMMENT ''zone code'' AFTER zone_id',
'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @has := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_quote' AND COLUMN_NAME = 'zone_name'
);
SET @sql := IF(@has = 0,
'ALTER TABLE prc_quote ADD COLUMN zone_name VARCHAR(100) DEFAULT NULL COMMENT ''zone display name'' AFTER zone_code',
'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @has := (
SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_quote' AND INDEX_NAME = 'idx_quote_zone'
);
SET @sql := IF(@has = 0,
'ALTER TABLE prc_quote ADD INDEX idx_quote_zone (zone_id)',
'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- ========== prc_order_bill ==========
SET @has := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_order_bill' AND COLUMN_NAME = 'zone_id'
);
SET @sql := IF(@has = 0,
'ALTER TABLE prc_order_bill ADD COLUMN zone_id BIGINT(20) DEFAULT NULL COMMENT ''prc_zone.zone_id'' AFTER country_name',
'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @has := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_order_bill' AND COLUMN_NAME = 'zone_code'
);
SET @sql := IF(@has = 0,
'ALTER TABLE prc_order_bill ADD COLUMN zone_code VARCHAR(50) DEFAULT NULL COMMENT ''zone code'' AFTER zone_id',
'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @has := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_order_bill' AND COLUMN_NAME = 'zone_name'
);
SET @sql := IF(@has = 0,
'ALTER TABLE prc_order_bill ADD COLUMN zone_name VARCHAR(100) DEFAULT NULL COMMENT ''zone display name'' AFTER zone_code',
'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @has := (
SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_order_bill' AND INDEX_NAME = 'idx_bill_zone'
);
SET @sql := IF(@has = 0,
'ALTER TABLE prc_order_bill ADD INDEX idx_bill_zone (zone_id)',
'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;