89 lines
3.2 KiB
Python
89 lines
3.2 KiB
Python
"""拼多多订单号校验(商家链接填单)"""
|
||
import re
|
||
from datetime import date, timedelta
|
||
|
||
# 用户复制错误时的引导文案
|
||
PDD_ORDER_ID_HELP = (
|
||
'请在拼多多 App:我的 → 我的订单 → 点开对应订单 → 复制「订单编号」后粘贴,'
|
||
'不要粘贴分享链接或网页地址。'
|
||
)
|
||
|
||
PDD_ORDER_ID_ERROR = '拼多多订单号格式不正确,' + PDD_ORDER_ID_HELP
|
||
|
||
|
||
def _parse_date_prefix(prefix: str):
|
||
"""解析订单号前 6 位 YYMMDD 或前 8 位 YYYYMMDD,返回 date 或 None。"""
|
||
if len(prefix) >= 8 and prefix[:8].isdigit():
|
||
y = int(prefix[:4])
|
||
if 2010 <= y <= 2035:
|
||
m, d = int(prefix[4:6]), int(prefix[6:8])
|
||
try:
|
||
return date(y, m, d)
|
||
except ValueError:
|
||
pass
|
||
if len(prefix) >= 6 and prefix[:6].isdigit():
|
||
yy, m, d = int(prefix[:2]), int(prefix[2:4]), int(prefix[4:6])
|
||
y = 2000 + yy if yy < 100 else yy
|
||
try:
|
||
return date(y, m, d)
|
||
except ValueError:
|
||
return None
|
||
return None
|
||
|
||
|
||
def validate_pdd_order_id(raw: str) -> tuple[bool, str]:
|
||
"""
|
||
校验拼多多订单号。
|
||
允许字母数字组合(含国际单 XP 前缀等),拒绝 URL/链接/token 误填。
|
||
"""
|
||
order_id = str(raw or '').strip()
|
||
if not order_id:
|
||
return False, '拼多多订单号不能为空'
|
||
|
||
lower = order_id.lower()
|
||
if re.search(r'https?://', lower) or '://' in lower:
|
||
return False, '请勿粘贴网页链接,请填写拼多多订单编号。' + PDD_ORDER_ID_HELP
|
||
if '/' in order_id or '?' in order_id or '#' in order_id:
|
||
return False, PDD_ORDER_ID_ERROR
|
||
if re.search(r'(order|dingdan)/[a-z0-9]{8,}', lower):
|
||
return False, '检测到派单链接内容,请填写拼多多订单编号。' + PDD_ORDER_ID_HELP
|
||
|
||
if len(order_id) < 12 or len(order_id) > 32:
|
||
return False, PDD_ORDER_ID_ERROR
|
||
if not re.match(r'^[A-Za-z0-9\-]+$', order_id):
|
||
return False, PDD_ORDER_ID_ERROR
|
||
if not re.search(r'\d', order_id):
|
||
return False, PDD_ORDER_ID_ERROR
|
||
|
||
# 国际清关等 XP 前缀
|
||
if order_id.upper().startswith('XP'):
|
||
if len(order_id) < 10:
|
||
return False, PDD_ORDER_ID_ERROR
|
||
return True, ''
|
||
|
||
# 须以数字开头(常见为年份/日期段)
|
||
if not order_id[0].isdigit():
|
||
return False, PDD_ORDER_ID_ERROR
|
||
|
||
order_date = _parse_date_prefix(order_id)
|
||
if order_date is not None:
|
||
today = date.today()
|
||
if order_date > today + timedelta(days=1):
|
||
return False, '订单号日期异常(不能晚于今天),请核对拼多多订单编号。'
|
||
if order_date < today - timedelta(days=730):
|
||
return False, '订单号日期过旧,请核对是否为当前拼多多订单编号。'
|
||
|
||
return True, ''
|
||
|
||
|
||
def validate_cn_mobile(raw: str, required: bool = False) -> tuple[bool, str]:
|
||
"""中国大陆手机号校验;默认选填,空值通过。"""
|
||
phone = str(raw or '').strip()
|
||
if not phone:
|
||
if required:
|
||
return False, '手机号不能为空'
|
||
return True, ''
|
||
if not re.match(r'^1[3-9]\d{9}$', phone):
|
||
return False, '请输入正确的11位中国大陆手机号'
|
||
return True, ''
|