feat(business): exclude intercompany transfer orders

Allow operators to configure internal company names and identifiers, then apply the filter consistently across business templates and query routing. Preserve direct external-customer orders and provide explicit CLI and environment overrides for internal-flow audits.

Validation: python -m unittest tests.test_business_facts tests.test_wiki_skills tests.test_user_ops -v (25 tests)
This commit is contained in:
Codex
2026-07-10 05:40:54 +00:00
parent 7eb9b987ab
commit 4c5454da90
7 changed files with 416 additions and 34 deletions
+54 -1
View File
@@ -29,6 +29,7 @@ from obsidian_wiki.business_facts import (
query_business_question,
sync_kingdee_orders,
)
from obsidian_wiki.config import load_config
from obsidian_wiki.file_assets import (
clean_config_value,
db_path_for_vault,
@@ -603,6 +604,7 @@ def cmd_business_query(args: argparse.Namespace) -> int:
db_path=_resolve_business_db(args, vault_path),
all_staff=args.all_staff,
fallback_sql=args.fallback_sql,
business_params=_business_internal_params(args),
)
if args.json:
print(json.dumps(result, ensure_ascii=False, indent=2))
@@ -666,7 +668,32 @@ def _business_template_params(args: argparse.Namespace) -> dict[str, object]:
"closestatus",
"currency",
)
return {key: getattr(args, key) for key in keys if getattr(args, key, None) not in (None, "")}
params = {key: getattr(args, key) for key in keys if getattr(args, key, None) not in (None, "", [])}
params.update({key: value for key, value in _business_internal_params(args).items() if key not in params})
return params
def _business_internal_params(args: argparse.Namespace) -> dict[str, object]:
params: dict[str, object] = {}
if getattr(args, "internal_parties", None):
params["internal_parties"] = getattr(args, "internal_parties")
if getattr(args, "internal_party_ids", None):
params["internal_party_ids"] = getattr(args, "internal_party_ids")
if getattr(args, "include_internal_orders", False):
params["include_internal_orders"] = True
config = load_config(Path.cwd())
if not params.get("internal_parties"):
parties = os.environ.get("OBSIDIAN_BUSINESS_INTERNAL_PARTIES") or config.get("OBSIDIAN_BUSINESS_INTERNAL_PARTIES")
if parties:
params["internal_parties"] = parties
if not params.get("internal_party_ids"):
party_ids = os.environ.get("OBSIDIAN_BUSINESS_INTERNAL_PARTY_IDS") or config.get("OBSIDIAN_BUSINESS_INTERNAL_PARTY_IDS")
if party_ids:
params["internal_party_ids"] = party_ids
include_internal = os.environ.get("OBSIDIAN_BUSINESS_INCLUDE_INTERNAL_ORDERS") or config.get("OBSIDIAN_BUSINESS_INCLUDE_INTERNAL_ORDERS")
if include_internal and not params.get("include_internal_orders"):
params["include_internal_orders"] = include_internal
return params
def cmd_business_sql(args: argparse.Namespace) -> int:
@@ -859,6 +886,19 @@ def build_parser() -> argparse.ArgumentParser:
bqp.add_argument("--db", metavar="PATH", help="SQLite DB path (defaults to <vault>/_meta/business-facts.sqlite)")
bqp.add_argument("--all-staff", action="store_true", help="include secondary sales and follow-up roles in staff queries")
bqp.add_argument("--fallback-sql", help="guarded read-only SQL to run only when no fixed template matches")
bqp.add_argument(
"--internal-party",
dest="internal_parties",
action="append",
help="internal company name substring to exclude intercompany transfer orders; repeat or comma-separate",
)
bqp.add_argument(
"--internal-party-id",
dest="internal_party_ids",
action="append",
help="internal org/customer code to exclude intercompany transfer orders; repeat or comma-separate",
)
bqp.add_argument("--include-internal-orders", action="store_true", help="include configured internal transfer orders")
bqp.add_argument("--json", action="store_true", help="print machine-readable query result")
bqp.add_argument("question", nargs="+", help="question, e.g. '2026-06 order count'")
bqp.set_defaults(func=cmd_business_query)
@@ -894,6 +934,19 @@ def build_parser() -> argparse.ArgumentParser:
btp.add_argument("--orderstatus", help="Kingdee orderstatus filter")
btp.add_argument("--closestatus", help="Kingdee closestatus filter")
btp.add_argument("--currency", help="currency code filter")
btp.add_argument(
"--internal-party",
dest="internal_parties",
action="append",
help="internal company name substring to exclude intercompany transfer orders; repeat or comma-separate",
)
btp.add_argument(
"--internal-party-id",
dest="internal_party_ids",
action="append",
help="internal org/customer code to exclude intercompany transfer orders; repeat or comma-separate",
)
btp.add_argument("--include-internal-orders", action="store_true", help="include configured internal transfer orders")
btp.add_argument("--json", action="store_true", help="print machine-readable template result")
btp.add_argument("template_name", help="template name from `business schema`")
btp.set_defaults(func=cmd_business_template)