certflow.services.dual_code 源代码
"""批次1 双编码:SN 短码 / KKS 长码 派生(B1-1 / B1-2)
背景与定案(reports_migration/notes/vba_replica_audit/README.md 76-86 行):
- B1-ambig(0.2):一般件 kks_code=长 V 码(含YYMM)、sn_code=剥 YYMM 短码;
电厂件 kks_code=用户 9 位 KKS 清单、sn_code=短 V 码。
- B1-sn-elec(0.4):电厂件 kks_code 来自订单 KKS 清单逐行补录(**非 getKKS 公式生成**),
getKKS 仅历史特殊规则参考 → 真 KKS 受保护不被编号覆盖。
本模块只负责「字段+生成规则」:
- to_sn_code: 由长 V 码剥离 4 位 YYMM → SN 短码(对齐 VBA 默认模式 sn = code[0]+code[5:])。
- sync_dual_codes: 编号后置,由 product_code 同步 sn_code / kks_code 到 SalePlan。
"""
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from certflow.models.sale_plan import SalePlan
from certflow.utils.logger import get_logger
logger = get_logger()
[文档]
def to_sn_code(long_code: str) -> str:
"""由长 V 码剥离 4 位 YYMM,得到 SN 短码(保留 V + 流水号 + 后缀)。
对齐 VBA 默认编码模式(certificate_print_service._derive_sn_and_kks 默认分支):
KKS(长)=完整编码含年月;SN(短)=去掉中间 4 位年月。
例:``V2604520Y`` -> ``V520Y``;``V2606001-V2606005`` -> ``V001-V2606005``
(仅首段去 YYMM,与打印期推导保持一致)。
非 V 码 / 空值原样返回。
Args:
long_code: 完整产品编号(如 ``V2604520Y``),一般为 product_code。
Returns:
str: SN 短码;输入非法时原样返回(空串返回空串)。
"""
if not long_code or not long_code.startswith("V") or len(long_code) <= 5:
return long_code or ""
# V + 4 位年月(YYMM) + 流水号 + 后缀 → 去掉中间 4 位年月,保留 V + 其余
return long_code[0] + long_code[5:]
def _is_real_kks(value: str) -> bool:
"""判断是否为用户录入的真 KKS(电厂件),而非自动默认的长 V 码。
真 KKS 来自订单 KKS 清单,不以 ``V`` 开头(KKS 为独立编码),受
:func:`sync_dual_codes` 保护不被编号覆盖。
Args:
value: 当前 kks_code 值。
Returns:
bool: 为真 KKS 返回 True。
"""
return bool(value) and not value.startswith("V")
[文档]
def sync_dual_codes(record: SalePlan) -> None:
"""编号后置:由 product_code 同步 sn_code / kks_code 到 SalePlan。
规则:
- ``sn_code`` = 剥 YYMM 短码(:func:`to_sn_code`)。
- ``kks_code`` = 一般件默认=长 V 码(product_code);电厂件已录入的真 KKS
(不以 V 开头)**受保护不被覆盖**(B1-sn-elec 0.4)。
Args:
record: 已设置 product_code 的 SalePlan ORM 对象(会被就地修改)。
"""
long_code = record.product_code or ""
# SN 短码始终跟随 product_code 重新推导
record.sn_code = to_sn_code(long_code)
# KKS 长码:真 KKS(电厂件)保护;其余(空或既往默认的 V 码)跟随 product_code
if _is_real_kks(record.kks_code or ""):
logger.debug(
f"sync_dual_codes | 真KKS受保护 product_code={long_code!r} "
f"sn_code={record.sn_code!r} kks_code={record.kks_code!r}(保留)"
)
return
record.kks_code = long_code
logger.debug(
f"sync_dual_codes | product_code={long_code!r} "
f"sn_code={record.sn_code!r} kks_code={record.kks_code!r}"
)