feat(business): add staff queries and incremental sync
Add order_staff normalization, salesperson query templates, guarded read-only SQL fallback, and incremental Kingdee sync cursor handling. Add a user-level systemd timer manager for daily Kingdee business sync and document the new workflow. Validation: python3 -m unittest discover -v; python3 -m compileall obsidian_wiki tests scripts; git diff --check.
This commit is contained in:
@@ -10,6 +10,7 @@ Use `<vault>/_meta/business-facts.sqlite` for questions where markdown is the wr
|
||||
- monthly sales amount
|
||||
- top customers for a month
|
||||
- customer order trend for a fixed period
|
||||
- sales order counts, lists, and amounts by salesperson
|
||||
|
||||
The wiki remains the place for context: customer background, project history, sales notes, email-derived signals, and later human-readable summaries.
|
||||
|
||||
@@ -28,13 +29,29 @@ obsidian-wiki business sync kingdee \
|
||||
--billstatus C
|
||||
|
||||
obsidian-wiki business sync kingdee --start-modifytime "2026-07-01 00:00:00"
|
||||
obsidian-wiki business sync kingdee --incremental
|
||||
obsidian-wiki business query "2026年6月接了多少单"
|
||||
obsidian-wiki business query "2026-06 sales amount"
|
||||
obsidian-wiki business query "2026-06 top customer"
|
||||
obsidian-wiki business query "徐丽最近一周订单"
|
||||
obsidian-wiki business query "徐丽最近一周接了多少单"
|
||||
obsidian-wiki business query "徐丽最近一周销售额" --all-staff
|
||||
obsidian-wiki business query "按组织列出订单" --fallback-sql "SELECT org_name, COUNT(*) AS order_count FROM orders GROUP BY org_name"
|
||||
obsidian-wiki business sql "SELECT COUNT(*) AS order_count FROM orders"
|
||||
```
|
||||
|
||||
When `--input` is omitted, sync reads `.runtime/kingdee.env`, gets or refreshes an access token, calls the official Kingdee sales order API, and stores the returned rows. If the file does not exist, `business sync kingdee` creates the template and asks you to fill it before retrying.
|
||||
|
||||
For unattended sync, install the user-level systemd timer:
|
||||
|
||||
```bash
|
||||
bash scripts/business_sync_service.sh start --vault /path/to/vault
|
||||
bash scripts/business_sync_service.sh run-now --vault /path/to/vault
|
||||
bash scripts/business_sync_service.sh status
|
||||
```
|
||||
|
||||
The timer defaults to daily `07:10` with a 15-minute randomized delay. It runs incremental Kingdee sync with a 48-hour lookback window.
|
||||
|
||||
The config template includes:
|
||||
|
||||
- Token defaults follow Kingdee's enhanced OpenAPI token authentication doc: `https://vip.kingdee.com/knowledge/specialDetail/226337046514476288?category=239331354741842688&id=489812471545485056&productLineId=29`.
|
||||
@@ -65,6 +82,8 @@ Tables:
|
||||
- `orders`: one normalized row per sales order. It keeps the query-critical fields (`order_id`, `order_no`, `order_date`, customer, status, organization, department, operator, currency, total amount, net amount, tax amount, address, comment) plus `raw_json` for the full original order header.
|
||||
- `order_items`: normalized material detail lines. It keeps material number/name/model, quantity, unit, price, tax-inclusive price, net amount, tax-inclusive amount, tax amount, delivery date, project, warehouse, and `raw_json` for the full original line.
|
||||
- `order_deliveries`: normalized delivery-plan rows from `billentry[].orderdeliverentry[]`. It keeps planned demand date, planned delivery date, planned quantity, planned base quantity, unit, receive address/place, remark, transport lead time, and `raw_json` for the full original delivery-plan row.
|
||||
- `order_staff`: sales staff roles extracted from the order header. Roles are `primary_sales`, `sales_2`, `sales_3`, `sales_4`, and `followup`.
|
||||
- `sync_state`: saved Kingdee incremental cursor.
|
||||
- `customers`: customer lookup data observed from orders.
|
||||
- `products`: product lookup data observed from order lines.
|
||||
|
||||
@@ -80,9 +99,30 @@ V1 statistics use fixed templates, not free-form SQL generated by an LLM.
|
||||
- Monthly sales amount: `SUM(total_amount)` by `order_date`.
|
||||
- Monthly top customers: group by customer name or ID and rank by sales amount.
|
||||
- Customer trend: group matching customer orders by order month.
|
||||
- Staff order list/count/amount: join `orders` to `order_staff`, defaulting to `primary_sales`.
|
||||
|
||||
Every answer includes the statistic, counting basis, data source, and last successful sync time. If the last successful sync is before the query date, the answer warns that newer data may be missing.
|
||||
|
||||
Salesperson queries default to the main Kingdee salesperson (`operator_operatorname`). Use `--all-staff`, or phrases such as "全部角色" or "含跟单", to include sales 2/3/4 and follow-up roles.
|
||||
|
||||
If no fixed template matches, callers may provide guarded SQL through `business sql` or `business query --fallback-sql`. The SQL fallback is still restricted:
|
||||
|
||||
- only one `SELECT` or `WITH ... SELECT` statement
|
||||
- only structured tables: `orders`, `order_items`, `order_deliveries`, `order_staff`, `customers`, `products`, `sync_runs`
|
||||
- no `raw_json` columns and no `raw_snapshots`
|
||||
- no write, schema, attach, pragma, or vacuum statements
|
||||
- default result limit is 100 rows, capped at 1000
|
||||
|
||||
## Incremental Sync
|
||||
|
||||
`obsidian-wiki business sync kingdee --incremental` uses Kingdee `start_modifytime`.
|
||||
|
||||
- First run without a cursor: fetches the last 7 days.
|
||||
- Later runs: starts from the saved cursor minus 48 hours.
|
||||
- Explicit `--start-modifytime` or `--since` wins over the computed cursor.
|
||||
|
||||
The 48-hour lookback intentionally re-fetches recent orders so late edits and boundary cases are updated rather than missed. Upserts keep the database deduplicated by `order_id`.
|
||||
|
||||
## Boundary With Wiki Ingest
|
||||
|
||||
Do not create one markdown page per order or order line. That makes the wiki noisy and produces unreliable statistics.
|
||||
|
||||
Reference in New Issue
Block a user