Files
obsidian-wiki/docs/business-facts.md
T
Codex 4e34e5b3fe feat(business): split Kingdee token body config
Allow Kingdee token requests to be built from app key, app secret, configurable field names, optional timestamp fields, and extra JSON. Keep raw KINGDEE_TOKEN_BODY_JSON as an advanced override with current-time placeholders.

Validation: python3 -m unittest discover -v; python3 -m compileall obsidian_wiki tests; git diff --check.
2026-07-06 20:03:28 +00:00

4.9 KiB

Business Facts

Business facts are structured operational data used for exact counts, sums, and rankings. They complement the markdown wiki; they do not replace it.

Purpose

Use <vault>/_meta/business-facts.sqlite for questions where markdown is the wrong source of truth:

  • how many sales orders were received in a month
  • monthly sales amount
  • top customers for a month
  • customer order trend for a fixed period

The wiki remains the place for context: customer background, project history, sales notes, email-derived signals, and later human-readable summaries.

Commands

obsidian-wiki business sync kingdee --input ./kingdee-orders.json

obsidian-wiki business config kingdee
# Fill .runtime/kingdee.env, then test the login/refresh flow:
obsidian-wiki business sync kingdee --dry-run-auth

obsidian-wiki business sync kingdee \
  --start-bizdate 2026-06-01 \
  --end-bizdate 2026-06-30 \
  --billstatus C

obsidian-wiki business sync kingdee --start-modifytime "2026-07-01 00:00:00"
obsidian-wiki business query "2026年6月接了多少单"
obsidian-wiki business query "2026-06 sales amount"
obsidian-wiki business query "2026-06 top customer"

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.

The config template includes:

  • KINGDEE_SALORDER_API_URL: defaults to the official querySalOrder endpoint.
  • KINGDEE_TOKEN_URL and KINGDEE_TOKEN_BODY_JSON: login/access-token request.
  • KINGDEE_APP_KEY, KINGDEE_APP_SECRET, KINGDEE_TOKEN_APP_KEY_FIELD, KINGDEE_TOKEN_APP_SECRET_FIELD: preferred split-field way to build the token request body without hand-writing the full JSON.
  • KINGDEE_TOKEN_TIMESTAMP_FIELD, KINGDEE_TOKEN_TIMESTAMP_FORMAT: optional current-time field for token APIs that require a timestamp. Supported formats are epoch_ms, epoch_seconds, datetime_utc, iso_utc, and date_utc.
  • KINGDEE_TOKEN_BODY_EXTRA_JSON: optional fixed extra fields merged into the generated token request body.
  • KINGDEE_TOKEN_BODY_JSON: advanced override for the full token request JSON. It supports {now_ms}, {now_epoch}, {now_seconds}, {now_datetime_utc}, {now_iso_utc}, and {today_utc} placeholders.
  • KINGDEE_TOKEN_HEADERS_JSON: optional token request headers, such as app-specific headers.
  • KINGDEE_TOKEN_FIELD, KINGDEE_TOKEN_EXPIRES_IN_FIELD, KINGDEE_REFRESH_TOKEN_FIELD: dot paths used to read token response fields.
  • KINGDEE_REFRESH_URL and KINGDEE_REFRESH_BODY_JSON: optional refresh request. Use {refresh_token} in the JSON body template.
  • KINGDEE_ACGW_IDENTITY: value sent as the required x-acgw-identity sales-order API header.
  • KINGDEE_PAGE_SIZE: default sales-order page size.

KINGDEE_LOGIN_URL, KINGDEE_LOGIN_BODY_JSON, and KINGDEE_LOGIN_HEADERS_JSON are accepted as aliases for the token settings. KINGDEE_ACCESS_TOKEN can also be set for one-off manual testing. Fetched tokens are cached in .runtime/kingdee-token.json; both local files are ignored by git and should not be copied into .env.example.

The API response can still be imported from a JSON file for replay or testing. JSON may be a list of order objects or an object containing orders, rows, data, records, or items.

Database

Default path: <vault>/_meta/business-facts.sqlite.

Tables:

  • sync_runs: one row per Kingdee sync attempt, including status, cursor, record counts, and error text.
  • raw_snapshots: content-hashed raw JSON payloads for audit and replay.
  • orders: one normalized row per sales order.
  • order_items: normalized detail lines for product/quantity/line amount analysis.
  • customers: customer lookup data observed from orders.
  • products: product lookup data observed from order lines.

Order upsert key: order_id, falling back to order_no when no explicit ID is present. Re-syncing the same order updates the existing row and replaces that order's detail lines.

Counting Basis

V1 statistics use fixed templates, not free-form SQL generated by an LLM.

  • 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.

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.

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.