From 1bc416da9dadb06ebe33658ed67fbf07c5c023c1 Mon Sep 17 00:00:00 2001 From: yuqei Date: Sun, 24 May 2026 09:02:15 +0800 Subject: [PATCH] feat: add intercompany loan document type --- .../legal_document_element_schema_service.py | 68 +++++++++++++++++++ .../services/legal_document_type_service.py | 12 +++- backend/app/services/template_service.py | 60 ++++++++++++++++ ...t_legal_document_element_schema_service.py | 47 +++++++++++++ .../tests/test_legal_document_type_service.py | 4 +- .../src/app/documents/new/[type]/page.tsx | 1 + frontend/src/app/documents/new/page.tsx | 1 + 7 files changed, 190 insertions(+), 3 deletions(-) diff --git a/backend/app/services/legal_document_element_schema_service.py b/backend/app/services/legal_document_element_schema_service.py index e2d3bf80..4907aae8 100644 --- a/backend/app/services/legal_document_element_schema_service.py +++ b/backend/app/services/legal_document_element_schema_service.py @@ -362,6 +362,74 @@ DEFAULT_ELEMENT_SCHEMAS: dict[str, dict[str, Any]] = { }, ] }, + "intercompany_loan_agreement": { + "sections": [ + _party_section(), + { + "key": "relationship_and_approval", + "title": "关联关系与内部审批", + "fields": [ + {"key": "relationship.description", "label": "关联关系说明", "type": "textarea", "required": True}, + {"key": "internal_approval.confirmation", "label": "内部审批确认", "type": "textarea", "required": True}, + ], + }, + { + "key": "loan_amount_and_purpose", + "title": "借款金额与资金用途", + "fields": [ + {"key": "loan.amount", "label": "借款金额", "type": "money", "required": True}, + {"key": "loan.purpose", "label": "借款用途", "type": "textarea", "required": True}, + {"key": "fund.disbursement_account", "label": "资金划付账户", "type": "textarea", "required": True}, + {"key": "fund.receipt_confirmation", "label": "资金到账确认", "type": "textarea", "required": True}, + {"key": "fund.usage_restriction", "label": "资金用途限制说明", "type": "textarea", "required": False}, + ], + }, + { + "key": "interest_and_term", + "title": "借款期限与计息", + "fields": [ + {"key": "loan.term", "label": "借款期限", "type": "text", "required": True}, + {"key": "interest.start_date", "label": "起息日", "type": "date", "required": True}, + {"key": "interest.rate_method", "label": "年化利率/计息方式", "type": "textarea", "required": True}, + {"key": "interest.payment_method", "label": "利息支付方式", "type": "textarea", "required": True}, + ], + }, + { + "key": "repayment_arrangements", + "title": "还款安排", + "fields": [ + {"key": "repayment.method", "label": "还款方式", "type": "textarea", "required": True}, + {"key": "repayment.plan", "label": "还款计划", "type": "textarea", "required": True}, + {"key": "repayment.account", "label": "还款账户", "type": "textarea", "required": True}, + {"key": "prepayment.arrangement", "label": "提前还款安排", "type": "textarea", "required": False}, + ], + }, + { + "key": "guarantee_and_compliance", + "title": "担保与合规", + "fields": [ + {"key": "guarantee.method", "label": "担保方式", "type": "textarea", "required": True}, + {"key": "guarantee.documents", "label": "担保文件", "type": "textarea", "required": False}, + {"key": "regulatory_note", "label": "资金合规与监管说明", "type": "textarea", "required": False}, + ], + }, + { + "key": "dispute_and_signature", + "title": "争议解决与签署", + "fields": [ + { + "key": "dispute_resolution.method", + "label": "争议解决方式", + "type": "select", + "required": True, + "options": ["诉讼", "仲裁"], + }, + {"key": "sign_date", "label": "签署日期", "type": "date", "required": True}, + {"key": "e_signature_platform", "label": "电子签署平台", "type": "text", "required": False}, + ], + }, + ] + }, "rescission_notice": { "sections": [ _party_section(), diff --git a/backend/app/services/legal_document_type_service.py b/backend/app/services/legal_document_type_service.py index 76f55b8a..7e260503 100644 --- a/backend/app/services/legal_document_type_service.py +++ b/backend/app/services/legal_document_type_service.py @@ -114,6 +114,16 @@ DEFAULT_LEGAL_DOCUMENT_TYPES: list[dict[str, Any]] = [ "risk_level": "high", "sort_order": 85, }, + { + "code": "intercompany_loan_agreement", + "name": "企业间借款合同", + "category": "investment-finance", + "industry": "general-enterprise", + "scenario": "intercompany-loan", + "description": "适用于企业间借款、关联交易、利率、担保、还款和资金合规场景。", + "risk_level": "critical", + "sort_order": 86, + }, { "code": "valuation_adjustment_agreement", "name": "对赌协议", @@ -122,7 +132,7 @@ DEFAULT_LEGAL_DOCUMENT_TYPES: list[dict[str, Any]] = [ "scenario": "valuation-adjustment", "description": "适用于投融资中的业绩承诺、估值调整、补偿和回购安排场景。", "risk_level": "critical", - "sort_order": 86, + "sort_order": 87, }, { "code": "shareholder_resolution", diff --git a/backend/app/services/template_service.py b/backend/app/services/template_service.py index 28cc67a5..e7ea06ca 100644 --- a/backend/app/services/template_service.py +++ b/backend/app/services/template_service.py @@ -255,6 +255,66 @@ DEFAULT_TEMPLATES: list[dict[str, Any]] = [ {"name": "sign_date", "label": "签署日期"}, ], }, + { + "name": "企业间借款合同模板", + "contract_type": "intercompany-loan", + "document_type_code": "intercompany_loan_agreement", + "template_category": "investment-finance", + "industry_category": "general-enterprise", + "description": "适用于企业间借款、关联交易、利率、还款、担保和资金合规场景。", + "content": ( + "甲方(出借方):{{lender}}\n" + "乙方(借款方):{{borrower}}\n" + "关联关系说明:{{relationship_note}}\n" + "内部审批确认:{{internal_approval}}\n\n" + "一、借款金额与用途\n" + "借款金额:{{loan_amount}}\n" + "借款用途:{{loan_purpose}}\n" + "资金划付账户:{{disbursement_account}}\n" + "资金到账确认:{{receipt_confirmation}}\n\n" + "二、借款期限与利息\n" + "借款期限:{{loan_term}}\n" + "起息日:{{interest_start_date}}\n" + "年化利率/计息方式:{{interest_rate_method}}\n" + "利息支付方式:{{interest_payment_method}}\n\n" + "三、还款与担保\n" + "还款方式:{{repayment_method}}\n" + "还款计划:{{repayment_plan}}\n" + "还款账户:{{repayment_account}}\n" + "担保方式:{{guarantee_method}}\n" + "担保文件:{{guarantee_documents}}\n\n" + "四、合规、违约与争议解决\n" + "资金用途限制说明:{{fund_usage_restriction}}\n" + "违约责任:{{breach_liability}}\n" + "争议解决方式:{{dispute_resolution}}\n" + "电子签署平台:{{e_signature_platform}}\n" + "签署日期:{{sign_date}}" + ), + "variables": [ + {"name": "lender", "label": "甲方名称"}, + {"name": "borrower", "label": "乙方名称"}, + {"name": "relationship_note", "label": "关联关系说明"}, + {"name": "internal_approval", "label": "内部审批确认"}, + {"name": "loan_amount", "label": "借款金额"}, + {"name": "loan_purpose", "label": "借款用途"}, + {"name": "disbursement_account", "label": "资金划付账户"}, + {"name": "receipt_confirmation", "label": "资金到账确认"}, + {"name": "loan_term", "label": "借款期限"}, + {"name": "interest_start_date", "label": "起息日"}, + {"name": "interest_rate_method", "label": "年化利率/计息方式"}, + {"name": "interest_payment_method", "label": "利息支付方式"}, + {"name": "repayment_method", "label": "还款方式"}, + {"name": "repayment_plan", "label": "还款计划"}, + {"name": "repayment_account", "label": "还款账户"}, + {"name": "guarantee_method", "label": "担保方式"}, + {"name": "guarantee_documents", "label": "担保文件", "required": False}, + {"name": "fund_usage_restriction", "label": "资金用途限制说明", "required": False}, + {"name": "breach_liability", "label": "违约责任", "required": False}, + {"name": "dispute_resolution", "label": "争议解决方式"}, + {"name": "e_signature_platform", "label": "电子签署平台", "required": False}, + {"name": "sign_date", "label": "签署日期"}, + ], + }, ] diff --git a/backend/tests/test_legal_document_element_schema_service.py b/backend/tests/test_legal_document_element_schema_service.py index 7c9ef20d..2a6ac52b 100644 --- a/backend/tests/test_legal_document_element_schema_service.py +++ b/backend/tests/test_legal_document_element_schema_service.py @@ -67,9 +67,16 @@ class StubDocumentTypeRepository: "technical_service", "lease_house", "equity_transfer", + "intercompany_loan_agreement", "cooperation_framework", "demand_letter", "rescission_notice", + "investment_agreement", + "valuation_adjustment_agreement", + "shareholder_resolution", + "power_of_attorney", + "legal_opinion", + "property_service_agreement", } def get_by_code(self, code): @@ -162,6 +169,46 @@ class LegalDocumentElementSchemaServiceTestCase(unittest.TestCase): self.assertFalse(percent_invalid["valid"]) self.assertTrue(any(item["field_key"] == "equity.percent" for item in percent_invalid["errors"])) + def test_intercompany_loan_schema_can_be_seeded_and_validated(self): + seeded = self.service.seed_default_element_schemas(self.admin_user, "intercompany_loan_agreement") + current = self.service.get_current_element_schema(self.member_user, "intercompany_loan_agreement") + + self.assertEqual(seeded["created_count"], 1) + self.assertEqual(current["document_type_code"], "intercompany_loan_agreement") + self.assertEqual( + [section["key"] for section in current["schema_json"]["sections"]], + [ + "parties", + "relationship_and_approval", + "loan_amount_and_purpose", + "interest_and_term", + "repayment_arrangements", + "guarantee_and_compliance", + "dispute_and_signature", + ], + ) + + result = self.service.validate_element_values( + self.member_user, + "intercompany_loan_agreement", + { + "party_a": {"name": "甲方公司"}, + "party_b": {"name": "乙方公司"}, + "relationship": {"description": "同一控制下关联企业"}, + "internal_approval": {"confirmation": "已完成董事会审批"}, + "loan": {"amount": "5000000", "purpose": "流动资金周转", "term": "12个月"}, + "fund": {"disbursement_account": "甲方对公账户", "receipt_confirmation": "已到账"}, + "interest": {"start_date": "2026-05-24", "rate_method": "年化3.5%", "payment_method": "按季度支付"}, + "repayment": {"method": "到期一次性还本付息", "plan": "12个月后结清", "account": "乙方对公账户"}, + "guarantee": {"method": "无担保"}, + "dispute_resolution": {"method": "诉讼"}, + "sign_date": "2026-05-24", + }, + ) + + self.assertTrue(result["valid"]) + self.assertEqual(result["errors"], []) + def test_valid_element_values_pass(self): self.service.seed_default_element_schemas(self.admin_user, "procurement_goods") diff --git a/backend/tests/test_legal_document_type_service.py b/backend/tests/test_legal_document_type_service.py index 9de3baad..3f4de1f7 100644 --- a/backend/tests/test_legal_document_type_service.py +++ b/backend/tests/test_legal_document_type_service.py @@ -73,7 +73,7 @@ class LegalDocumentTypeServiceTestCase(unittest.TestCase): industry="technology", ) - self.assertEqual(seeded["created_count"], 17) + self.assertEqual(seeded["created_count"], 18) self.assertEqual(seeded["existing_count"], 0) self.assertEqual(listed["total"], 2) self.assertEqual([item["code"] for item in listed["items"]], ["technical_service", "software_development"]) @@ -83,7 +83,7 @@ class LegalDocumentTypeServiceTestCase(unittest.TestCase): investment_list = self.service.list_document_types(self.member_user, category="investment-finance") self.assertEqual( [item["code"] for item in investment_list["items"]], - ["equity_transfer", "investment_agreement", "valuation_adjustment_agreement"], + ["equity_transfer", "investment_agreement", "intercompany_loan_agreement", "valuation_adjustment_agreement"], ) property_list = self.service.list_document_types(self.member_user, category="real-estate") self.assertEqual([item["code"] for item in property_list["items"]], ["lease_house", "property_service"]) diff --git a/frontend/src/app/documents/new/[type]/page.tsx b/frontend/src/app/documents/new/[type]/page.tsx index d8a0c060..4498ae51 100644 --- a/frontend/src/app/documents/new/[type]/page.tsx +++ b/frontend/src/app/documents/new/[type]/page.tsx @@ -76,6 +76,7 @@ const documentNameMap: Record = { nda_commercial: "保密协议", lease_house: "房屋租赁合同", equity_transfer: "股权转让协议", + intercompany_loan_agreement: "企业间借款合同", cooperation_framework: "合作框架协议", demand_letter: "催告函", rescission_notice: "解除合同通知书", diff --git a/frontend/src/app/documents/new/page.tsx b/frontend/src/app/documents/new/page.tsx index c624d84c..84f72b2a 100644 --- a/frontend/src/app/documents/new/page.tsx +++ b/frontend/src/app/documents/new/page.tsx @@ -57,6 +57,7 @@ const scenarioLabelMap: Record = { confidentiality: "商业保密", lease: "租赁履约", "equity-transfer": "股权交易", + "intercompany-loan": "企业间借款", cooperation: "合作框架", "demand-letter": "履约催告", "rescission-notice": "解除通知",