feat: 合同页尽调闸和签订日开始日回退

This commit is contained in:
Yuuuu 2026-10-05 22:49:18 +08:00
parent 4c49f9d253
commit 5f5ec4874f
5 changed files with 86 additions and 4 deletions

View File

@ -141,6 +141,8 @@ def build_flow_context(spec: ContractCreateInput, draft: ContractDraft) -> Contr
amount=draft.amount, amount=draft.amount,
contract_title=draft.contract_title, contract_title=draft.contract_title,
contract_end_date=draft.contract_end_date, contract_end_date=draft.contract_end_date,
contract_sign_date=draft.contract_sign_date,
contract_start_date=draft.contract_start_date,
is_major_contract=draft.is_major_contract, is_major_contract=draft.is_major_contract,
is_prepayment=draft.is_prepayment, is_prepayment=draft.is_prepayment,
belong_year=draft.belong_year, belong_year=draft.belong_year,

View File

@ -35,6 +35,8 @@ class ContractDraft:
amount: str = "" amount: str = ""
contract_title: str = "" contract_title: str = ""
contract_end_date: str = "" contract_end_date: str = ""
contract_sign_date: str = ""
contract_start_date: str = ""
is_major_contract: str = "否" is_major_contract: str = "否"
is_prepayment: str = "否" is_prepayment: str = "否"
belong_year: str = "" belong_year: str = ""
@ -87,6 +89,8 @@ def contract_draft_from_dict(data: dict[str, Any]) -> ContractDraft:
amount=str(data.get("amount", "")), amount=str(data.get("amount", "")),
contract_title=str(data.get("contractTitle") or data.get("docSubject") or ""), contract_title=str(data.get("contractTitle") or data.get("docSubject") or ""),
contract_end_date=str(data.get("contractEndDate", "")), contract_end_date=str(data.get("contractEndDate", "")),
contract_sign_date=str(data.get("contractSignDate", "")),
contract_start_date=str(data.get("contractStartDate", "")),
is_major_contract=str(data.get("isMajorContract", "否")), is_major_contract=str(data.get("isMajorContract", "否")),
is_prepayment=str(data.get("isPrepayment", "否")), is_prepayment=str(data.get("isPrepayment", "否")),
belong_year=str(data.get("belongYear", "")), belong_year=str(data.get("belongYear", "")),

View File

