AutoRpa/rpa_oms/app/inbound/sales_goods.py

171 lines
5.5 KiB
Python
Raw 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.

"""接口 1 逐条校验与落表。不跑选品。
入参 camelCase,落表 snake_case。长度跟 VARCHAR2。
单条结果:
- ACCEPTED:入库,deal_flag=0,等选品作业捞
- DUPLICATE:库里已有同一 omsId,不更新、不重跑
- CONFLICT:同一请求里 omsId 出现过(前一条哪怕被拒,后一条也算冲突)
- REJECTED:字段不过,不入库
混批 HTTP 仍 200。omsId / 数量必须是 JSON 整数,不把 "10" 当 10。
"""
from __future__ import annotations
from datetime import date, datetime
from decimal import Decimal, InvalidOperation
from .repo import DuplicateOmsId
# (接口字段, 表列, 最大字符数)
_STRING_FIELDS = (
("barCode", "bar_code", 40),
("goodsId", "goods_id", 20),
("goodsName", "goods_name", 200),
("goodsSpec", "goods_spec", 100),
("manufacturer", "manufacturer", 100),
("approvalNo", "approval_no", 100),
("unit", "unit", 20),
("customerId", "customer_id", 20),
("customerName", "customer_name", 200),
("orgCode", "org_code", 10),
("goodsMdmCode", "goods_mdm_code", 100),
("customerMdmCode", "customer_mdm_code", 100),
)
_INT_FIELDS = (
("saleQty", "sale_qty"),
("planPurchaseQty", "plan_purchase_qty"),
)
def receive_sales_goods(rows: list, repo) -> list[dict]:
seen: set[int] = set()
results: list[dict] = []
for row in rows:
results.append(_receive_one(row, repo, seen))
return results
def _receive_one(row: object, repo, seen: set[int]) -> dict:
if not isinstance(row, dict):
return _result(None, "REJECTED", "明细必须是对象")
oms_id, oms_error = _parse_oms_id(row.get("omsId"))
if oms_id is not None and oms_id in seen:
return _result(oms_id, "CONFLICT", "同一请求中 omsId 重复")
if oms_id is not None:
seen.add(oms_id)
parsed, error = _parse_row(row, oms_id, oms_error)
if error:
_camel, message = error
return _result(row.get("omsId"), "REJECTED", message)
try:
repo.insert(parsed)
except DuplicateOmsId:
return _result(parsed["oms_id"], "DUPLICATE", "订单中心序号已存在,未重复入库")
return _result(parsed["oms_id"], "ACCEPTED", "接收成功,等待RPA处理")
def _parse_row(row: dict, oms_id: int | None, oms_error: str | None):
if oms_error:
return None, ("omsId", oms_error)
record: dict = {"oms_id": oms_id, "deal_flag": 0}
for camel, snake, max_len in _STRING_FIELDS:
value, error = _parse_str(row.get(camel), camel, max_len)
if error:
return None, (camel, error)
record[snake] = value
order_date, error = _parse_date(row.get("orderDate"))
if error:
return None, ("orderDate", error)
record["order_date"] = order_date
sale_price, error = _parse_decimal(row.get("salePrice"), "salePrice")
if error:
return None, ("salePrice", error)
record["sale_price"] = sale_price
for camel, snake in _INT_FIELDS:
value, error = _parse_int(row.get(camel), camel)
if error:
return None, (camel, error)
record[snake] = value
return record, None
def _parse_oms_id(value) -> tuple[int | None, str | None]:
if value is None or value == "":
return None, "缺少必填字段 omsId"
# bool 是 int 子类,必须用 type(value) is int。oms_id 列 number(20)。
if type(value) is int and 0 < value < 10**20:
return value, None
return None, "omsId 必须是整数"
def _parse_str(value, camel: str, max_len: int) -> tuple[str | None, str | None]:
if value is None:
return None, f"缺少必填字段 {camel}"
if not isinstance(value, str):
return None, f"{camel} 必须是字符串"
text = value.strip()
if not text:
return None, f"缺少必填字段 {camel}"
if len(text) > max_len:
return None, f"{camel} 超出长度"
return text, None
def _parse_int(value, camel: str) -> tuple[int | None, str | None]:
if value is None or value == "":
return None, f"缺少必填字段 {camel}"
if type(value) is int:
return value, None
return None, f"{camel} 必须是整数"
def _parse_decimal(value, camel: str) -> tuple[Decimal | None, str | None]:
if value is None or value == "":
return None, f"缺少必填字段 {camel}"
if type(value) is bool:
return None, f"{camel} 必须是数字"
try:
if isinstance(value, Decimal):
amount = value
elif isinstance(value, str):
amount = Decimal(value.strip())
elif type(value) is int:
amount = Decimal(value)
elif isinstance(value, float):
amount = Decimal(str(value))
else:
return None, f"{camel} 必须是数字"
except (InvalidOperation, ValueError):
return None, f"{camel} 必须是数字"
return amount, None
def _parse_date(value) -> tuple[date | None, str | None]:
if value is None or value == "":
return None, "缺少必填字段 orderDate"
if isinstance(value, datetime):
return value.date(), None
if isinstance(value, date):
return value, None
if not isinstance(value, str):
return None, "orderDate 必须是 YYYY-MM-DD"
try:
return date.fromisoformat(value.strip()), None
except ValueError:
return None, "orderDate 必须是 YYYY-MM-DD"
def _result(oms_id, result_code: str, message: str) -> dict:
return {"omsId": oms_id, "resultCode": result_code, "message": message}