dy-dashboard/services/spot_confirmation_edit.py
2026-10-28 11:14:17 +08:00

69 lines
3.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Shared validation for sampling confirmation edits and imports."""
from datetime import date, datetime, timedelta
REASONS = ('价格高', '质感差', '资质不全', '同质化严重')
SAMPLE_STATUSES = ('未付款', '付款中', '样品到货中', '样品已到货', '不授权', '厂家无货', '停产', '其他')
# Keep existing imported values editable without silently changing historical records.
LEGACY_SAMPLE_STATUSES = ('不做', '产品停产', '厂家无现货', '已到货', '待寄出')
TEXT_LIMITS = {
'sample_status': 50, 'oa_approval_no': 100, 'express_tracking_no': 100,
'remark': 65535, 'product_code': 100, 'final_product_name': 300,
'platform': 200, 'sample_confirmed': 50, 'sample_confirmation_reason': 65535,
'barcode': 100, 'product_unit_price': 1000,
}
EDITABLE = frozenset((*TEXT_LIMITS, 'product_unit_price', 'arrival_date'))
def validate_confirmation_values(data):
values = {}
for key in EDITABLE & data.keys():
raw = data[key]
value = str(raw).strip() if raw is not None else ''
if key == 'arrival_date':
try:
values[key] = date.fromisoformat(value) if value else None
except ValueError:
raise ValueError('到样日期格式错误,请填写YYYY-MM-DD')
else:
size = len(value.encode('utf-8')) if TEXT_LIMITS[key] == 65535 else len(value)
if size > TEXT_LIMITS[key]:
raise ValueError('字段内容过长')
if key == 'sample_confirmed' and value not in ('', '做', '不做'):
raise ValueError('样品确认请选择做或不做')
if key == 'sample_status' and value not in ('', *SAMPLE_STATUSES, *LEGACY_SAMPLE_STATUSES):
raise ValueError('请选择有效的样品状态')
if key == 'sample_confirmation_reason' and value:
if value == '其他' or value.startswith('其他:'):
other = str(data.get('other_reason') or '').strip() if value == '其他' else value[3:].strip()
if not other:
raise ValueError('选择其他时,请填写具体原因')
if any(reason in other for reason in REASONS):
raise ValueError('其他原因不能包含价格高、质感差、资质不全、同质化严重')
value = '其他:' + other
if len(value.encode('utf-8')) > 65535:
raise ValueError('其他原因内容过长')
elif value not in (*REASONS, '无'):
raise ValueError('请选择有效的样品确认原因')
values[key] = value
if str(data.get('sample_confirmed') or '').strip() == '做' and not str(
data.get('sample_confirmation_reason') or '').strip():
values['sample_confirmation_reason'] = '无'
return values
def confirmation_reminder_state(arrival_date, sample_confirmed, as_of=None):
"""Return the derived 10-day confirmation reminder state without sending messages."""
if not arrival_date:
return {'due_date': None, 'pending': False}
if isinstance(arrival_date, str):
try:
arrival_date = date.fromisoformat(arrival_date[:10])
except ValueError:
return {'due_date': None, 'pending': False}
if isinstance(arrival_date, datetime):
arrival_date = arrival_date.date()
due_date = arrival_date + timedelta(days=10)
today = as_of or date.today()
pending = not str(sample_confirmed or '').strip() and today >= due_date
return {'due_date': due_date.isoformat(), 'pending': pending}