@ -8,6 +8,7 @@ from typing import Protocol
from accept import AcceptanceReport, accept_log_path, evidence_shot from accept import AcceptanceReport, accept_log_path, evidence_shot
from errors import ( from errors import (
DiligenceError,
LoginFailed, LoginFailed,
NodeError, NodeError,
PdfMergeUnsupported, PdfMergeUnsupported,
@ -69,6 +70,8 @@ class ContractFlowContext:
amount: str = "" amount: str = ""
contract_title: str = "" contract_title: str = ""
contract_end_date: str = "" contract_end_date: str = ""
contract_sign_date: str = ""
contract_start_date: str = ""
is_major_contract: str = "否" is_major_contract: str = "否"
is_prepayment: str = "否" is_prepayment: str = "否"
belong_year: str = "" belong_year: str = ""
@ -104,6 +107,7 @@ def run_contract_create_flow(browser: BrowserAdapter, ctx: ContractFlowContext)
enter_contract_create(browser) enter_contract_create(browser)
select_contract_template(browser, ctx) select_contract_template(browser, ctx)
fill_contract_signatory_info(browser, ctx) fill_contract_signatory_info(browser, ctx)
check_customer_diligence(browser, ctx)
fill_contract_basic_info(browser, ctx) fill_contract_basic_info(browser, ctx)
fill_contract_amount_and_dates(browser, ctx) fill_contract_amount_and_dates(browser, ctx)
fill_contract_goods_lines(browser, ctx) fill_contract_goods_lines(browser, ctx)
@ -531,14 +535,30 @@ def _select_settlement_type(browser: BrowserAdapter, value: str) -> None:
raise NodeError(f"结算方式下拉未选中,仍停留在「==请选择==」,期望「{value}」") raise NodeError(f"结算方式下拉未选中,仍停留在「==请选择==」,期望「{value}」")
def sign_date_for(ctx: ContractFlowContext) -> str:
return (ctx.contract_sign_date or ctx.order_date or "").strip()
def begin_date_for(ctx: ContractFlowContext) -> str:
return (ctx.contract_start_date or ctx.order_date or "").strip()
def check_customer_diligence(browser: BrowserAdapter, ctx: ContractFlowContext) -> None:
text = browser.read_body_text() or ""
if "未尽调" in text:
raise DiligenceError("客户未尽调")
def fill_contract_amount_and_dates(browser: BrowserAdapter, ctx: ContractFlowContext) -> None: def fill_contract_amount_and_dates(browser: BrowserAdapter, ctx: ContractFlowContext) -> None:
amount_type = (ctx.amount_type or "合同标的金额").strip() amount_type = (ctx.amount_type or "合同标的金额").strip()
if amount_type: if amount_type:
browser.select_xform(X["amount_type"], amount_type) browser.select_xform(X["amount_type"], amount_type)
if ctx.amount: if ctx.amount:
browser.fill_first([F["amount"]], ctx.amount) browser.fill_first([F["amount"]], ctx.amount)
browser.fill_first([F["sign_date"]], ctx.order_date) sign_date = sign_date_for(ctx)
browser.fill_first([F["begin_date"]], ctx.order_date) begin_date = begin_date_for(ctx)
browser.fill_first([F["sign_date"]], sign_date)
browser.fill_first([F["begin_date"]], begin_date)
if ctx.contract_end_date: if ctx.contract_end_date:
browser.fill_first([F["end_date"]], ctx.contract_end_date) browser.fill_first([F["end_date"]], ctx.contract_end_date)
evidence_shot(browser, "contract-amount-and-dates-filled") evidence_shot(browser, "contract-amount-and-dates-filled")
@ -547,8 +567,8 @@ def fill_contract_amount_and_dates(browser: BrowserAdapter, ctx: ContractFlowCon
"金额日期", "金额日期",
[ [
("amount", _try_read(browser, [F["amount"]]), ctx.amount), ("amount", _try_read(browser, [F["amount"]]), ctx.amount),
("signDate", _try_read(browser, [F["sign_date"]]), ctx.order_date), ("signDate", _try_read(browser, [F["sign_date"]]), sign_date),
("beginDate", _try_read(browser, [F["begin_date"]]), ctx.order_date), ("beginDate", _try_read(browser, [F["begin_date"]]), begin_date),
("endDate", _try_read(browser, [F["end_date"]]), ctx.contract_end_date), ("endDate", _try_read(browser, [F["end_date"]]), ctx.contract_end_date),
], ],
browser=browser, browser=browser,

View File

@ -29,3 +29,9 @@ class UnknownRpaError(NodeError):
error_code = "RPA_UNKNOWN_ERROR" error_code = "RPA_UNKNOWN_ERROR"
retryable = True retryable = True
route_role = "OPS" route_role = "OPS"
class DiligenceError(NodeError):
error_code = "BIZ_CUSTOMER_NOT_DILIGENCE"
retryable = False
route_role = "PURCHASER"

View File

@ -0,0 +1,50 @@
from contract_flow_steps import (
ContractFlowContext,
begin_date_for,
check_customer_diligence,
sign_date_for,
)
from errors import DiligenceError
import pytest
def _ctx(**overrides) -> ContractFlowContext:
data = dict(
contract_url="http://example",
username="u",
password="p",
supplier_name="示例",
order_date="2026-09-28",
source_type="",
)
data.update(overrides)
return ContractFlowContext(**data)
class _FakeBrowser:
def __init__(self, text: str):
self._text = text
def read_body_text(self) -> str:
return self._text
def test_sign_and_begin_fall_back_to_order_date():
ctx = _ctx()
assert sign_date_for(ctx) == "2026-09-28"
assert begin_date_for(ctx) == "2026-09-28"
def test_sign_and_begin_use_contract_dates_when_set():
ctx = _ctx(contract_sign_date="2026-10-01", contract_start_date="2026-10-02")
assert sign_date_for(ctx) == "2026-10-01"
assert begin_date_for(ctx) == "2026-10-02"
def test_diligence_raises_when_page_says_not_done():
with pytest.raises(DiligenceError, match="客户未尽调"):
check_customer_diligence(_FakeBrowser("客户未尽调,不能起草"), _ctx())
def test_diligence_passes_when_text_absent():
check_customer_diligence(_FakeBrowser("客户已尽调"), _ctx())