AutoRpa/选品流程/repo.py

220 lines
6.4 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 领取、表 2 落结果。
claim 时 deal_flag 0 → 3;save 时写成 1 或 2。
中途崩溃会停在 3,需人工改回 0 再跑。
"""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from typing import Any
from db import DEAL_USER_NAME, RepoUnavailable, connect_from_env, oracle_dsn
_SELECT_PENDING = """
SELECT fid, oms_id, bar_code, sale_price, plan_purchase_qty,
NVL(approval_no, '') AS approval_no,
NVL(goods_name, '') AS goods_name,
NVL(goods_spec, '') AS goods_spec,
NVL(manufacturer, '') AS manufacturer,
NVL(org_code, '') AS org_code,
deal_flag
FROM rpa_sales_goods_mapping_data
WHERE deal_flag = 0
ORDER BY fid
"""
_SELECT_PENDING_LIMIT = f"""
SELECT * FROM (
{_SELECT_PENDING}
) WHERE ROWNUM <= :limit
"""
_CLAIM_SQL = """
UPDATE rpa_sales_goods_mapping_data
SET deal_flag = 3,
deal_time = SYSDATE,
update_time = SYSDATE,
deal_user_name = :deal_user_name
WHERE fid = :fid AND deal_flag = 0
"""
_INSERT_CART_SQL = """
INSERT INTO rpa_cart_settlement_goods_data (
operate_type, oms_id, platform_type, supplier_name, bar_code,
purchase_price, purchase_qty, purchase_total, status, fail_reason,
push_status, create_time, org_code, multi_platform_flag, create_user_name
) VALUES (
:operate_type, :oms_id, :platform_type, :supplier_name, :bar_code,
:purchase_price, :purchase_qty, :purchase_total, :status, :fail_reason,
:push_status, SYSDATE, :org_code, :multi_platform_flag, :create_user_name
)
"""
_COMPLETE_SQL = """
UPDATE rpa_sales_goods_mapping_data
SET deal_flag = :deal_flag,
deal_result = :deal_result,
deal_time = SYSDATE,
update_time = SYSDATE,
deal_user_name = :deal_user_name
WHERE oms_id = :oms_id
"""
_CART_BIND_KEYS = (
"operate_type",
"oms_id",
"platform_type",
"supplier_name",
"bar_code",
"purchase_price",
"purchase_qty",
"purchase_total",
"status",
"fail_reason",
"push_status",
"org_code",
"multi_platform_flag",
)
@dataclass
class MappingRow:
fid: int
oms_id: int
bar_code: str
sale_price: float | None
plan_purchase_qty: float | None
approval_no: str
goods_name: str
goods_spec: str
manufacturer: str
org_code: str
deal_flag: int
deal_result: str = ""
class MemorySelectRepo:
def __init__(self, rows: list[MappingRow]):
self.mapping: dict[int, MappingRow] = {row.oms_id: row for row in rows}
self.cart: list[dict[str, Any]] = []
def claim_pending(self, limit: int | None = None) -> list[MappingRow]:
pending = sorted(
(row for row in self.mapping.values() if row.deal_flag == 0),
key=lambda row: row.fid,
)
if limit is not None:
pending = pending[:limit]
for row in pending:
row.deal_flag = 3
return pending
def save_result(
self,
oms_id: int,
deal_flag: int,
deal_result: str,
cart_rows: list[dict[str, Any]],
) -> None:
row = self.mapping[oms_id]
row.deal_flag = deal_flag
row.deal_result = deal_result
self.cart.extend(dict(item) for item in cart_rows)
class OracleSelectRepo:
def __init__(self, connect: Callable):
self._connect = connect
@classmethod
def from_env(cls) -> "OracleSelectRepo":
oracle_dsn()
return cls(connect=connect_from_env)
def claim_pending(self, limit: int | None = None) -> list[MappingRow]:
conn = self._connect()
try:
with conn.cursor() as cur:
if limit is None:
cur.execute(_SELECT_PENDING)
else:
cur.execute(_SELECT_PENDING_LIMIT, {"limit": int(limit)})
fetched = [_mapping_from_cursor(cur, rec) for rec in cur.fetchall()]
claimed: list[MappingRow] = []
for row in fetched:
cur.execute(
_CLAIM_SQL,
{"fid": row.fid, "deal_user_name": DEAL_USER_NAME},
)
if cur.rowcount == 1:
row.deal_flag = 3
claimed.append(row)
conn.commit()
return claimed
except Exception as exc:
try:
conn.rollback()
except Exception:
pass
raise RepoUnavailable(str(exc)) from exc
finally:
conn.close()
def save_result(
self,
oms_id: int,
deal_flag: int,
deal_result: str,
cart_rows: list[dict[str, Any]],
) -> None:
conn = self._connect()
try:
with conn.cursor() as cur:
for row in cart_rows:
payload = {key: row.get(key) for key in _CART_BIND_KEYS}
payload["create_user_name"] = DEAL_USER_NAME
cur.execute(_INSERT_CART_SQL, payload)
cur.execute(
_COMPLETE_SQL,
{
"deal_flag": deal_flag,
"deal_result": deal_result,
"deal_user_name": DEAL_USER_NAME,
"oms_id": oms_id,
},
)
conn.commit()
except Exception as exc:
try:
conn.rollback()
except Exception:
pass
raise RepoUnavailable(str(exc)) from exc
finally:
conn.close()
def _mapping_from_cursor(cur, rec) -> MappingRow:
cols = [item[0].lower() for item in cur.description]
data = dict(zip(cols, rec))
return MappingRow(
fid=int(data["fid"]),
oms_id=int(data["oms_id"]),
bar_code=str(data.get("bar_code") or ""),
sale_price=_float_or_none(data.get("sale_price")),
plan_purchase_qty=_float_or_none(data.get("plan_purchase_qty")),
approval_no=str(data.get("approval_no") or ""),
goods_name=str(data.get("goods_name") or ""),
goods_spec=str(data.get("goods_spec") or ""),
manufacturer=str(data.get("manufacturer") or ""),
org_code=str(data.get("org_code") or ""),
deal_flag=int(data.get("deal_flag") or 0),
)
def _float_or_none(value: object) -> float | None:
if value is None or value == "":
return None
return float(value)