Skip to content

Commit cdec747

Browse files
fix(example-crm): the opportunity dataset's amount measures inherit the tenant currency (#27205)
Fixes #27158 Clause-②: no Metadata-protocol: none ## 维护者速读 - **改了什么:** 删掉 CRM 示例 `opportunity.dataset.ts` 两个金额度量(`total_amount`、`avg_amount`)上的 `currency: 'USD'`,并把 `pipeline.dashboard.ts` 里引用这个键的注释改成币种的实际来源;并去掉看板两个金额标题里写死的 ($)。 - **为什么改:** `amount` 是动态币种字段,写死 USD 会让非美元组织在管道看板上看到 `$`;去掉后度量走「字段 → 组织默认币种」链(ADR-0104 D1,裁决 6464202770 的 G4)。 - **风险与回滚:** 只动示例元数据与一段注释,无产品代码、无契约改动;回滚即 revert 本 PR。 - **先看:** `examples/app-crm/src/datasets/opportunity.dataset.ts`(两行度量);`examples/app-crm/src/dashboards/pipeline.dashboard.ts`(注释)。 - **两分钟验证:** `git grep -n "currency: 'USD'" -- examples/app-crm` 预期零命中;`pnpm --filter @objectstack/example-crm test` 预期 46/46 通过。 - **需要你做的:** 无,席位落地。 ## What changes - `examples/app-crm/src/datasets/opportunity.dataset.ts`: the `total_amount` and `avg_amount` measures over `crm_opportunity.amount` lose `currency: 'USD'`. They now inherit the analytics chain `packages/services/service-analytics/src/analytics-service.ts:3127`, measure `currency` then the field's `defaultCurrency` (fixed mode only) then the tenant default `ctx.currency`. `amount` is a dynamic `Field.currency` with no `currencyConfig`, so the tiles show the tenant default currency. A three-line comment above `measures` says why the key is absent. - `examples/app-crm/src/dashboards/pipeline.dashboard.ts`: the KPI-tile comment said the measures "declare `format` + `currency`". It now says they declare `format`, and that their currency is the `amount` field's (the tenant default). Comment only. - No product code, no spec, no docs edit. `examples/app-crm` is `private: true`, so this PR carries `skip-changeset`. - `pipeline.dashboard.ts`: the `total_pipeline` and `pipeline_by_industry` titles drop their hard-coded `($)` (`'Total Pipeline'`, `'Open Pipeline by Stage'`); the tiles' number face carries the tenant's symbol. Same family, fixed in place on the seat's patch round (addendum 6467121533). ### Q3: confirming the claim's premise (no docs edit) Both sentences the card named already read as shipped on `main` (`2f96d874`, and unchanged at the merged head `031ff70c`): - `content/docs/protocol/objectql/index.mdx:121`: "Money, in the field's fixed currency or the tenant default", example "`1000` (a bare number)". - `content/docs/protocol/objectql/types.mdx:30`: "Store a bare number, no per-record currency code". The section at L290 agrees ("stored as a bare number. The currency is field configuration, never stored per value"). Neither "exchange rates" nor "amount + currency code" survives on either page. That half of the card shipped earlier, so this PR only does G4. ## Tests At head `8f724ac7` (the title patch): `pnpm --filter @objectstack/example-crm test` 6/6 files, 46/46 tests; typecheck exit 0; `objectstack validate` passed; the 34 derived gates all exit 0 (addendum 6467121533). The readings below are the previous head's. No CRM test, pin or generated artifact asserts or quotes the removed keys. I checked with `git grep` for `opportunity_metrics`, `OpportunityDataset` and `opportunity.dataset` across the tree, then for currency or USD in every file it hit. The one service-analytics test that expects `currency` `USD` (`measure-column-aggregate.test.ts:144`) uses its own fixture and a tenant context of `USD`, not the CRM dataset. No assertion was changed. The run on the final head `031ff70c` (after merging `origin/main` `b322b5da`): - `pnpm --filter @objectstack/example-crm test`: Test Files 6 passed (6), Tests 46 passed (46). - `pnpm --filter @objectstack/example-crm typecheck`: `tsc --noEmit` exit 0. - `objectstack validate` (CRM): "Validation passed". It reports no diagnostic that names a currency, a dataset or `opportunity_metrics`. The `field-no-consumers` warnings are pre-existing. - `pnpm --filter @objectstack/spec check:generated`: exit 0. `packages/spec` moved in the merge, so this re-check was needed. No ablation: the change is example metadata and a comment, and it changes no tested behaviour. ## Acceptance notes - **Behaviour change in the example:** a CRM tenant with no default currency set now sees the two amount tiles without a currency symbol. Before, they always showed `$`. This is the ruled Q2 = X outcome: no explicit currency and no tenant default means DISPLAY carries no symbol. - **Same family, not edited (out of scope):** `content/docs/data-modeling/field-type-decision-tree.mdx:228` says "Money needs currency code and decimal handling". This loosely implies a per-value code. - **Same family, not edited (out of scope):** `content/docs/references/data/field.mdx` (CurrencyValue section) is generated from the `@deprecated` `CurrencyValueSchema` (`packages/spec/src/data/field.zod.ts:581`). It publishes a `{ value, currency }` shape with no deprecation note. ADR-0104 D1 deletes that schema, and its removal rides the next spec major. ## Verification Derived gates (`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`): 34 commands. I ran all 34 on head `031ff70c` and each exited 0. `--ran` reconciliation: "34 derived famil(ies) accounted for — 34 run, 0 NOT-MEASURED (a DERIVED zero — all 34 recorded an exit code and none of them is 3)". On the first pass, `check:dual-build-cjs-loads` and `check:i18n-coverage` exited 3 with PREREQUISITE NOT MET because some packages were unbuilt. I built `./packages/**` and both then exited 0. `node scripts/docs-audit/affected-docs.mjs`: "0 docs name something this change touched". CI runs the families outside the derived list. <details><summary>Derived gate list, each with its exit on 031ff70</summary> ```text node scripts/check-closing-keyword-parity.mjs :: exit 0 node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0 node scripts/check-comment-mask-adoption.mjs :: exit 0 node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0 node scripts/check-comment-mask-corpus.mjs :: exit 0 node scripts/check-dts-emitted.mjs --self-test :: exit 0 node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0 node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0 node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0 pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0 pnpm check:ci-filter-parity :: exit 0 pnpm check:cross-package-test-inputs :: exit 0 pnpm check:driver-memory-census :: exit 0 pnpm check:dts-closure :: exit 0 pnpm check:dual-build-cjs-loads :: exit 0 pnpm check:examples-live-imports :: exit 0 pnpm check:gitlink-declared :: exit 0 pnpm check:i18n-coverage :: exit 0 pnpm check:keyed-text-bounds :: exit 0 pnpm check:lean-entry-closure :: exit 0 pnpm check:logger-receiver-detach :: exit 0 pnpm check:nul-bytes :: exit 0 pnpm check:org-identifier :: exit 0 pnpm check:page-declaration-shape :: exit 0 pnpm check:published-files :: exit 0 pnpm check:refd-timer-probe :: exit 0 pnpm check:registry-log-declared :: exit 0 pnpm check:rest-log-spy-declared :: exit 0 pnpm check:sourcemap-no-sources-content :: exit 0 pnpm check:system-context-census :: exit 0 pnpm check:test-source-alias :: exit 0 pnpm check:tier-file-adoption :: exit 0 pnpm check:undeclared-dep-imports :: exit 0 pnpm check:watch-hint-literal :: exit 0 ``` </details> Not governed: the diff touches only `examples/app-crm/src/**`. --- _Generated by [Claude Code](https://claude.ai/code/session_01QSeKYmLevd91XpqGmYf7fU)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent fd73f2b commit cdec747

