aria-code 4.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agents/__init__.py +32 -0
- agents/base.py +190 -0
- agents/deep/__init__.py +37 -0
- agents/deep/calibration_loop.py +144 -0
- agents/deep/critic.py +125 -0
- agents/deep/deepen.py +193 -0
- agents/deep/models.py +149 -0
- agents/deep/pipeline.py +164 -0
- agents/deep/quant_fusion.py +192 -0
- agents/deep/themes.py +95 -0
- agents/deep/tiers.py +106 -0
- agents/financial/__init__.py +10 -0
- agents/financial/catalyst.py +279 -0
- agents/financial/debate.py +145 -0
- agents/financial/earnings.py +303 -0
- agents/financial/fundamental.py +159 -0
- agents/financial/macro.py +99 -0
- agents/financial/news.py +207 -0
- agents/financial/risk.py +132 -0
- agents/financial/sector.py +279 -0
- agents/financial/synthesis.py +274 -0
- agents/financial/technical.py +258 -0
- agents/portfolio_agent.py +333 -0
- agents/realty/__init__.py +62 -0
- agents/realty/asset_diagnosis.py +150 -0
- agents/realty/business_match.py +165 -0
- agents/realty/cashflow_verify.py +208 -0
- agents/realty/contract_rules.py +209 -0
- agents/realty/energy_anomaly.py +188 -0
- agents/realty/exit_settlement.py +207 -0
- agents/realty/fulfillment_risk.py +205 -0
- agents/realty/ops_optimize.py +159 -0
- agents/realty/revenue_share.py +214 -0
- agents/registry.py +144 -0
- agents/sports/__init__.py +0 -0
- agents/sports/football_agent.py +169 -0
- agents/team.py +289 -0
- aliyun_data_client.py +660 -0
- apps/README.md +12 -0
- apps/__init__.py +2 -0
- apps/channels/README.md +15 -0
- apps/cli/README.md +13 -0
- apps/cli/__init__.py +2 -0
- apps/cli/bootstrap.py +99 -0
- apps/cli/codegen_paths.py +29 -0
- apps/cli/commands/__init__.py +16 -0
- apps/cli/commands/analysis_cmds.py +288 -0
- apps/cli/commands/backtest_cmds.py +1887 -0
- apps/cli/commands/broker_cmds.py +1154 -0
- apps/cli/commands/business_workflow_cmds.py +289 -0
- apps/cli/commands/catalog.py +84 -0
- apps/cli/commands/data_cmds.py +405 -0
- apps/cli/commands/diagnostic_cmds.py +179 -0
- apps/cli/commands/diagnostic_ops_cmds.py +696 -0
- apps/cli/commands/finance_render.py +12 -0
- apps/cli/commands/market.py +399 -0
- apps/cli/commands/market_cmds.py +1276 -0
- apps/cli/commands/market_context.py +425 -0
- apps/cli/commands/market_render.py +7 -0
- apps/cli/commands/model_cmds.py +1579 -0
- apps/cli/commands/ops_cmds.py +668 -0
- apps/cli/commands/portfolio_cmds.py +962 -0
- apps/cli/commands/report.py +377 -0
- apps/cli/commands/scaffold_templates.py +617 -0
- apps/cli/commands/session_cmds.py +179 -0
- apps/cli/commands/session_ux_cmds.py +280 -0
- apps/cli/commands/team.py +588 -0
- apps/cli/commands/team_render.py +8 -0
- apps/cli/commands/ui_cmds.py +358 -0
- apps/cli/commands/workflow_cmds.py +279 -0
- apps/cli/commands/workspace_cmds.py +1414 -0
- apps/cli/config_paths.py +70 -0
- apps/cli/config_store.py +61 -0
- apps/cli/deterministic.py +122 -0
- apps/cli/direct.py +48 -0
- apps/cli/github_app_auth.py +135 -0
- apps/cli/handlers/__init__.py +11 -0
- apps/cli/handlers/broker_handlers.py +122 -0
- apps/cli/handlers/chart_handlers.py +1309 -0
- apps/cli/handlers/market_handlers.py +2509 -0
- apps/cli/handlers/realty_handlers.py +114 -0
- apps/cli/handlers/strategy_advice.py +82 -0
- apps/cli/hooks.py +180 -0
- apps/cli/i18n.py +284 -0
- apps/cli/intent.py +136 -0
- apps/cli/intent_router.py +217 -0
- apps/cli/lifecycle_hooks.py +48 -0
- apps/cli/main.py +29 -0
- apps/cli/market_metadata.py +135 -0
- apps/cli/market_universe.py +265 -0
- apps/cli/message_processing.py +257 -0
- apps/cli/plan_mode.py +139 -0
- apps/cli/plotly_html.py +15 -0
- apps/cli/prediction_feedback.py +202 -0
- apps/cli/preflight.py +497 -0
- apps/cli/project_aria.py +60 -0
- apps/cli/prompts/__init__.py +0 -0
- apps/cli/prompts/coding.py +658 -0
- apps/cli/prompts/system_prompts.py +531 -0
- apps/cli/prompts/ui.py +434 -0
- apps/cli/providers/__init__.py +1 -0
- apps/cli/providers/base.py +271 -0
- apps/cli/providers/chat_routing.py +80 -0
- apps/cli/providers/llm/__init__.py +1 -0
- apps/cli/providers/llm/ollama_stream.py +1170 -0
- apps/cli/providers/llm/sse_stream.py +216 -0
- apps/cli/providers/runtime_bridge.py +185 -0
- apps/cli/runtime_consumer.py +489 -0
- apps/cli/session_export.py +87 -0
- apps/cli/session_jsonl.py +207 -0
- apps/cli/session_store.py +112 -0
- apps/cli/todo_tracker.py +190 -0
- apps/cli/tools/__init__.py +40 -0
- apps/cli/tools/context.py +46 -0
- apps/cli/tools/file_tools.py +112 -0
- apps/cli/tools/market_tools.py +549 -0
- apps/cli/tools/notebook_tools.py +111 -0
- apps/cli/tools/system_tools.py +669 -0
- apps/cli/tools/write_tools.py +715 -0
- apps/cli/tradingview_bridge.py +434 -0
- apps/cli/update_check.py +152 -0
- apps/cli/utils/__init__.py +0 -0
- apps/cli/utils/market_detect.py +1578 -0
- apps/daemon/README.md +14 -0
- apps/vscode/README.md +115 -0
- apps/vscode/package.json +70 -0
- aria_cli.py +11636 -0
- aria_code-4.1.3.dist-info/METADATA +952 -0
- aria_code-4.1.3.dist-info/RECORD +284 -0
- aria_code-4.1.3.dist-info/WHEEL +5 -0
- aria_code-4.1.3.dist-info/entry_points.txt +2 -0
- aria_code-4.1.3.dist-info/licenses/LICENSE +121 -0
- aria_code-4.1.3.dist-info/top_level.txt +50 -0
- aria_daemon.py +1295 -0
- aria_feishu_bot.py +1359 -0
- aria_relay_client.py +182 -0
- aria_relay_server.py +405 -0
- aria_telegram_bot.py +202 -0
- ariarc.py +328 -0
- artifacts.py +491 -0
- backtest_report.py +472 -0
- brokers/__init__.py +72 -0
- brokers/base.py +207 -0
- brokers/capabilities.py +264 -0
- brokers/cn/__init__.py +10 -0
- brokers/cn/easytrader_broker.py +193 -0
- brokers/cn/futu_broker.py +194 -0
- brokers/cn/longbridge_broker.py +190 -0
- brokers/cn/tiger_broker.py +196 -0
- brokers/cn/xtquant_broker.py +175 -0
- brokers/config.py +364 -0
- brokers/intl/__init__.py +5 -0
- brokers/intl/alpaca_broker.py +183 -0
- brokers/intl/ibkr_broker.py +215 -0
- brokers/intl/webull_broker.py +156 -0
- brokers/paper_broker.py +259 -0
- brokers/planning.py +296 -0
- brokers/registry.py +181 -0
- brokers/trading.py +237 -0
- change_store.py +127 -0
- command_safety.py +19 -0
- computer_use_tools.py +504 -0
- dashboard_generator.py +578 -0
- data_analysis_tools.py +808 -0
- data_cleaner.py +483 -0
- data_service.py +481 -0
- datasources/__init__.py +23 -0
- datasources/base.py +166 -0
- datasources/router.py +221 -0
- datasources/sources/__init__.py +15 -0
- datasources/sources/akshare_source.py +269 -0
- datasources/sources/alpha_vantage_source.py +202 -0
- datasources/sources/edgar_source.py +218 -0
- datasources/sources/finnhub_source.py +197 -0
- datasources/sources/fred_source.py +219 -0
- datasources/sources/tushare_source.py +141 -0
- datasources/sources/web_scraper_source.py +278 -0
- datasources/sources/world_bank_source.py +205 -0
- datasources/sources/yfinance_source.py +152 -0
- demo_player.py +204 -0
- doctor.py +508 -0
- file_analysis_tools.py +734 -0
- finance_formulas.py +389 -0
- football_data_client.py +1670 -0
- intent_classifier.py +358 -0
- local_finance_tools.py +3221 -0
- local_llm_provider.py +552 -0
- macro_tools.py +368 -0
- market_data_client.py +1899 -0
- mcp_client.py +506 -0
- memory_manager.py +245 -0
- model_capability.py +416 -0
- notification_tools.py +248 -0
- packages/__init__.py +23 -0
- packages/aria_agents/__init__.py +5 -0
- packages/aria_agents/manifest.py +69 -0
- packages/aria_core/__init__.py +34 -0
- packages/aria_core/architecture.py +192 -0
- packages/aria_core/export.py +124 -0
- packages/aria_core/manifest.py +65 -0
- packages/aria_infra/__init__.py +15 -0
- packages/aria_infra/arthera.py +52 -0
- packages/aria_infra/doctor.py +246 -0
- packages/aria_infra/product.py +37 -0
- packages/aria_mcp/__init__.py +25 -0
- packages/aria_mcp/bridge.py +38 -0
- packages/aria_mcp/config.py +97 -0
- packages/aria_mcp/tools.py +61 -0
- packages/aria_sdk/__init__.py +19 -0
- packages/aria_sdk/client.py +396 -0
- packages/aria_sdk/providers.py +70 -0
- packages/aria_sdk/streaming.py +73 -0
- packages/aria_sdk/types.py +86 -0
- packages/aria_services/__init__.py +55 -0
- packages/aria_services/context.py +258 -0
- packages/aria_services/data.py +11 -0
- packages/aria_services/provider_health.py +189 -0
- packages/aria_services/registry.py +213 -0
- packages/aria_services/usage.py +138 -0
- packages/aria_skills/__init__.py +5 -0
- packages/aria_skills/registry.py +59 -0
- packages/aria_tools/__init__.py +5 -0
- packages/aria_tools/registry.py +128 -0
- packages/quant_engine/__init__.py +6 -0
- packages/quant_engine/sports/__init__.py +72 -0
- packages/quant_engine/sports/calibrator.py +353 -0
- packages/quant_engine/sports/dixon_coles.py +234 -0
- packages/quant_engine/sports/elo.py +299 -0
- packages/quant_engine/sports/form.py +188 -0
- packages/quant_engine/sports/h2h.py +195 -0
- packages/quant_engine/sports/ml_model.py +354 -0
- packages/quant_engine/sports/predictor.py +311 -0
- packages/quant_engine/sports/tracker.py +664 -0
- packages/quant_engine/stochastic/__init__.py +27 -0
- packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
- packages/quant_engine/stochastic/ito_calculus.py +477 -0
- packages/quant_engine/stochastic/kelly_criterion.py +181 -0
- packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
- packages/quant_engine/stochastic/options_pricing.py +573 -0
- packages/quant_engine/stochastic/stochastic_processes.py +90 -0
- plan_utils.py +194 -0
- plugin_loader.py +328 -0
- portfolio_ledger.py +262 -0
- privacy/__init__.py +5 -0
- privacy/feedback.py +123 -0
- project_tools.py +525 -0
- providers/__init__.py +30 -0
- providers/llm/__init__.py +19 -0
- providers/llm/anthropic.py +184 -0
- providers/llm/base.py +139 -0
- providers/llm/ollama.py +128 -0
- providers/llm/openai_compat.py +282 -0
- providers/llm/registry.py +358 -0
- realty_data_tools.py +659 -0
- report_generator.py +1314 -0
- runtime/__init__.py +103 -0
- runtime/agent_loop.py +1183 -0
- runtime/approval.py +51 -0
- runtime/events.py +102 -0
- runtime/gateway.py +128 -0
- runtime/lsp.py +346 -0
- runtime/subagent.py +258 -0
- runtime/tool_executor.py +104 -0
- runtime/tool_policy.py +106 -0
- safety/__init__.py +21 -0
- safety/permissions.py +275 -0
- setup_wizard.py +653 -0
- strategy_vault.py +420 -0
- ui/__init__.py +100 -0
- ui/banner.py +310 -0
- ui/completer.py +391 -0
- ui/console.py +271 -0
- ui/image_render.py +243 -0
- ui/input_box.py +376 -0
- ui/picker.py +195 -0
- ui/render/__init__.py +11 -0
- ui/render/finance.py +1480 -0
- ui/render/market.py +225 -0
- ui/render/output.py +681 -0
- ui/render/team.py +346 -0
- ui/robot.py +235 -0
- workspace/__init__.py +6 -0
- workspace/files.py +170 -0
- workspace/verify.py +113 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agents/realty/contract_rules.py — 合同规则 Agent
|
|
3
|
+
=================================================
|
|
4
|
+
将业务谈判结果转化为合同条款和分账规则草案。
|
|
5
|
+
|
|
6
|
+
输入数据(data dict keys):
|
|
7
|
+
negotiation — 谈判结果摘要(保底/分润比例/结算周期/退出条件等)
|
|
8
|
+
asset_info — 资产基础信息
|
|
9
|
+
operator_info — 经营方信息(资质/历史数据等)
|
|
10
|
+
|
|
11
|
+
输出:
|
|
12
|
+
analysis — 合同条款草案文本
|
|
13
|
+
signal — BUY=条款清晰可执行 / HOLD=需补充条款 / SELL=有重大风险条款
|
|
14
|
+
key_points — 关键条款摘要(保底金额/分润比例/结算周期/违约条款)
|
|
15
|
+
"""
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from decimal import Decimal, ROUND_HALF_UP
|
|
19
|
+
from typing import Any, Dict, List, Optional
|
|
20
|
+
from ..base import BaseAgent, AgentResult
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ContractRulesAgent(BaseAgent):
|
|
24
|
+
name = "contract_rules"
|
|
25
|
+
description = "合同规则生成:将谈判结果结构化为可执行的合同条款和分账规则草案"
|
|
26
|
+
|
|
27
|
+
_SYSTEM = (
|
|
28
|
+
"你是一名专业的不动产运营合同起草顾问。\n"
|
|
29
|
+
"你的任务是根据谈判结果,生成结构化的合同条款草案,包含:\n"
|
|
30
|
+
" 1. 经营权共创模式说明(资产方不转让产权,基于使用权获得收益)\n"
|
|
31
|
+
" 2. 收益分配规则:保底收益、流水分润计算方式、阶梯分成规则\n"
|
|
32
|
+
" 3. 结算周期与结算方式\n"
|
|
33
|
+
" 4. 保证金条款(金额、用途、退还条件)\n"
|
|
34
|
+
" 5. 风险准备金(比例、用途)\n"
|
|
35
|
+
" 6. 平台服务费(比例或固定金额)\n"
|
|
36
|
+
" 7. 退出条款(提前退出违约金、清算顺序)\n"
|
|
37
|
+
" 8. 开业义务与履约要求\n\n"
|
|
38
|
+
"输出要求:\n"
|
|
39
|
+
"- 每个条款必须包含:条款名称、具体数值、计算公式(如适用)\n"
|
|
40
|
+
"- 标注 [系统可执行] / [需人工确认] / [建议律师审核]\n"
|
|
41
|
+
"- 最后给出:合同风险评级 [低/中/高] 及主要风险点"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
async def analyze(self, symbol: str, data: Dict[str, Any]) -> AgentResult:
|
|
45
|
+
nego = data.get("negotiation", {})
|
|
46
|
+
asset = data.get("asset_info", {})
|
|
47
|
+
operator = data.get("operator_info", {})
|
|
48
|
+
|
|
49
|
+
# 解析谈判关键数值(兼容多种字段命名)
|
|
50
|
+
guaranteed = nego.get("guaranteed_amount",
|
|
51
|
+
nego.get("guaranteed_monthly", 0))
|
|
52
|
+
revenue_share = nego.get("revenue_share_pct", 0)
|
|
53
|
+
base_revenue = nego.get("base_revenue",
|
|
54
|
+
nego.get("revenue_share_base", 0))
|
|
55
|
+
tiered_rules = nego.get("tiered_rules", [])
|
|
56
|
+
settle_cycle = nego.get("settlement_cycle", "monthly")
|
|
57
|
+
# 保证金:直接金额 > deposit_months × 保底 > 0
|
|
58
|
+
deposit_months = nego.get("deposit_months", 0)
|
|
59
|
+
deposit = nego.get("deposit_amount",
|
|
60
|
+
nego.get("deposit",
|
|
61
|
+
guaranteed * deposit_months if deposit_months else 0))
|
|
62
|
+
risk_reserve = nego.get("risk_reserve_pct", 3)
|
|
63
|
+
platform_fee = nego.get("platform_fee_pct", 5)
|
|
64
|
+
contract_years= nego.get("contract_years", 1)
|
|
65
|
+
exit_penalty = nego.get("exit_penalty_months", 3)
|
|
66
|
+
|
|
67
|
+
user_prompt = (
|
|
68
|
+
f"谈判结果:\n"
|
|
69
|
+
f" 保底收益: {guaranteed:,}元/月\n"
|
|
70
|
+
f" 流水分润: 月流水超过{base_revenue:,}元后按{revenue_share}%分润\n"
|
|
71
|
+
f" 阶梯规则: {tiered_rules or '无阶梯'}\n"
|
|
72
|
+
f" 结算周期: {settle_cycle}\n"
|
|
73
|
+
f" 保证金: {deposit:,}元\n"
|
|
74
|
+
f" 风险准备金: 流水的{risk_reserve}%\n"
|
|
75
|
+
f" 平台服务费: 流水的{platform_fee}%\n"
|
|
76
|
+
f" 合同年限: {contract_years}年\n"
|
|
77
|
+
f" 提前退出违约: {exit_penalty}个月保底金额\n\n"
|
|
78
|
+
f"资产信息: {asset.get('name','未命名')} ({asset.get('area',0)}m²)\n"
|
|
79
|
+
f"经营方: {operator.get('name','未知')} "
|
|
80
|
+
f"(行业: {operator.get('industry','未知')})\n\n"
|
|
81
|
+
"请生成完整的合同条款草案。"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
analysis = await self._call_llm(self._SYSTEM, user_prompt, max_tokens=1000)
|
|
85
|
+
if not analysis:
|
|
86
|
+
analysis = _template_contract(nego, asset, operator)
|
|
87
|
+
|
|
88
|
+
# 结构化规则供系统执行
|
|
89
|
+
structured = _build_structured_rules(nego)
|
|
90
|
+
signal = _contract_signal(nego)
|
|
91
|
+
confidence = _contract_confidence(nego)
|
|
92
|
+
key_points = _contract_key_points(nego, structured)
|
|
93
|
+
|
|
94
|
+
return AgentResult(
|
|
95
|
+
agent = self.name,
|
|
96
|
+
symbol = symbol,
|
|
97
|
+
analysis = analysis,
|
|
98
|
+
confidence = confidence,
|
|
99
|
+
signal = signal,
|
|
100
|
+
key_points = key_points,
|
|
101
|
+
data_used = {"structured_rules": structured, "negotiation": nego},
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# ── 辅助函数 ──────────────────────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
def _build_structured_rules(nego: Dict) -> Dict:
|
|
108
|
+
"""生成系统可直接执行的分账规则 JSON(兼容多种字段命名)"""
|
|
109
|
+
_g = nego.get("guaranteed_amount", nego.get("guaranteed_monthly", 0))
|
|
110
|
+
guaranteed = Decimal(str(_g))
|
|
111
|
+
share_pct = Decimal(str(nego.get("revenue_share_pct", 0)))
|
|
112
|
+
base_revenue = Decimal(str(nego.get("base_revenue", nego.get("revenue_share_base", 0))))
|
|
113
|
+
risk_reserve = Decimal(str(nego.get("risk_reserve_pct", 3)))
|
|
114
|
+
platform_fee = Decimal(str(nego.get("platform_fee_pct", 5)))
|
|
115
|
+
_dm = nego.get("deposit_months", 0)
|
|
116
|
+
deposit = Decimal(str(nego.get("deposit_amount",
|
|
117
|
+
nego.get("deposit",
|
|
118
|
+
float(_g) * _dm if _dm else 0))))
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
"guaranteed_monthly": float(guaranteed),
|
|
122
|
+
"revenue_share_pct": float(share_pct),
|
|
123
|
+
"revenue_share_base": float(base_revenue),
|
|
124
|
+
"risk_reserve_pct": float(risk_reserve),
|
|
125
|
+
"platform_fee_pct": float(platform_fee),
|
|
126
|
+
"deposit_amount": float(deposit),
|
|
127
|
+
"settlement_cycle": nego.get("settlement_cycle", "monthly"),
|
|
128
|
+
"tiered_rules": nego.get("tiered_rules", []),
|
|
129
|
+
"contract_years": nego.get("contract_years", 1),
|
|
130
|
+
"exit_penalty_months": nego.get("exit_penalty_months", 3),
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _contract_signal(nego: Dict) -> str:
|
|
135
|
+
issues = 0
|
|
136
|
+
if not (nego.get("guaranteed_amount") or nego.get("guaranteed_monthly")): issues += 1
|
|
137
|
+
if not nego.get("revenue_share_pct"): issues += 1
|
|
138
|
+
if not (nego.get("deposit") or nego.get("deposit_amount") or nego.get("deposit_months")): issues += 1
|
|
139
|
+
if not nego.get("settlement_cycle"): issues += 1
|
|
140
|
+
if not nego.get("contract_years"): issues += 1
|
|
141
|
+
|
|
142
|
+
if issues == 0: return "BUY"
|
|
143
|
+
if issues <= 2: return "HOLD"
|
|
144
|
+
return "SELL"
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _contract_confidence(nego: Dict) -> float:
|
|
148
|
+
keys_pairs = [
|
|
149
|
+
("guaranteed_amount", "guaranteed_monthly"),
|
|
150
|
+
("revenue_share_pct",),
|
|
151
|
+
("base_revenue", "revenue_share_base"),
|
|
152
|
+
("deposit", "deposit_amount", "deposit_months"),
|
|
153
|
+
("settlement_cycle",),
|
|
154
|
+
("contract_years",),
|
|
155
|
+
]
|
|
156
|
+
filled = sum(1 for kp in keys_pairs if any(nego.get(k) for k in kp))
|
|
157
|
+
return round(0.4 + 0.1 * filled, 2)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _contract_key_points(nego: Dict, rules: Dict) -> List[str]:
|
|
161
|
+
pts = []
|
|
162
|
+
g = rules.get("guaranteed_monthly", 0)
|
|
163
|
+
s = rules.get("revenue_share_pct", 0)
|
|
164
|
+
b = rules.get("revenue_share_base", 0)
|
|
165
|
+
d = rules.get("deposit_amount", 0)
|
|
166
|
+
c = rules.get("settlement_cycle", "monthly")
|
|
167
|
+
yrs = rules.get("contract_years", 1)
|
|
168
|
+
|
|
169
|
+
if g: pts.append(f"保底收益: {g:,.0f}元/月(年合计 {g*12:,.0f}元)")
|
|
170
|
+
if s: pts.append(f"流水分润: 超过{b:,.0f}元后按{s}%分润")
|
|
171
|
+
if d: pts.append(f"保证金: {d:,.0f}元(合同结束后退还)")
|
|
172
|
+
if c: pts.append(f"结算周期: {c}")
|
|
173
|
+
if yrs: pts.append(f"合同年限: {yrs}年,到期可续签")
|
|
174
|
+
return pts[:5]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _template_contract(nego: Dict, asset: Dict, operator: Dict) -> str:
|
|
178
|
+
g = nego.get("guaranteed_amount", nego.get("guaranteed_monthly", 0))
|
|
179
|
+
s = nego.get("revenue_share_pct", 0)
|
|
180
|
+
b = nego.get("base_revenue", nego.get("revenue_share_base", 0))
|
|
181
|
+
dm = nego.get("deposit_months", 0)
|
|
182
|
+
d = nego.get("deposit_amount", nego.get("deposit", g * dm if dm else 0))
|
|
183
|
+
rf = nego.get("risk_reserve_pct", 3)
|
|
184
|
+
pf = nego.get("platform_fee_pct", 5)
|
|
185
|
+
ep = nego.get("exit_penalty_months", 3)
|
|
186
|
+
c = nego.get("settlement_cycle", "月结")
|
|
187
|
+
y = nego.get("contract_years", 1)
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
f"经营权共创合同规则草案(模板)\n"
|
|
191
|
+
f"{'='*40}\n"
|
|
192
|
+
f"资产方:{asset.get('owner','待确认')} 经营方:{operator.get('name','待确认')}\n"
|
|
193
|
+
f"标的资产:{asset.get('name','未命名')} ({asset.get('area',0)}m²)\n\n"
|
|
194
|
+
f"第一条 收益分配规则\n"
|
|
195
|
+
f" 1.1 保底收益: {g:,}元/月 [系统可执行]\n"
|
|
196
|
+
f" 1.2 流水分润: 月流水超过{b:,}元后,资产方按{s}%分润 [系统可执行]\n"
|
|
197
|
+
f" 1.3 平台服务费: 月流水的{pf}% [系统可执行]\n"
|
|
198
|
+
f" 1.4 风险准备金: 月流水的{rf}%,累计至3个月保底额度后暂停 [系统可执行]\n\n"
|
|
199
|
+
f"第二条 结算条款\n"
|
|
200
|
+
f" 2.1 结算周期: {c} [系统可执行]\n"
|
|
201
|
+
f" 2.2 保底补足: 当月流水分润低于保底金额时,由经营方补足差额 [需人工确认]\n\n"
|
|
202
|
+
f"第三条 保证金\n"
|
|
203
|
+
f" 3.1 保证金: {d:,}元,签约时一次性缴纳 [需人工确认]\n"
|
|
204
|
+
f" 3.2 用途: 用于弥补违约、欠费等损失 [系统可执行]\n\n"
|
|
205
|
+
f"第四条 合同期限与退出\n"
|
|
206
|
+
f" 4.1 合同年限: {y}年 [系统可执行]\n"
|
|
207
|
+
f" 4.2 提前退出违约金: {ep}个月保底金额(即{g*ep:,}元)[需人工确认]\n\n"
|
|
208
|
+
f"【风险评级: {'低' if g>0 and d>0 else '中'}】[建议律师审核]"
|
|
209
|
+
)
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agents/realty/energy_anomaly.py — 能耗异常 Agent
|
|
3
|
+
=================================================
|
|
4
|
+
用水电、门禁、停车、客流判断经营状态,识别:空置/低效/超范围/欠费/异常经营。
|
|
5
|
+
|
|
6
|
+
输入数据(data dict keys):
|
|
7
|
+
energy_records — 水电用量历史(按日/周/月)
|
|
8
|
+
access_records — 门禁/访客记录
|
|
9
|
+
parking_records — 停车记录
|
|
10
|
+
foot_traffic — 客流数据
|
|
11
|
+
revenue_data — 对应期营业流水(用于交叉验证)
|
|
12
|
+
benchmarks — 同业基准值(可选)
|
|
13
|
+
|
|
14
|
+
输出:
|
|
15
|
+
analysis — 能耗分析报告
|
|
16
|
+
signal — BUY=正常 / HOLD=轻度异常 / SELL=严重异常/疑似空置
|
|
17
|
+
key_points — 异常指标清单
|
|
18
|
+
"""
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from typing import Any, Dict, List
|
|
22
|
+
from ..base import BaseAgent, AgentResult
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class EnergyAnomalyAgent(BaseAgent):
|
|
26
|
+
name = "energy_anomaly"
|
|
27
|
+
description = "能耗异常:交叉分析水电、门禁、客流与流水,识别空置/低效/异常经营"
|
|
28
|
+
|
|
29
|
+
_SYSTEM = (
|
|
30
|
+
"你是一名商业空间运营监控专家,擅长通过能耗和空间数据识别异常经营行为。\n"
|
|
31
|
+
"请对能耗分析结果进行解读:\n"
|
|
32
|
+
" 1. 水电用量是否与营业流水匹配(高流水应有高能耗)\n"
|
|
33
|
+
" 2. 门禁/客流记录是否与营业时段一致\n"
|
|
34
|
+
" 3. 是否存在非营业时段用电(可能夜间经营未申报)\n"
|
|
35
|
+
" 4. 能耗趋势分析(是否逐月下降,可能经营在减少)\n"
|
|
36
|
+
" 5. 综合判断:[正常经营] / [低效经营] / [空置] / [疑似违规经营] / [超范围经营]\n"
|
|
37
|
+
" 6. 处置建议(巡检、整改、补缴水电费等)"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
async def analyze(self, symbol: str, data: Dict[str, Any]) -> AgentResult:
|
|
41
|
+
energy = data.get("energy_records", {})
|
|
42
|
+
access = data.get("access_records", {})
|
|
43
|
+
parking = data.get("parking_records", {})
|
|
44
|
+
traffic = data.get("foot_traffic", {})
|
|
45
|
+
revenue = data.get("revenue_data", {})
|
|
46
|
+
bench = data.get("benchmarks", {})
|
|
47
|
+
|
|
48
|
+
check = _analyze_energy(energy, access, parking, traffic, revenue, bench)
|
|
49
|
+
|
|
50
|
+
user_prompt = (
|
|
51
|
+
f"能耗分析数据:\n"
|
|
52
|
+
f" 本期用电: {energy.get('electricity_kwh',0):.1f} kWh "
|
|
53
|
+
f" 用水: {energy.get('water_tons',0):.1f} 吨\n"
|
|
54
|
+
f" 环比变化: 用电{check['elec_change_pct']:+.1f}% 用水{check['water_change_pct']:+.1f}%\n"
|
|
55
|
+
f" 门禁进出: {access.get('entry_count',0)}次/期 停车: {parking.get('vehicle_count',0)}辆/期\n"
|
|
56
|
+
f" 客流量: {traffic.get('total_visits',0)}人次\n"
|
|
57
|
+
f" 营业流水: {revenue.get('declared',0):,.2f}元\n"
|
|
58
|
+
f" 每千元流水能耗: {check['energy_per_revenue']:.2f} kWh\n"
|
|
59
|
+
f" 基准能耗/千元: {bench.get('energy_per_1k_revenue', 2.5):.2f} kWh\n\n"
|
|
60
|
+
f"发现异常:\n"
|
|
61
|
+
+ "\n".join(f" - {a}" for a in check["anomalies"])
|
|
62
|
+
+ "\n\n请完成能耗异常分析报告。"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
analysis = await self._call_llm(self._SYSTEM, user_prompt, max_tokens=600)
|
|
66
|
+
if not analysis:
|
|
67
|
+
analysis = _template_energy(check, energy, revenue)
|
|
68
|
+
|
|
69
|
+
signal = _energy_signal(check)
|
|
70
|
+
confidence = _energy_confidence(check)
|
|
71
|
+
key_points = _energy_key_points(check, energy)
|
|
72
|
+
|
|
73
|
+
return AgentResult(
|
|
74
|
+
agent = self.name,
|
|
75
|
+
symbol = symbol,
|
|
76
|
+
analysis = analysis,
|
|
77
|
+
confidence = confidence,
|
|
78
|
+
signal = signal,
|
|
79
|
+
key_points = key_points,
|
|
80
|
+
data_used = {"energy_check": check},
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# ── 核验逻辑 ──────────────────────────────────────────────────────────────────
|
|
85
|
+
|
|
86
|
+
def _analyze_energy(
|
|
87
|
+
energy: Dict, access: Dict, parking: Dict,
|
|
88
|
+
traffic: Dict, revenue: Dict, bench: Dict,
|
|
89
|
+
) -> Dict:
|
|
90
|
+
elec = energy.get("electricity_kwh", 0)
|
|
91
|
+
elec_prev = energy.get("prev_electricity_kwh", elec)
|
|
92
|
+
water = energy.get("water_tons", 0)
|
|
93
|
+
water_prev= energy.get("prev_water_tons", water)
|
|
94
|
+
rev = revenue.get("declared", 0)
|
|
95
|
+
entries = access.get("entry_count", 0)
|
|
96
|
+
vehicles = parking.get("vehicle_count", 0)
|
|
97
|
+
visits = traffic.get("total_visits", 0)
|
|
98
|
+
|
|
99
|
+
elec_change = (elec - elec_prev) / elec_prev * 100 if elec_prev else 0
|
|
100
|
+
water_change = (water - water_prev) / water_prev * 100 if water_prev else 0
|
|
101
|
+
|
|
102
|
+
# 每千元流水能耗
|
|
103
|
+
energy_per_rev = elec / (rev / 1000) if rev > 0 else 0
|
|
104
|
+
bench_per_rev = bench.get("energy_per_1k_revenue", 2.5)
|
|
105
|
+
|
|
106
|
+
anomalies = []
|
|
107
|
+
|
|
108
|
+
# 空置判断(低能耗 + 低流水 + 低门禁)
|
|
109
|
+
if elec < 10 and rev < 1000 and entries < 5:
|
|
110
|
+
anomalies.append("水电用量极低且无门禁记录,疑似空置状态")
|
|
111
|
+
|
|
112
|
+
# 能耗与流水不匹配
|
|
113
|
+
if rev > 0 and energy_per_rev > bench_per_rev * 3:
|
|
114
|
+
anomalies.append(f"能耗/流水比异常偏高({energy_per_rev:.2f}),可能有黑账")
|
|
115
|
+
elif rev > 0 and energy_per_rev < bench_per_rev * 0.3 and elec > 50:
|
|
116
|
+
anomalies.append("高能耗配合低流水,疑似流水漏报或私账")
|
|
117
|
+
|
|
118
|
+
# 能耗持续下降
|
|
119
|
+
if elec_change < -30:
|
|
120
|
+
anomalies.append(f"用电量环比下降{abs(elec_change):.1f}%,经营规模可能在萎缩")
|
|
121
|
+
|
|
122
|
+
# 非营业时段用电(能耗数据需细化到时段)
|
|
123
|
+
night_elec = energy.get("night_electricity_kwh", 0)
|
|
124
|
+
if night_elec > elec * 0.4:
|
|
125
|
+
anomalies.append(f"夜间用电占比{night_elec/elec*100:.1f}%偏高,可能存在夜间未申报经营")
|
|
126
|
+
|
|
127
|
+
# 门禁/客流 vs 流水
|
|
128
|
+
if visits > 0 and rev > 0:
|
|
129
|
+
revenue_per_visit = rev / visits
|
|
130
|
+
bench_rpv = bench.get("revenue_per_visit", 50)
|
|
131
|
+
if revenue_per_visit < bench_rpv * 0.3:
|
|
132
|
+
anomalies.append(f"人均消费{revenue_per_visit:.1f}元/人远低于基准{bench_rpv}元,流水疑似偏低")
|
|
133
|
+
|
|
134
|
+
# 水费欠缴
|
|
135
|
+
if energy.get("water_arrears", 0) > 0:
|
|
136
|
+
anomalies.append(f"水费欠缴: {energy['water_arrears']:,.2f}元")
|
|
137
|
+
if energy.get("electricity_arrears", 0) > 0:
|
|
138
|
+
anomalies.append(f"电费欠缴: {energy['electricity_arrears']:,.2f}元")
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
"elec_kwh": elec,
|
|
142
|
+
"water_tons": water,
|
|
143
|
+
"elec_change_pct": elec_change,
|
|
144
|
+
"water_change_pct": water_change,
|
|
145
|
+
"energy_per_revenue": energy_per_rev,
|
|
146
|
+
"bench_per_revenue": bench_per_rev,
|
|
147
|
+
"entries": entries,
|
|
148
|
+
"vehicles": vehicles,
|
|
149
|
+
"visits": visits,
|
|
150
|
+
"anomalies": anomalies,
|
|
151
|
+
"anomaly_count": len(anomalies),
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _energy_signal(check: Dict) -> str:
|
|
156
|
+
n = check.get("anomaly_count", 0)
|
|
157
|
+
if n == 0: return "BUY"
|
|
158
|
+
if n == 1: return "HOLD"
|
|
159
|
+
if n == 2: return "SELL"
|
|
160
|
+
return "STRONG_SELL"
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _energy_confidence(check: Dict) -> float:
|
|
164
|
+
sources = sum(1 for k in ["elec_kwh", "entries", "visits"] if check.get(k, 0) > 0)
|
|
165
|
+
return round(min(0.9, 0.5 + 0.15 * sources), 2)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _energy_key_points(check: Dict, energy: Dict) -> List[str]:
|
|
169
|
+
pts = [f"用电 {check['elec_kwh']:.1f} kWh(环比{check['elec_change_pct']:+.1f}%)"
|
|
170
|
+
f" 用水 {check['water_tons']:.1f} 吨"]
|
|
171
|
+
pts.append(f"门禁进出 {check['entries']} 次 客流 {check['visits']} 人次")
|
|
172
|
+
for a in check["anomalies"][:3]:
|
|
173
|
+
pts.append(f"异常: {a}")
|
|
174
|
+
return pts[:5]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _template_energy(check: Dict, energy: Dict, revenue: Dict) -> str:
|
|
178
|
+
status = "正常" if check["anomaly_count"] == 0 else f"发现 {check['anomaly_count']} 项异常"
|
|
179
|
+
return (
|
|
180
|
+
f"能耗异常分析(模板):\n"
|
|
181
|
+
f" 用电: {check['elec_kwh']:.1f} kWh 用水: {check['water_tons']:.1f} 吨\n"
|
|
182
|
+
f" 门禁: {check['entries']}次 客流: {check['visits']}人次\n"
|
|
183
|
+
f" 营业流水: {revenue.get('declared',0):,.2f}元\n"
|
|
184
|
+
f" 每千元能耗: {check['energy_per_revenue']:.2f} kWh(基准{check['bench_per_revenue']:.2f})\n"
|
|
185
|
+
f" 核验状态: {status}\n"
|
|
186
|
+
+ (" 异常项目:\n" + "\n".join(f" • {a}" for a in check["anomalies"])
|
|
187
|
+
if check["anomalies"] else " 无异常")
|
|
188
|
+
)
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agents/realty/exit_settlement.py — 退出清算 Agent
|
|
3
|
+
==================================================
|
|
4
|
+
项目到期、提前终止或换经营方时,生成清算方案。
|
|
5
|
+
|
|
6
|
+
输入数据(data dict keys):
|
|
7
|
+
project_info — 项目基本信息(合同期限/实际开始结束时间)
|
|
8
|
+
financials — 财务数据(未结收入/欠费/保证金/预收款/违约情况)
|
|
9
|
+
asset_condition — 资产现状(装修状态/设备清单/改造情况)
|
|
10
|
+
exit_reason — 退出原因(到期/提前/违约/经营失败/换经营方)
|
|
11
|
+
|
|
12
|
+
输出:
|
|
13
|
+
analysis — 清算方案草案
|
|
14
|
+
signal — BUY=清算顺利无纠纷 / HOLD=有待确认项 / SELL=存在较大争议
|
|
15
|
+
key_points — 各方清算金额摘要
|
|
16
|
+
data_used — 包含 settlement_result(结构化清算数据)
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from decimal import Decimal, ROUND_HALF_UP
|
|
21
|
+
from typing import Any, Dict, List
|
|
22
|
+
from ..base import BaseAgent, AgentResult
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ExitSettlementAgent(BaseAgent):
|
|
26
|
+
name = "exit_settlement"
|
|
27
|
+
description = "退出清算:生成退出方案(欠费扣除/保证金处理/设备交接/违约金计算)"
|
|
28
|
+
|
|
29
|
+
_SYSTEM = (
|
|
30
|
+
"你是一名专业的不动产合同清算顾问,处理经营权共创项目的退出和清算。\n"
|
|
31
|
+
"请根据以下数据生成清算草案:\n"
|
|
32
|
+
" 1. 未结收入清算(未付保底/分润账单合计)\n"
|
|
33
|
+
" 2. 保证金处理(全额退还/部分扣除/全额扣除 + 依据)\n"
|
|
34
|
+
" 3. 违约金计算(若有违约,按合同规则计算金额)\n"
|
|
35
|
+
" 4. 预收款退还(如有预付款未消耗部分)\n"
|
|
36
|
+
" 5. 装修与设备处理(保留/赔偿/折旧计算)\n"
|
|
37
|
+
" 6. 最终各方应收/应付金额汇总\n"
|
|
38
|
+
" 7. 交接清单(钥匙/设备/合同/数据/账户注销)\n"
|
|
39
|
+
" 8. 建议处置时间表(7日内/30日内完成)\n\n"
|
|
40
|
+
"标注每项条款是否为 [系统可计算] / [需人工确认] / [建议律师处理]"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
async def analyze(self, symbol: str, data: Dict[str, Any]) -> AgentResult:
|
|
44
|
+
project = data.get("project_info", {})
|
|
45
|
+
fin = data.get("financials", {})
|
|
46
|
+
asset = data.get("asset_condition", {})
|
|
47
|
+
reason = data.get("exit_reason", "到期终止")
|
|
48
|
+
|
|
49
|
+
settlement = _calculate_settlement(project, fin, asset, reason)
|
|
50
|
+
|
|
51
|
+
user_prompt = (
|
|
52
|
+
f"退出清算信息:\n"
|
|
53
|
+
f" 项目: {project.get('name','未命名')} 退出原因: {reason}\n"
|
|
54
|
+
f" 合同到期: {project.get('contract_end','未知')} 实际退出: {project.get('actual_exit','未知')}\n\n"
|
|
55
|
+
f"财务状况:\n"
|
|
56
|
+
f" 未结账单: {settlement['unpaid_invoices']:,.2f}元\n"
|
|
57
|
+
f" 保证金: {fin.get('deposit_amount',0):,.2f}元 "
|
|
58
|
+
f" 可扣除: {settlement['deposit_deductible']:,.2f}元\n"
|
|
59
|
+
f" 违约金: {settlement['penalty']:,.2f}元({reason})\n"
|
|
60
|
+
f" 预收款退还: {settlement['prepayment_refund']:,.2f}元\n"
|
|
61
|
+
f" 装修/设备折旧: {settlement['depreciation_deduction']:,.2f}元\n\n"
|
|
62
|
+
f"最终清算:\n"
|
|
63
|
+
f" 经营方应付平台/资产方: {settlement['operator_owes']:,.2f}元\n"
|
|
64
|
+
f" 平台/资产方应退经营方: {settlement['platform_owes']:,.2f}元\n"
|
|
65
|
+
f" 净结算金额: {settlement['net_settlement']:,.2f}元"
|
|
66
|
+
f"({'经营方需支付' if settlement['net_settlement'] > 0 else '平台需退还'})\n\n"
|
|
67
|
+
"请生成完整清算草案。"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
analysis = await self._call_llm(self._SYSTEM, user_prompt, max_tokens=900)
|
|
71
|
+
if not analysis:
|
|
72
|
+
analysis = _template_settlement(settlement, project, reason)
|
|
73
|
+
|
|
74
|
+
signal = _settlement_signal(settlement, reason)
|
|
75
|
+
confidence = _settlement_confidence(fin)
|
|
76
|
+
key_points = _settlement_key_points(settlement)
|
|
77
|
+
|
|
78
|
+
return AgentResult(
|
|
79
|
+
agent = self.name,
|
|
80
|
+
symbol = symbol,
|
|
81
|
+
analysis = analysis,
|
|
82
|
+
confidence = confidence,
|
|
83
|
+
signal = signal,
|
|
84
|
+
key_points = key_points,
|
|
85
|
+
data_used = {"settlement_result": settlement},
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# ── 清算计算逻辑 ──────────────────────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
def _calculate_settlement(
|
|
92
|
+
project: Dict, fin: Dict, asset: Dict, reason: str,
|
|
93
|
+
) -> Dict:
|
|
94
|
+
D = Decimal
|
|
95
|
+
|
|
96
|
+
deposit = D(str(fin.get("deposit_amount", 0)))
|
|
97
|
+
unpaid = D(str(fin.get("unpaid_invoices", 0)))
|
|
98
|
+
# 兼容 prepayment_received / prepayment 两种命名
|
|
99
|
+
prepayment = D(str(fin.get("prepayment_received", fin.get("prepayment", 0))))
|
|
100
|
+
prepaid_used = D(str(fin.get("prepayment_used", 0)))
|
|
101
|
+
guaranteed = D(str(fin.get("guaranteed_monthly", 0)))
|
|
102
|
+
exit_penalty_months = D(str(fin.get("exit_penalty_months", 3)))
|
|
103
|
+
|
|
104
|
+
# 折旧计算:renovation_cost 可在 financials 或 asset_condition 中
|
|
105
|
+
reno_cost = D(str(asset.get("renovation_cost",
|
|
106
|
+
fin.get("renovation_cost", 0))))
|
|
107
|
+
contract_yrs = D(str(project.get("contract_years", 1)))
|
|
108
|
+
used_months = D(str(project.get("used_months", 12)))
|
|
109
|
+
contract_months = contract_yrs * 12
|
|
110
|
+
if contract_months > 0:
|
|
111
|
+
remaining_ratio = max(D("0"), (contract_months - used_months) / contract_months)
|
|
112
|
+
else:
|
|
113
|
+
remaining_ratio = D("0")
|
|
114
|
+
depreciation = (reno_cost * remaining_ratio).quantize(D("0.01"), ROUND_HALF_UP)
|
|
115
|
+
|
|
116
|
+
# 违约金计算
|
|
117
|
+
is_breach = reason in ("提前退出", "违约", "经营违规")
|
|
118
|
+
penalty = (guaranteed * exit_penalty_months
|
|
119
|
+
).quantize(D("0.01"), ROUND_HALF_UP) if is_breach else D("0")
|
|
120
|
+
|
|
121
|
+
# 预收款退还(未消耗部分)
|
|
122
|
+
prepayment_refund = max(D("0"), prepayment - prepaid_used)
|
|
123
|
+
|
|
124
|
+
# 保证金可扣除项
|
|
125
|
+
deposit_deductible = min(deposit, unpaid + penalty)
|
|
126
|
+
|
|
127
|
+
# 汇总
|
|
128
|
+
operator_owes = unpaid + penalty + depreciation
|
|
129
|
+
platform_owes = prepayment_refund + max(D("0"), deposit - deposit_deductible)
|
|
130
|
+
net = (operator_owes - platform_owes).quantize(D("0.01"), ROUND_HALF_UP)
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
"unpaid_invoices": float(unpaid),
|
|
134
|
+
"deposit_amount": float(deposit),
|
|
135
|
+
"deposit_deductible": float(deposit_deductible),
|
|
136
|
+
"penalty": float(penalty),
|
|
137
|
+
"prepayment_refund": float(prepayment_refund),
|
|
138
|
+
"depreciation_deduction": float(depreciation),
|
|
139
|
+
"operator_owes": float(operator_owes),
|
|
140
|
+
"platform_owes": float(platform_owes),
|
|
141
|
+
"net_settlement": float(net),
|
|
142
|
+
"is_breach": is_breach,
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _settlement_signal(s: Dict, reason: str) -> str:
|
|
147
|
+
if s["net_settlement"] > 0 and not s["is_breach"]:
|
|
148
|
+
return "HOLD" # 经营方有欠款但无违约,需催收
|
|
149
|
+
if s["is_breach"] and s["net_settlement"] > 0:
|
|
150
|
+
return "SELL" # 违约且有欠款
|
|
151
|
+
if s["operator_owes"] == 0 and s["platform_owes"] == 0:
|
|
152
|
+
return "BUY" # 干净退出
|
|
153
|
+
return "HOLD"
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _settlement_confidence(fin: Dict) -> float:
|
|
157
|
+
keys = ["deposit_amount", "unpaid_invoices", "guaranteed_monthly", "exit_penalty_months"]
|
|
158
|
+
filled = sum(1 for k in keys if fin.get(k))
|
|
159
|
+
return round(0.5 + 0.12 * filled, 2)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _settlement_key_points(s: Dict) -> List[str]:
|
|
163
|
+
pts = [f"未结账单: {s['unpaid_invoices']:,.2f}元"]
|
|
164
|
+
if s["penalty"] > 0:
|
|
165
|
+
pts.append(f"违约金: {s['penalty']:,.2f}元")
|
|
166
|
+
pts.append(f"保证金: {s['deposit_amount']:,.2f}元 可扣除: {s['deposit_deductible']:,.2f}元")
|
|
167
|
+
if s["prepayment_refund"] > 0:
|
|
168
|
+
pts.append(f"预收款退还: {s['prepayment_refund']:,.2f}元")
|
|
169
|
+
direction = "经营方付" if s["net_settlement"] > 0 else "平台退"
|
|
170
|
+
pts.append(f"净结算: {abs(s['net_settlement']):,.2f}元({direction})")
|
|
171
|
+
return pts[:5]
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _template_settlement(s: Dict, project: Dict, reason: str) -> str:
|
|
175
|
+
penalty_line = (
|
|
176
|
+
"违约金: {:,.2f}元".format(s['penalty'])
|
|
177
|
+
if s['penalty'] > 0 else "无违约金(正常到期)"
|
|
178
|
+
)
|
|
179
|
+
return (
|
|
180
|
+
f"退出清算草案(模板)\n"
|
|
181
|
+
f"{'='*40}\n"
|
|
182
|
+
f"项目: {project.get('name','未命名')} 退出原因: {reason}\n\n"
|
|
183
|
+
f"一、应收账款清算\n"
|
|
184
|
+
f" 未结账单合计: {s['unpaid_invoices']:,.2f}元 [系统可计算]\n\n"
|
|
185
|
+
f"二、违约金\n"
|
|
186
|
+
f" {penalty_line} [系统可计算]\n\n"
|
|
187
|
+
f"三、保证金处理\n"
|
|
188
|
+
f" 保证金总额: {s['deposit_amount']:,.2f}元\n"
|
|
189
|
+
f" 扣除欠款后退还: {s['deposit_amount'] - s['deposit_deductible']:,.2f}元 [需人工确认]\n\n"
|
|
190
|
+
f"四、预收款退还\n"
|
|
191
|
+
f" 应退预收款: {s['prepayment_refund']:,.2f}元 [系统可计算]\n\n"
|
|
192
|
+
f"五、装修折旧\n"
|
|
193
|
+
f" 折旧扣除: {s['depreciation_deduction']:,.2f}元 [需人工确认]\n\n"
|
|
194
|
+
f"六、最终净结算\n"
|
|
195
|
+
f" 经营方应付: {s['operator_owes']:,.2f}元\n"
|
|
196
|
+
f" 平台方应退: {s['platform_owes']:,.2f}元\n"
|
|
197
|
+
f" 净结算: {abs(s['net_settlement']):,.2f}元 "
|
|
198
|
+
f"({'经营方支付' if s['net_settlement'] > 0 else '平台退还'})\n\n"
|
|
199
|
+
f"七、交接清单\n"
|
|
200
|
+
f" [ ] 场地钥匙及门禁权限\n"
|
|
201
|
+
f" [ ] 合同及附件文件\n"
|
|
202
|
+
f" [ ] 收款账户注销/变更\n"
|
|
203
|
+
f" [ ] 备案收银系统注销\n"
|
|
204
|
+
f" [ ] 经营数据存档\n"
|
|
205
|
+
f" [ ] 水电气账户过户\n\n"
|
|
206
|
+
f"[注:以上为草案,请由平台运营人员核实后提交审批]"
|
|
207
|
+
)
|