feat(business): add schema-driven query templates

Expose a business schema catalog and explicit template runner for Kingdee sales-order facts. Update wiki-query guidance so the LLM routes operational questions through templates first and guarded SQL only when needed. Refresh user docs and ops aliases, and add coverage for schema metadata, template execution, and CLI JSON output.

Validation: python3 -m unittest discover -v; python3 -m compileall obsidian_wiki tests scripts; git diff --check
This commit is contained in:
Codex
2026-07-06 22:27:49 +00:00
parent b85c26e0ba
commit d3f3151218
8 changed files with 1327 additions and 39 deletions
+34 -22
View File
@@ -8,11 +8,11 @@ Use `<vault>/_meta/business-facts.sqlite` for questions where markdown is the wr
- how many sales orders were received in a month
- monthly sales amount
- top customers for a month
- customer order trend for a fixed period
- sales order counts, lists, and amounts by salesperson
- customer, product, salesperson, organization, department, project, warehouse, status, and currency rankings or breakdowns
- customer, product, and salesperson summaries
- sales order counts, lists, trends, quantities, averages, and delivery-plan quantities
The wiki remains the place for context: customer background, project history, sales notes, email-derived signals, and later human-readable summaries.
The wiki remains the place for context: customer background, project history, sales notes, email-derived signals, and cross-linked narrative knowledge.
## Commands
@@ -30,13 +30,15 @@ scripts/obsidian-wiki-ops.py kingdee sync \
scripts/obsidian-wiki-ops.py kingdee sync --start-modifytime "2026-07-01 00:00:00"
scripts/obsidian-wiki-ops.py kingdee sync --incremental
scripts/obsidian-wiki-ops.py kingdee query "2026年6月接了多少单"
scripts/obsidian-wiki-ops.py kingdee query "2026-06 sales amount"
scripts/obsidian-wiki-ops.py kingdee query "2026-06 top customer"
scripts/obsidian-wiki-ops.py kingdee query "徐丽最近一周订单"
scripts/obsidian-wiki-ops.py kingdee query "徐丽最近一周接了多少单"
scripts/obsidian-wiki-ops.py kingdee query "徐丽最近一周销售额" --all-staff
scripts/obsidian-wiki-ops.py kingdee query "按组织列出订单" --fallback-sql "SELECT org_name, COUNT(*) AS order_count FROM orders GROUP BY org_name"
# wiki-query uses this schema/template catalog to answer business questions.
scripts/obsidian-wiki-ops.py kingdee schema --json
scripts/obsidian-wiki-ops.py kingdee template order_count --vault /path/to/vault --year 2026 --month 6 --json
scripts/obsidian-wiki-ops.py kingdee template sales_amount --vault /path/to/vault --year 2026 --month 6 --json
scripts/obsidian-wiki-ops.py kingdee template top_products --vault /path/to/vault --year 2026 --month 6 --limit 10 --json
scripts/obsidian-wiki-ops.py kingdee template staff_summary --vault /path/to/vault --start-date 2026-06-30 --end-date 2026-07-07 --staff 徐丽 --staff-role-scope all --json
# Guarded SQL is for gaps where no template fits.
scripts/obsidian-wiki-ops.py kingdee sql "SELECT COUNT(*) AS order_count FROM orders"
```
@@ -91,21 +93,32 @@ Order upsert key: `order_id`, falling back to `order_no` when no explicit ID is
`total_amount` is the statistic field used by monthly sales queries. For Kingdee sales orders it prefers `totalallamount` (价税合计) and falls back to other total fields only when the tax-inclusive total is absent. `total_net_amount`, `total_tax_amount`, and `total_all_amount` are stored separately so later reports can choose a different accounting basis without re-fetching historical payloads.
## Counting Basis
## Query Flow And Counting Basis
V1 statistics use fixed templates, not free-form SQL generated by an LLM.
`wiki-query` decides semantically whether a user question needs business facts. When it does, it loads `obsidian-wiki business schema --json`, chooses a template if one fits, and only then uses guarded SQL for gaps.
- Monthly order count: `COUNT(DISTINCT order_no)` by `order_date`.
- 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`.
Template families include:
- Order totals: `order_count`, `sales_amount`, `customer_count`, `product_count`, `quantity_sum`, `avg_order_amount`.
- Trends: `order_trend`, `sales_trend`, `quantity_trend`, grouped by day or month.
- Rankings and breakdowns: customers, products, staff, organizations, departments, projects, warehouses, statuses, currencies.
- Lists: orders, customer orders, product orders, staff orders.
- Summaries: customer, product, and staff summaries.
- Delivery plans: delivery-plan count, quantity, and list by planned date.
Core counting basis:
- Order count: `COUNT(DISTINCT order_no)` by `orders.order_date`.
- Sales amount: `SUM(orders.total_amount)` by `orders.order_date`.
- Ordered quantity: `SUM(order_items.quantity)` by `orders.order_date`.
- Delivery-plan quantity: `SUM(order_deliveries.plan_qty)` by `order_deliveries.plan_date`.
- Staff templates 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.
Salesperson templates default to the main Kingdee salesperson (`operator_operatorname`). Use `--staff-role-scope all`, or wording 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:
If no template matches, `wiki-query` may generate guarded SQL and execute it through `business 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`
@@ -126,5 +139,4 @@ The 48-hour lookback intentionally re-fetches recent orders so late edits and bo
## Boundary With Wiki Ingest
Do not create one markdown page per order or order line. That makes the wiki noisy and produces unreliable statistics.
If business summaries are added later, generate compact daily or monthly summary sources from this database and pass those summaries through `wiki-ingest`. The database remains the fact source for exact numbers.
The database remains the fact source for exact numbers; the wiki remains the context source.