2 files changed

Lines changed: 11 additions & 7 deletions

File tree

‎examples/app-crm/src/dashboards/pipeline.dashboard.ts‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,16 @@ export const PipelineDashboard: Dashboard = {
3535
columns: 12,
3636
widgets: [
3737
// --- Row 1: KPI tiles -------------------------------------------------
38-
// No `options` on these tiles: the currency face comes from the dataset
39-
// measure (`total_amount` / `avg_amount` declare `format` + `currency` in
40-
// `opportunity.dataset.ts`). A dataset-bound widget reads only the `options`
38+
// No `options` on these tiles: the number face comes from the dataset
39+
// measure (`total_amount` / `avg_amount` declare `format` in
40+
// `opportunity.dataset.ts`; their currency is the `amount` field's, the
41+
// tenant default). A dataset-bound widget reads only the `options`
4142
// keys the spec declares (plus the `description` sub-caption), so an
4243
// `options.format` / `options.currency` here was inert.
4344
{
4445
id: 'total_pipeline',
4546
type: 'metric',
46-
title: 'Total Pipeline ($)',
47+
title: 'Total Pipeline',
4748
description: 'Sum of opportunity amounts across open stages.',
4849
filter: { stage: { $nin: ['closed_won', 'closed_lost'] } },
4950
dataset: 'opportunity_metrics',
@@ -124,7 +125,7 @@ export const PipelineDashboard: Dashboard = {
124125
{
125126
id: 'pipeline_by_industry',
126127
type: 'pie',
127-
title: 'Open Pipeline by Stage ($)',
128+
title: 'Open Pipeline by Stage',
128129
description: 'Open-pipeline revenue split by pipeline stage. Pie/donut/funnel ignore `compareTo`.',
129130
filter: { stage: { $nin: ['closed_won', 'closed_lost'] } },
130131
dataset: 'opportunity_metrics',

‎examples/app-crm/src/datasets/opportunity.dataset.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@ export const OpportunityDataset = defineDataset({
2727
{ name: 'close_date', label: 'Close Date', field: 'close_date', type: 'date', dateGranularity: 'month' },
2828
],
2929

30+
// The amount measures carry no `currency`: they inherit the `amount` field's
31+
// currency, which is the tenant default (ADR-0104 D1). A hard-coded code here
32+
// would print `$` for a tenant whose books are in another currency.
3033
measures: [
3134
{ name: 'opp_count', label: 'Opportunities', aggregate: 'count' },
32-
{ name: 'total_amount', label: 'Total Amount', aggregate: 'sum', field: 'amount', format: '0,0', currency: 'USD' },
33-
{ name: 'avg_amount', label: 'Avg Deal Size', aggregate: 'avg', field: 'amount', format: '0,0', currency: 'USD' },
35+
{ name: 'total_amount', label: 'Total Amount', aggregate: 'sum', field: 'amount', format: '0,0' },
36+
{ name: 'avg_amount', label: 'Avg Deal Size', aggregate: 'avg', field: 'amount', format: '0,0' },
3437
],
3538
});

0 commit comments

Comments
 (0)