accounting/README.md

142 lines
9.0 KiB
Markdown
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.

# accounting — 记账模块
## 模块定位
Sage 平台的**核心记账引擎**:以复式记账(借/贷双腿)为基础,围绕
「科目subject→ 账户account→ 明细acc_detail/ 余额acc_balance/ 流水
accounting_log」的账务体系向上提供开户、充值、消费、账单、总账、日结、信用额度、
多币种汇率等能力。
记账的定义 = **写分录明细 + 写账务日志 + 修改账户余额**,三步缺一不可,且余额更新与
透支/信用额度校验必须和明细写入在**同一数据库事务上下文**内完成(原子性铁律)。
模块形态Python 包 `accounting`(业务逻辑)+ `models/`(表定义)+ `json/`CRUD 定义)
+ `wwwroot/`(页面/dspy 端点)+ `init/data.json`(种子数据)+ `scripts/`RBAC 注册)。
宿主应用sage 主应用)通过 `load_accounting()` 把所有类与函数注入 `ServerEnv`
供其他模块product、supplychain、unipay 等)跨模块调用。
核心业务文件:`accounting_config.py`Accounting 配置类)/ `openaccount.py`(开户)/
`recharge.py`(充值 RechargeBiz/ `consume.py`(消费记账)/ `bill.py`write_bill 账单)/
`ledger.py`(总账)/ `dayend_balance.py`(日结) / `settle.py`+`settledate.py`(结算)/
`creditlimit.py`(信用额度)/ `exchange.py`(多币种汇率换算)/ `stats.py`(统计)/
`order_to_bill.py`(订单转账单)。
## 表清单models/*.json
| 表名 | 说明 | 关键字段 |
|---|---|---|
| `subject` | 科目表 | name, balance_side(余额方向), subjecttype |
| `account` | 机构账户表 | accounting_orgid, orgid, org1id, currency, subjectid, balance_at, max_detailno |
| `acc_balance` | 账户余额表 | accountid, acc_date, balance |
| `acc_detail` | 账户明细表(分录) | accountid, acc_no, acc_date, acc_timestamp, acc_dir(借/贷), summary, amount |
| `accounting_log` | 账务流水表 | accountid, acc_date, acc_timestamp, acc_dir, summary, amount, billid |
| `account_config` | 账户配置表(参与方类型→科目) | subjectid, partytype, party1type |
| `accounting_config` | 记账配置表(驱动分录双腿) | action, accounting_orgtype, accounting_dir, orgtype, org1type, subjectid, amt_pattern |
| `bill` | 账单 | customerid, resellerid, productid, resourceid, orderid, business_op, amount |
| `bill_detail` | 账单明细 | accounting_orgid, billid, description, participantid, participanttype, subjectname, accounting_dir |
| `biz_order` | 业务订单 | customerid, resellerid, order_date, order_status, business_op, amount, currency |
| `biz_orderdetail` | 业务订单明细 | orderid, productid, product_cnt, prod_config, list_amount, trans_amount, currency |
| `ledger` | 总账表 | accounting_orgid, subjectid, acc_date, d_balance(借方), c_balance(贷方), currency, exchange_rate |
| `credit_limit` | 信用额度表 | accountid, orgid, grant_orgid(授信方,多租户), credit_limit, used_credit, available_credit, valid_from |
| `currency` | 币种 | name, symbol, decimal_places, is_base, status |
| `exchange_rate` | 汇率表 | from_currency, to_currency, buy_rate, sell_rate, mid_rate, effective_date |
种子数据(`init/data.json`appcodes/appcodes_kv 码表 + subject 科目 +
account_config + accounting_config 记账配置 + currency + exchange_rate 初始汇率。
信用额度建表 SQL 另见 `sql/credit_limit.sql`;多币种迁移见
`scripts/multi_currency_migration.sql`
## 对外 API / dspy 端点wwwroot/
**api/(多币种管理端)**
- `currency_create/update/delete.dspy` — 币种维护
- `exchange_rate_create/update/delete.dspy` — 汇率维护
- `fetch_forex_rates.dspy` — 拉取外部外汇牌价
**credit_limit/(信用额度管理)**
- `add/update/delete/get_credit_limit.dspy` — 额度 CRUD
- `credit_manage.ui` / `credit_overview.ui` / `hub.ui` — 管理/总览页面
- `api/credit_summary.dspy``api/set_customer_credit.dspy`(+`set_credit_form.ui`) —
额度汇总与客户授信设置
**账务页面端点wwwroot/ 根)**
- `myaccounts.dspy/.ui``mybalance.dspy``accdetail.dspy/.ui` — 我的账户/余额/明细
- `billing.dspy/.ui``billing_download.dspy` — 账单查询与下载
- `get_user_balance.dspy``oca.dspy``usermenu.ui``error_accounting.ui`
- 开户端点:`open_owner_accounts.dspy` / `open_provider_accounts.dspy` /
`open_reseller_accounts.dspy` / `open_reseller_provider_accounts.dspy` /
`open_customer_accounts.dspy` / `open_customer_accounts_with_orgid.dspy`
- 代充值:`proxy_recharge.ui` + `proxy_recharge_submit.dspy`
- 统计 widget`stat_account_count.ui` / `stat_month_consumption.ui` /
`stat_today_consumption.ui` / `stat_total_balance.ui`
CRUD 定义在 `json/`account/acc_balance/acc_detail/accounting_log/accounting_config/
account_config/subject/credit_limit/currency_list/exchange_rate_list其中
`json/build.sh``xls2ui -m ../models -o ../wwwroot accounting *.json` 从模型生成
wwwroot 页面——**改 CRUD 走 json 定义重新生成,勿手改产物**。
## load 注册函数
宿主在初始化时调用:
```python
from accounting.init import load_accounting
load_accounting()
```
`load_accounting()` 把以下能力注入 `ServerEnv`(跨模块可见):
- **配置/业务类**`Accounting`(记账配置类)、`RechargeBiz`(充值业务)
- **记账函数**`consume_accounting``recharge_accounting``write_bill`
- **开户函数**`openOwnerAccounts` / `openProviderAccounts` / `openResellerAccounts` /
`openCustomerAccounts` / `openRetailRelationshipAccounts`
- **查询函数**`getAccountBalance``getCustomerBalance``getAccountByName`
`get_account_total_amount``get_accdetail``all_my_accounts``get_accounting_stats`
- **信用额度**`get_credit_limit_for_account``update_used_credit``set_credit_limit`
`get_credit_stats``get_my_credit_list``get_all_customer_credits` + 三个 web 包装
`get_credit_stats_web` / `get_my_credits_web` / `get_all_credits_web`,供 Jinja2 .ui 用)
- **多币种**`get_exchange_rate``convert_currency``convert_to_base`
`get_user_currency``BASE_CURRENCY`
数据库名通过宿主注册的 `get_module_dbname('accounting')` 解析(跨宿主复用时表前缀/库名
映射的关键钩子)。独立调试可跑 `app/acc.py`(自带 webapp + RegisterFunction 的最小宿主)。
## 宿主集成(部署)
1. **安装**`./py3/bin/pip install pkgs/accounting`setup.py 打包,包名 accounting
版本见 `accounting/version.py`)。宿主 `import_init.py` 的 INIT_MODULES 需包含本模块
以导入 `init/data.json` 种子数据(码表/科目/记账配置)。
2. **入口调用**:宿主初始化处 `import` 后显式调用 `load_accounting()`
3. **RBAC 注册**`./py3/bin/python pkgs/accounting/scripts/load_path.py [--add-only]`
(自动定位宿主根:含 py3+wwwroot把 wwwroot 全部 .ui/.dspy 路径注册进 permission
表并给角色授权)。注册后 redis db0 FLUSHDB 刷 RBAC 缓存即生效。
4. **建表**models/*.json 经 json2ddl 生成 DDL 部署期执行;运行期禁止 schema 变更。
信用额度增量见 `sql/credit_limit.sql`,多币种迁移见 `scripts/multi_currency_migration.sql`
5. **菜单**:新页面需在 sage 主仓库 `wwwroot/global_menu.ui` 加菜单入口。
6. **i18n**:词条在 `i18n/{zh,en,jp,ko}`,部署时合并进宿主。
新功能四件套核查(缺一即不可见/不可用):`init.py` ServerEnv 暴露 →
`scripts/load_path.py` RBAC 路径 → 宿主 `global_menu.ui` 菜单 → `json/<表>.json` CRUD 定义。
## 部署注意
1. **余额更新不是可选项**:只写 acc_detail 不改 account/acc_balance 的实现按定义就是
不完整记账;透支/信用额度校验必须与明细写入同一事务上下文。
2. **数据隔离**:查询类端点(如 get_accdetail必须按 `orgid` 过滤,防止按 accountid
越权枚举他人账务——新增查询端点照抄该模式。
3. **信用额度多租户**`grant_orgid` 区分授信方;管理端读全部、客户端只读本机构视图,
迁移按 `sql/credit_limit.sql` 执行。
4. **pip 非 editable 安装**:改码后必须重新 `pip install` 到宿主 py3 再重启,
只 git pull 仓库不会更新 site-packages可用文件 md5 对比确认加载版本)。
5. **sage 核心记账引擎 vs sageapi 网关是两层**:本仓库是核心引擎(复式记账/双腿/科目),
sageapi 只是轻量 API 网关credit_limit 等逻辑两层都可能需要但实现方式不同,勿混淆。
6. **先读全模块再改**PFBiz → Accounting → leg_accounting 是完整既有体系,加功能前先读
`accounting_config.py` / `creditlimit.py` / `consume.py`,勿发明平行实现。
7. RBAC 精确 path 匹配,父路径不覆盖子路径;新增 dspy 必须逐条注册,否则 403。
设计文档见 `docs/平台类系统记账子系统.docx`;测试脚本见 `test/`
open_account.py / recharge.py / run_test.py