Python使用正则校验发票号,判断新发票号仅序列号合法递增
发票编号校验实现方案
实现逻辑
通过正则把新旧发票号拆分为「前缀」「序列号」「年份」三个部分,按以下规则校验:
- 新旧发票号必须都匹配预设的
[前缀]-[序列号]/[年份]格式,否则抛出格式错误 - 新旧发票号的前缀、年份必须完全一致,不允许修改
- 新发票号的序列号转为整数后必须严格大于旧序列号,不允许持平或调低
正则说明
使用分组正则^(\w+)-(\d+)/(\d+)$,各分组含义:
- 第1组:匹配
-之前的前缀部分(默认支持字母、数字、下划线,可根据业务调整字符范围) - 第2组:匹配
-和/中间的数字序列号,自动兼容前导零 - 第3组:匹配
/之后的年份数字
完整实现代码
import re from rest_framework.exceptions import ValidationError # 预编译正则,提升重复调用的性能 INVOICE_NO_PATTERN = re.compile(r'^(\w+)-(\d+)/(\d+)$') def update(self, instance, validated_data): old_invoice_no = instance.number # 示例值:CN-002/2021 new_invoice_no = validated_data.get("number") # 示例值:CN-001/2021 if old_invoice_no != new_invoice_no: # 校验新旧编号格式是否合法 old_match = INVOICE_NO_PATTERN.fullmatch(old_invoice_no) new_match = INVOICE_NO_PATTERN.fullmatch(new_invoice_no) if not old_match or not new_match: raise ValidationError("msg_error_malformed_invoice_number_pattern") # 提取三个字段的值 old_prefix, old_seq, old_year = old_match.groups() new_prefix, new_seq, new_year = new_match.groups() # 校验前缀、年份未被修改,序列号递增 if old_prefix != new_prefix or old_year != new_year: # 如果业务要求所有非法修改都返回同一个错误提示,可直接使用msg_error_malformed_invoice_number_pattern raise ValidationError("msg_error_invoice_number_cannot_modify_prefix_or_year") if int(new_seq) <= int(old_seq): # 同上,可根据需求统一错误提示 raise ValidationError("msg_error_invoice_number_sequence_must_increase") # 校验通过,执行原更新逻辑 validated_data = self._update_validated_data(validated_data) instance = super().update(instance, validated_data) self._update_customer(validated_data, instance) return instance
规则调整说明
如果发票编号前缀支持特殊字符(比如横杠、点),可以调整正则的前缀匹配规则,例如允许横杠的话把\w+改成[a-zA-Z0-9-]+即可。
内容的提问来源于stack exchange,提问作者Dziu Gas
相关产品推荐
相关产品推荐

