142 lines
9.0 KiB
Markdown
142 lines
9.0 KiB
Markdown
# 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)。
|