feat: 合同页尽调闸和签订日开始日回退
This commit is contained in:
parent
4c49f9d253
commit
5f5ec4874f
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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", "")),
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
Loading…
Reference in New Issue