@happyvertical/smrt-projects 0.40.70 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +19 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -2
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +383 -256
- package/dist/migrations/moneyMinorUnits.d.ts +26 -0
- package/dist/migrations/moneyMinorUnits.d.ts.map +1 -0
- package/dist/models/service-evidence.d.ts +16 -0
- package/dist/models/service-evidence.d.ts.map +1 -1
- package/dist/playground.js +6 -6
- package/dist/playground.js.map +1 -1
- package/dist/services/service-evidence-service.d.ts +8 -0
- package/dist/services/service-evidence-service.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +60 -9
- package/dist/svelte/ServiceEvidenceList.svelte +17 -4
- package/dist/svelte/ServiceEvidenceList.svelte.d.ts.map +1 -1
- package/dist/svelte/components/__tests__/TimeEntryCard.test.js +2 -2
- package/dist/svelte/components/utils.d.ts +10 -1
- package/dist/svelte/components/utils.d.ts.map +1 -1
- package/dist/svelte/components/utils.js +19 -4
- package/dist/svelte/delivery-types.d.ts +2 -0
- package/dist/svelte/delivery-types.d.ts.map +1 -1
- package/dist/svelte/playground.d.ts.map +1 -1
- package/dist/svelte/playground.js +7 -6
- package/dist/svelte/utils.d.ts +10 -1
- package/dist/svelte/utils.d.ts.map +1 -1
- package/dist/svelte/utils.js +19 -4
- package/dist/svelte/utils.test.js +44 -0
- package/package.json +12 -11
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { DatabaseInterface, MinorUnitsPreflightResult, MinorUnitsRescaleResult, MoneyColumnTarget } from '@happyvertical/smrt-core/migrations';
|
|
2
|
+
/** Marker recorded in `_smrt_backfills` once the rescale has run. */
|
|
3
|
+
export declare const PROJECTS_MONEY_MINOR_UNITS_BACKFILL = "@happyvertical/smrt-projects:money-minor-units:v1";
|
|
4
|
+
/** Every projects money column that held major units before #2401. */
|
|
5
|
+
export declare const PROJECTS_MONEY_COLUMNS: MoneyColumnTarget[];
|
|
6
|
+
/**
|
|
7
|
+
* Report what {@link migrateProjectsMoneyToMinorUnits} would do, without
|
|
8
|
+
* writing anything.
|
|
9
|
+
*/
|
|
10
|
+
export declare function preflightProjectsMoneyMinorUnits(db: DatabaseInterface, options?: {
|
|
11
|
+
scale?: number;
|
|
12
|
+
engineHint?: string;
|
|
13
|
+
}): Promise<MinorUnitsPreflightResult>;
|
|
14
|
+
/**
|
|
15
|
+
* Convert every projects money column from floating-point major units to
|
|
16
|
+
* integer minor units. Idempotent via a `_smrt_backfills` marker.
|
|
17
|
+
*
|
|
18
|
+
* @throws `MinorUnitsPreflightError` when a row would be rounded or would
|
|
19
|
+
* overflow `int4` and `force` was not set.
|
|
20
|
+
*/
|
|
21
|
+
export declare function migrateProjectsMoneyToMinorUnits(db: DatabaseInterface, options?: {
|
|
22
|
+
scale?: number;
|
|
23
|
+
engineHint?: string;
|
|
24
|
+
force?: boolean;
|
|
25
|
+
}): Promise<MinorUnitsRescaleResult>;
|
|
26
|
+
//# sourceMappingURL=moneyMinorUnits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moneyMinorUnits.d.ts","sourceRoot":"","sources":["../../src/migrations/moneyMinorUnits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,EAGvB,MAAM,qCAAqC,CAAC;AAE7C,qEAAqE;AACrE,eAAO,MAAM,mCAAmC,sDACK,CAAC;AAEtD,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,EAAE,iBAAiB,EAGrD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,gCAAgC,CAC9C,EAAE,EAAE,iBAAiB,EACrB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACpD,OAAO,CAAC,yBAAyB,CAAC,CAEpC;AAED;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAC9C,EAAE,EAAE,iBAAiB,EACrB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GACrE,OAAO,CAAC,uBAAuB,CAAC,CAMlC"}
|
|
@@ -42,6 +42,15 @@ export declare class ServiceTimeEntry extends SmrtObject {
|
|
|
42
42
|
export declare class ServiceChargeSnapshot extends SmrtObject {
|
|
43
43
|
tenantId: string | null;
|
|
44
44
|
timeEntryId: string;
|
|
45
|
+
/**
|
|
46
|
+
* Client charge in **integer minor units** of {@link currency} — `$19.99` is
|
|
47
|
+
* `1999`. The `= 0` initializer is load-bearing: SMRT maps an integer literal
|
|
48
|
+
* to INTEGER and a decimal literal to DECIMAL (#2401).
|
|
49
|
+
*
|
|
50
|
+
* Copied verbatim from the upstream `ClientCharge.amount`, so the two carry
|
|
51
|
+
* the same unit by construction; a split would land cents in a major-units
|
|
52
|
+
* column with no error anywhere.
|
|
53
|
+
*/
|
|
45
54
|
amount: number;
|
|
46
55
|
currency: string;
|
|
47
56
|
pricingVersion: string;
|
|
@@ -55,6 +64,13 @@ export declare class ServiceChargeSnapshot extends SmrtObject {
|
|
|
55
64
|
export declare class ServiceCompensationSnapshot extends SmrtObject {
|
|
56
65
|
tenantId: string | null;
|
|
57
66
|
timeEntryId: string;
|
|
67
|
+
/**
|
|
68
|
+
* Provider earning in **integer minor units** of {@link currency} (#2401).
|
|
69
|
+
*
|
|
70
|
+
* Converts with {@link ServiceChargeSnapshot.amount}: the delivery margin is
|
|
71
|
+
* `charge - compensation`, so a mixed pair would make that subtraction
|
|
72
|
+
* meaningless.
|
|
73
|
+
*/
|
|
58
74
|
amount: number;
|
|
59
75
|
currency: string;
|
|
60
76
|
termsVersion: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-evidence.d.ts","sourceRoot":"","sources":["../../src/models/service-evidence.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,cAAc,EACd,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EACV,eAAe,EACf,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,aAAa,CAAC;AAiGrB;;;GAGG;AACH,qBAOa,gBAAiB,SAAQ,UAAU;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAI7D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAQ;IACY,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAClC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IAIzE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAQ;IACV,eAAe,EAAE,sBAAsB,CAAW;IAE3E,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAClB,QAAQ,EAAE,MAAM,CAAM;IACtB,MAAM,EAAE,sBAAsB,CAAY;IAC1C,WAAW,EAAE,MAAM,CAAM;IAClD,SAAS,EAAE,IAAI,GAAG,IAAI,CAAQ;IAC9B,OAAO,EAAE,IAAI,GAAG,IAAI,CAAQ;IAC5B,eAAe,EAAE,MAAM,CAAK;IACH,QAAQ,EAAE,MAAM,CAAQ;IACxB,MAAM,EAAE,sBAAsB,CAAW;IAClE,WAAW,EAAE,IAAI,GAAG,IAAI,CAAQ;IAEhC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3C,UAAU,EAAE,IAAI,GAAG,IAAI,CAAQ;IAE/B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAQ;IACjB,YAAY,EAAE,MAAM,CAAM;IACnD,UAAU,EAAE,IAAI,GAAG,IAAI,CAAQ;IAE/B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAQ;IACjB,eAAe,EAAE,MAAM,CAAM;IACtB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC5C,QAAQ,EAAE,MAAM,CAAQ;IAEjD,WAAW,IAAI,eAAe,EAAE;IAGhC,WAAW,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,IAAI;IAG3C,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAGtC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAGjD,aAAa,IAAI,MAAM;IAIR,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YA2BtB,SAAS;CA0BxB;AAED,qBAQa,qBAAsB,SAAQ,UAAU;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IACT,WAAW,EAAE,MAAM,CAAM;IAC7E,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"service-evidence.d.ts","sourceRoot":"","sources":["../../src/models/service-evidence.ts"],"names":[],"mappings":"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"}
|
package/dist/playground.js
CHANGED
|
@@ -8,9 +8,9 @@ var sampleTimeEntries = [
|
|
|
8
8
|
hours: 6.5,
|
|
9
9
|
description: "Editorial governance review and fact-linking pass",
|
|
10
10
|
status: "submitted",
|
|
11
|
-
amount:
|
|
11
|
+
amount: 78e3,
|
|
12
12
|
workerName: "Taylor Rowan",
|
|
13
|
-
hourlyRate:
|
|
13
|
+
hourlyRate: 12e3,
|
|
14
14
|
mileage: 18
|
|
15
15
|
},
|
|
16
16
|
{
|
|
@@ -19,9 +19,9 @@ var sampleTimeEntries = [
|
|
|
19
19
|
hours: 4.25,
|
|
20
20
|
description: "Content workflow instrumentation and approval QA",
|
|
21
21
|
status: "approved",
|
|
22
|
-
amount:
|
|
22
|
+
amount: 51e3,
|
|
23
23
|
workerName: "Jordan Lee",
|
|
24
|
-
hourlyRate:
|
|
24
|
+
hourlyRate: 12e3
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
id: "time-entry-3",
|
|
@@ -29,9 +29,9 @@ var sampleTimeEntries = [
|
|
|
29
29
|
hours: 2,
|
|
30
30
|
description: "Follow-up revisions for contributor feedback",
|
|
31
31
|
status: "draft",
|
|
32
|
-
amount:
|
|
32
|
+
amount: 24e3,
|
|
33
33
|
workerName: "Casey Tran",
|
|
34
|
-
hourlyRate:
|
|
34
|
+
hourlyRate: 12e3
|
|
35
35
|
}
|
|
36
36
|
];
|
|
37
37
|
var totalHours = sampleTimeEntries.reduce((sum, entry) => sum + entry.hours, 0);
|
package/dist/playground.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playground.js","names":[],"sources":["../src/svelte/playground.ts"],"sourcesContent":["import { PROJECTS_MODULE_META } from '../ui.js';\n\nconst noop = () => {};\n\nconst sampleTimeEntries = [\n {\n id: 'time-entry-1',\n date: '2026-03-18T16:00:00.000Z',\n hours: 6.5,\n description: 'Editorial governance review and fact-linking pass',\n status: 'submitted',\n amount:
|
|
1
|
+
{"version":3,"file":"playground.js","names":[],"sources":["../src/svelte/playground.ts"],"sourcesContent":["import { PROJECTS_MODULE_META } from '../ui.js';\n\nconst noop = () => {};\n\n// Money is integer minor units (#2401): 6.5 h x 12000 (=$120.00/h) = 78000.\nconst sampleTimeEntries = [\n {\n id: 'time-entry-1',\n date: '2026-03-18T16:00:00.000Z',\n hours: 6.5,\n description: 'Editorial governance review and fact-linking pass',\n status: 'submitted',\n amount: 78000,\n workerName: 'Taylor Rowan',\n hourlyRate: 12000,\n mileage: 18,\n },\n {\n id: 'time-entry-2',\n date: '2026-03-19T16:00:00.000Z',\n hours: 4.25,\n description: 'Content workflow instrumentation and approval QA',\n status: 'approved',\n amount: 51000,\n workerName: 'Jordan Lee',\n hourlyRate: 12000,\n },\n {\n id: 'time-entry-3',\n date: '2026-03-20T16:00:00.000Z',\n hours: 2,\n description: 'Follow-up revisions for contributor feedback',\n status: 'draft',\n amount: 24000,\n workerName: 'Casey Tran',\n hourlyRate: 12000,\n },\n];\n\nconst totalHours = sampleTimeEntries.reduce(\n (sum, entry) => sum + entry.hours,\n 0,\n);\nconst totalAmount = sampleTimeEntries.reduce(\n (sum, entry) => sum + (entry.amount ?? 0),\n 0,\n);\nconst pendingEntries = sampleTimeEntries.filter(\n (entry) => entry.status === 'submitted',\n);\n\nconst loadApprovalActions = () => import('./components/ApprovalActions.svelte');\nconst loadTimeEntryList = () => import('./components/TimeEntryList.svelte');\nconst loadTimeSummary = () => import('./components/TimeSummary.svelte');\nconst loadDevelopmentBoard = () => import('./DevelopmentBoard.svelte');\nconst loadProjectBoard = () => import('./ProjectBoard.svelte');\n\nexport default {\n packageName: '@happyvertical/smrt-projects',\n displayName: PROJECTS_MODULE_META.displayName,\n description: PROJECTS_MODULE_META.description,\n moduleMeta: PROJECTS_MODULE_META,\n entries: [\n {\n id: 'project-board',\n title: 'Project Board',\n description: 'Controlled provider project board with canonical statuses.',\n loadComponent: loadProjectBoard,\n order: 0,\n props: {\n projectId: 'project-demo',\n statuses: [\n { id: 'todo', name: 'Todo', order: 0 },\n { id: 'done', name: 'Done', order: 1 },\n ],\n items: [\n {\n id: 'item-demo',\n contentId: 'content-demo',\n title: 'Publish project board',\n status: 'Todo',\n fields: {},\n type: 'Issue',\n },\n ],\n },\n modes: { mock: { label: 'Mock' } },\n },\n {\n id: 'development-board',\n title: 'Development Board',\n description: 'Read-only delivery-status projection.',\n loadComponent: loadDevelopmentBoard,\n order: 1,\n props: {\n requests: [\n {\n id: 'request-demo',\n description: 'Publish project board',\n type: 'feature',\n status: 'planned',\n requesterLabel: 'Project owner',\n },\n ],\n },\n modes: { mock: { label: 'Mock' } },\n },\n {\n id: 'time-entry-list',\n title: 'Time Entry List',\n description:\n 'Selectable list view for recent time entries with billing context.',\n loadComponent: loadTimeEntryList,\n order: 2,\n props: {\n entries: sampleTimeEntries,\n selectable: true,\n selectedIds: ['time-entry-1'],\n currency: 'CAD',\n onselectionchange: noop,\n baseHref: '/projects/time-entries',\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n {\n id: 'time-summary',\n title: 'Time Summary',\n description: 'Hours and value summary cards for a project review period.',\n loadComponent: loadTimeSummary,\n order: 3,\n props: {\n totalHours,\n totalAmount,\n pendingHours: pendingEntries.reduce(\n (sum, entry) => sum + entry.hours,\n 0,\n ),\n pendingAmount: pendingEntries.reduce(\n (sum, entry) => sum + (entry.amount ?? 0),\n 0,\n ),\n approvedHours: sampleTimeEntries\n .filter((entry) => entry.status === 'approved')\n .reduce((sum, entry) => sum + entry.hours, 0),\n approvedAmount: sampleTimeEntries\n .filter((entry) => entry.status === 'approved')\n .reduce((sum, entry) => sum + (entry.amount ?? 0), 0),\n entryCount: sampleTimeEntries.length,\n currency: 'CAD',\n showApproved: true,\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n {\n id: 'approval-actions',\n title: 'Approval Actions',\n description:\n 'Status-sensitive action row for approving or returning submitted work.',\n loadComponent: loadApprovalActions,\n order: 4,\n props: {\n status: 'submitted',\n onapprove: noop,\n onreject: noop,\n onedit: noop,\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n ],\n};\n"],"mappings":"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"}
|
|
@@ -19,6 +19,14 @@ export interface RecordServiceTimeInput {
|
|
|
19
19
|
metadata?: Record<string, unknown>;
|
|
20
20
|
}
|
|
21
21
|
export interface CommercialSnapshot {
|
|
22
|
+
/**
|
|
23
|
+
* Integer minor units of `currency` — `$19.99` is `1999` (#2401).
|
|
24
|
+
*
|
|
25
|
+
* Written straight into `ServiceChargeSnapshot.amount` /
|
|
26
|
+
* `ServiceCompensationSnapshot.amount`, which are INTEGER columns, so a
|
|
27
|
+
* resolver that returns major units corrupts the snapshot silently on SQLite
|
|
28
|
+
* and fails with `22P02` on PostgreSQL.
|
|
29
|
+
*/
|
|
22
30
|
amount: number;
|
|
23
31
|
currency?: string;
|
|
24
32
|
version: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-evidence-service.d.ts","sourceRoot":"","sources":["../../src/services/service-evidence-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EACL,+BAA+B,EAC/B,qCAAqC,EACrC,KAAK,gBAAgB,EACrB,0BAA0B,EAC3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EACV,eAAe,EACf,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,sBAAsB,CAAC;IACxC,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAClE,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC1E;AAED,qBAAa,sBAAsB;IAE/B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;gBAHX,OAAO,EAAE,0BAA0B,EACnC,OAAO,EAAE,+BAA+B,EACxC,YAAY,EAAE,qCAAqC,EACnD,UAAU,CAAC,EAAE,yBAAyB,YAAA;WAG5C,MAAM,CACjB,OAAO,GAAE,gBAAqB,EAC9B,UAAU,CAAC,EAAE,yBAAyB,GACrC,OAAO,CAAC,sBAAsB,CAAC;IAc5B,MAAM,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA4ChE,MAAM,CACV,KAAK,EAAE,gBAAgB,EACvB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,gBAAgB,CAAC;IAStB,OAAO,CACX,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GACzD,OAAO,CAAC,gBAAgB,CAAC;IAkGtB,OAAO,CACX,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,gBAAgB,CAAC;CAkB7B"}
|
|
1
|
+
{"version":3,"file":"service-evidence-service.d.ts","sourceRoot":"","sources":["../../src/services/service-evidence-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EACL,+BAA+B,EAC/B,qCAAqC,EACrC,KAAK,gBAAgB,EACrB,0BAA0B,EAC3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EACV,eAAe,EACf,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,sBAAsB,CAAC;IACxC,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;;;;OAOG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAClE,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC1E;AAED,qBAAa,sBAAsB;IAE/B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;gBAHX,OAAO,EAAE,0BAA0B,EACnC,OAAO,EAAE,+BAA+B,EACxC,YAAY,EAAE,qCAAqC,EACnD,UAAU,CAAC,EAAE,yBAAyB,YAAA;WAG5C,MAAM,CACjB,OAAO,GAAE,gBAAqB,EAC9B,UAAU,CAAC,EAAE,yBAAyB,GACrC,OAAO,CAAC,sBAAsB,CAAC;IAc5B,MAAM,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA4ChE,MAAM,CACV,KAAK,EAAE,gBAAgB,EACvB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,gBAAgB,CAAC;IAStB,OAAO,CACX,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GACzD,OAAO,CAAC,gBAAgB,CAAC;IAkGtB,OAAO,CACX,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,gBAAgB,CAAC;CAkB7B"}
|
package/dist/smrt-knowledge.json
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"sensitiveFieldsExcluded": true,
|
|
4
4
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
5
5
|
"packageName": "@happyvertical/smrt-projects",
|
|
6
|
-
"packageVersion": "0.
|
|
6
|
+
"packageVersion": "0.41.0",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
12
|
-
"agents": "
|
|
10
|
+
"manifest": "972016cf4af90a3f972993a944bac1620cfca20fcf28d7729e50774ad8007485",
|
|
11
|
+
"packageJson": "1f241101ce11df6af493f06d501329fcd88445606ad864981f555ef8808211b4",
|
|
12
|
+
"agents": "d7be7e278e0907430f329e3389847f7e83163bf45dee6c919bce60aea119eecc"
|
|
13
13
|
},
|
|
14
14
|
"exports": [
|
|
15
15
|
".",
|
|
@@ -856,6 +856,11 @@
|
|
|
856
856
|
"mode": "optional",
|
|
857
857
|
"field": "tenantId"
|
|
858
858
|
},
|
|
859
|
+
"conflictColumns": [
|
|
860
|
+
"tenant_id",
|
|
861
|
+
"slug",
|
|
862
|
+
"context"
|
|
863
|
+
],
|
|
859
864
|
"surfaces": [
|
|
860
865
|
{
|
|
861
866
|
"kind": "api",
|
|
@@ -1034,6 +1039,11 @@
|
|
|
1034
1039
|
"mode": "required",
|
|
1035
1040
|
"field": "tenantId"
|
|
1036
1041
|
},
|
|
1042
|
+
"conflictColumns": [
|
|
1043
|
+
"tenant_id",
|
|
1044
|
+
"slug",
|
|
1045
|
+
"context"
|
|
1046
|
+
],
|
|
1037
1047
|
"surfaces": [],
|
|
1038
1048
|
"relationshipFeatures": [
|
|
1039
1049
|
"foreignKey",
|
|
@@ -1113,6 +1123,11 @@
|
|
|
1113
1123
|
"mode": "required",
|
|
1114
1124
|
"field": "tenantId"
|
|
1115
1125
|
},
|
|
1126
|
+
"conflictColumns": [
|
|
1127
|
+
"tenant_id",
|
|
1128
|
+
"slug",
|
|
1129
|
+
"context"
|
|
1130
|
+
],
|
|
1116
1131
|
"surfaces": [],
|
|
1117
1132
|
"relationshipFeatures": [
|
|
1118
1133
|
"foreignKey",
|
|
@@ -1680,6 +1695,12 @@
|
|
|
1680
1695
|
"field": "tenantId"
|
|
1681
1696
|
},
|
|
1682
1697
|
"tableStrategy": "sti",
|
|
1698
|
+
"conflictColumns": [
|
|
1699
|
+
"tenant_id",
|
|
1700
|
+
"slug",
|
|
1701
|
+
"context",
|
|
1702
|
+
"_meta_type"
|
|
1703
|
+
],
|
|
1683
1704
|
"surfaces": [
|
|
1684
1705
|
{
|
|
1685
1706
|
"kind": "api",
|
|
@@ -2204,6 +2225,11 @@
|
|
|
2204
2225
|
"mode": "optional",
|
|
2205
2226
|
"field": "tenantId"
|
|
2206
2227
|
},
|
|
2228
|
+
"conflictColumns": [
|
|
2229
|
+
"tenant_id",
|
|
2230
|
+
"slug",
|
|
2231
|
+
"context"
|
|
2232
|
+
],
|
|
2207
2233
|
"surfaces": [
|
|
2208
2234
|
{
|
|
2209
2235
|
"kind": "api",
|
|
@@ -2485,6 +2511,11 @@
|
|
|
2485
2511
|
"mode": "required",
|
|
2486
2512
|
"field": "tenantId"
|
|
2487
2513
|
},
|
|
2514
|
+
"conflictColumns": [
|
|
2515
|
+
"tenant_id",
|
|
2516
|
+
"slug",
|
|
2517
|
+
"context"
|
|
2518
|
+
],
|
|
2488
2519
|
"surfaces": [],
|
|
2489
2520
|
"relationshipFeatures": [
|
|
2490
2521
|
"foreignKey",
|
|
@@ -3457,6 +3488,11 @@
|
|
|
3457
3488
|
"mode": "optional",
|
|
3458
3489
|
"field": "tenantId"
|
|
3459
3490
|
},
|
|
3491
|
+
"conflictColumns": [
|
|
3492
|
+
"tenant_id",
|
|
3493
|
+
"slug",
|
|
3494
|
+
"context"
|
|
3495
|
+
],
|
|
3460
3496
|
"surfaces": [
|
|
3461
3497
|
{
|
|
3462
3498
|
"kind": "api",
|
|
@@ -3932,6 +3968,11 @@
|
|
|
3932
3968
|
"mode": "required",
|
|
3933
3969
|
"field": "tenantId"
|
|
3934
3970
|
},
|
|
3971
|
+
"conflictColumns": [
|
|
3972
|
+
"tenant_id",
|
|
3973
|
+
"slug",
|
|
3974
|
+
"context"
|
|
3975
|
+
],
|
|
3935
3976
|
"surfaces": [],
|
|
3936
3977
|
"relationshipFeatures": [
|
|
3937
3978
|
"foreignKey",
|
|
@@ -4013,6 +4054,11 @@
|
|
|
4013
4054
|
"mode": "required",
|
|
4014
4055
|
"field": "tenantId"
|
|
4015
4056
|
},
|
|
4057
|
+
"conflictColumns": [
|
|
4058
|
+
"tenant_id",
|
|
4059
|
+
"slug",
|
|
4060
|
+
"context"
|
|
4061
|
+
],
|
|
4016
4062
|
"surfaces": [],
|
|
4017
4063
|
"relationshipFeatures": [
|
|
4018
4064
|
"foreignKey",
|
|
@@ -4376,6 +4422,11 @@
|
|
|
4376
4422
|
"mode": "optional",
|
|
4377
4423
|
"field": "tenantId"
|
|
4378
4424
|
},
|
|
4425
|
+
"conflictColumns": [
|
|
4426
|
+
"tenant_id",
|
|
4427
|
+
"slug",
|
|
4428
|
+
"context"
|
|
4429
|
+
],
|
|
4379
4430
|
"surfaces": [
|
|
4380
4431
|
{
|
|
4381
4432
|
"kind": "api",
|
|
@@ -4449,9 +4500,9 @@
|
|
|
4449
4500
|
},
|
|
4450
4501
|
{
|
|
4451
4502
|
"name": "amount",
|
|
4452
|
-
"type": "
|
|
4503
|
+
"type": "integer",
|
|
4453
4504
|
"required": false,
|
|
4454
|
-
"columnType": "
|
|
4505
|
+
"columnType": "INTEGER",
|
|
4455
4506
|
"default": 0
|
|
4456
4507
|
},
|
|
4457
4508
|
{
|
|
@@ -4596,9 +4647,9 @@
|
|
|
4596
4647
|
},
|
|
4597
4648
|
{
|
|
4598
4649
|
"name": "amount",
|
|
4599
|
-
"type": "
|
|
4650
|
+
"type": "integer",
|
|
4600
4651
|
"required": false,
|
|
4601
|
-
"columnType": "
|
|
4652
|
+
"columnType": "INTEGER",
|
|
4602
4653
|
"default": 0
|
|
4603
4654
|
},
|
|
4604
4655
|
{
|
|
@@ -5456,5 +5507,5 @@
|
|
|
5456
5507
|
"polymorphicAssociations": 0,
|
|
5457
5508
|
"uuidColumns": 73
|
|
5458
5509
|
},
|
|
5459
|
-
"agentDoc": "# @happyvertical/smrt-projects\n\nProvider-agnostic project management plus the managed-application delivery\ncontrol plane. Repository and board providers remain canonical; managed apps\nonly receive scoped Project Integration credentials and provider-neutral\nrequest/delivery projections.\n\n## Managed application delivery (#1949)\n\n- `ProjectIntegration` stores capability grants and a sensitive credential\n hash; the raw credential is returned once by\n `ProjectIntegrationCollection.provision()`/`rotate()` and is never persisted.\n Provisioning, rotation, and revocation are append-only audited.\n- The stable requester identity is supplied when authenticating\n `ManagedProjectClient`; request reads are always restricted to that requester\n and integration.\n- `DevelopmentRequest` preserves evidence, origin, discussion, visibility, and\n lifecycle history. `ManagedProjectClient` owns managed intake and\n `DevelopmentRequestService` adds internal triage and work projection.\n- `DevelopmentRequestWorkLink` connects zero-to-many provider-neutral work\n items. Canonical status stays on the link and drives request lifecycle\n projection without granting the managed app provider credentials.\n- `ProjectDeliveryEvent` is idempotent per integration key and sequenced for\n replay. Preview decisions flow through the control-plane adapter, never\n directly to repository providers.\n- `AssistanceRequest` preserves conversational intake before lossless routing\n to Support, Development, or both. `smrt-support` supplies the concrete\n `ProjectAssistanceSupportAdapter`.\n- `ManagedProjectClient` deliberately exposes no repository or board client;\n delivery and assistance use separate capability-gated service facades.\n\n## Shared Professional Service evidence (#1955)\n\n`ServiceTimeEntry` is canonical here on the existing `service_time_entries`\ntable. Planning, development, and support use the same immutable evidence and\ncorrection chain. `SubscriptionServiceCommercialResolver` prices client work\nthrough `smrt-subscriptions` (#1925); provider compensation remains a separate\nresolver and snapshot. See `SERVICE_TIME_MIGRATION.md`.\n\n## Models\n\n| Model | Key Fields | Notes |\n|-------|-----------|-------|\n| **Repository** | `owner`, `name`, `providerType`, `tokenConfigKey` | `sync()`, `getIssues()`, `getPullRequests()` |\n| **Issue** | `repositoryId` (FK), `number`, `title`, `body`, `state`, `labels[]` | `incorporateFeedback()`, `rollback()`, `suggestLabels()` |\n| **PullRequest** | extends Issue + `headRef`, `baseRef`, `merged`, `draft` | STI on Issue table. `summarize()`, `merge()` |\n| **Project** | `projectId`, `title`, `statuses[]`, `statusFieldId` | GitHub Projects V2. `addItem()`, `moveItem()`, `analyzeHealth()` |\n| **Comment** | `issueId` (FK), `body`, `authorLogin` | AI analysis support |\n| **Label** | `repositoryId` (FK), `name`, `color` | |\n\n## Key Patterns\n\n- **Token config reference**: stores env var name (`tokenConfigKey: 'GITHUB_TOKEN'`), not the token itself. Resolved at runtime from `process.env` or `getModuleConfig()`\n- **Living spec** (`incorporateFeedback()`): AI synthesizes issue comments into updated body. Supports preview mode and `rollback()`\n- **Provider-agnostic**: GitHub primary, GitLab/Bitbucket/Azure planned. Uses `@happyvertical/repos` and `@happyvertical/projects` SDK packages\n- **PullRequest is STI on Issue**: shares table, discriminated by `_meta_type`\n\n## Collection Methods\n\nAll collections provide: `discover({ repository, filters })`, `findByRepository(repoId)`, `findOpen(repoId?)`, `batchSync(repository)`.\n\n## Gotchas\n\n- **SDK dependency**: requires `@happyvertical/repos` and `@happyvertical/projects` from SDK\n- **tokenConfigKey not tokenValue**: never store actual tokens in the database\n- **synthesisCount tracks incorporateFeedback calls**: incremented on each apply\n"
|
|
5510
|
+
"agentDoc": "# @happyvertical/smrt-projects\n\nProvider-agnostic project management plus the managed-application delivery\ncontrol plane. Repository and board providers remain canonical; managed apps\nonly receive scoped Project Integration credentials and provider-neutral\nrequest/delivery projections.\n\n## Managed application delivery (#1949)\n\n- `ProjectIntegration` stores capability grants and a sensitive credential\n hash; the raw credential is returned once by\n `ProjectIntegrationCollection.provision()`/`rotate()` and is never persisted.\n Provisioning, rotation, and revocation are append-only audited.\n- The stable requester identity is supplied when authenticating\n `ManagedProjectClient`; request reads are always restricted to that requester\n and integration.\n- `DevelopmentRequest` preserves evidence, origin, discussion, visibility, and\n lifecycle history. `ManagedProjectClient` owns managed intake and\n `DevelopmentRequestService` adds internal triage and work projection.\n- `DevelopmentRequestWorkLink` connects zero-to-many provider-neutral work\n items. Canonical status stays on the link and drives request lifecycle\n projection without granting the managed app provider credentials.\n- `ProjectDeliveryEvent` is idempotent per integration key and sequenced for\n replay. Preview decisions flow through the control-plane adapter, never\n directly to repository providers.\n- `AssistanceRequest` preserves conversational intake before lossless routing\n to Support, Development, or both. `smrt-support` supplies the concrete\n `ProjectAssistanceSupportAdapter`.\n- `ManagedProjectClient` deliberately exposes no repository or board client;\n delivery and assistance use separate capability-gated service facades.\n\n## Shared Professional Service evidence (#1955)\n\n`ServiceTimeEntry` is canonical here on the existing `service_time_entries`\ntable. Planning, development, and support use the same immutable evidence and\ncorrection chain. `SubscriptionServiceCommercialResolver` prices client work\nthrough `smrt-subscriptions` (#1925); provider compensation remains a separate\nresolver and snapshot. See `SERVICE_TIME_MIGRATION.md`.\n\n## Models\n\n| Model | Key Fields | Notes |\n|-------|-----------|-------|\n| **Repository** | `owner`, `name`, `providerType`, `tokenConfigKey` | `sync()`, `getIssues()`, `getPullRequests()` |\n| **Issue** | `repositoryId` (FK), `number`, `title`, `body`, `state`, `labels[]` | `incorporateFeedback()`, `rollback()`, `suggestLabels()` |\n| **PullRequest** | extends Issue + `headRef`, `baseRef`, `merged`, `draft` | STI on Issue table. `summarize()`, `merge()` |\n| **Project** | `projectId`, `title`, `statuses[]`, `statusFieldId` | GitHub Projects V2. `addItem()`, `moveItem()`, `analyzeHealth()` |\n| **Comment** | `issueId` (FK), `body`, `authorLogin` | AI analysis support |\n| **Label** | `repositoryId` (FK), `name`, `color` | |\n\n## Key Patterns\n\n- **Token config reference**: stores env var name (`tokenConfigKey: 'GITHUB_TOKEN'`), not the token itself. Resolved at runtime from `process.env` or `getModuleConfig()`\n- **Living spec** (`incorporateFeedback()`): AI synthesizes issue comments into updated body. Supports preview mode and `rollback()`\n- **Provider-agnostic**: GitHub primary, GitLab/Bitbucket/Azure planned. Uses `@happyvertical/repos` and `@happyvertical/projects` SDK packages\n- **PullRequest is STI on Issue**: shares table, discriminated by `_meta_type`\n\n## Collection Methods\n\nAll collections provide: `discover({ repository, filters })`, `findByRepository(repoId)`, `findOpen(repoId?)`, `batchSync(repository)`.\n\n## Gotchas\n\n- **Money is integer minor units** (cents) — `$19.99` is `1999`.\n `ServiceChargeSnapshot.amount` and `ServiceCompensationSnapshot.amount`\n initialize `= 0`, never `= 0.0`: the integer literal is what maps them to\n INTEGER columns (#2401). The two convert as a pair — the delivery margin is\n `charge - compensation`, an exact integer subtraction with no tolerance —\n and both are fed verbatim by `CommercialSnapshot.amount`, so a resolver that\n returns major units corrupts the snapshot silently on SQLite and fails with\n `22P02` on PostgreSQL. `pnpm --filter @happyvertical/smrt-projects\n test:postgres` is the lane that holds the line.\n- **UI formats by dividing, never by `toFixed`**: `formatCurrency()` and\n `ServiceEvidenceList`'s `money()` scale back to major units using the\n currency's own minor-unit exponent, so zero-decimal currencies (JPY, KRW) are\n not divided.\n- **Migrating an existing database**: `preflightProjectsMoneyMinorUnits(db)`\n reports which columns still hold major units and which rows would be rounded\n or overflow `int4`; `migrateProjectsMoneyToMinorUnits(db)` converts them\n (idempotent via `_smrt_backfills`). On SQLite the values are rescaled but the\n declared type needs the table-rebuild path (#2370). The `int4` ceiling is\n ~2.1e9 minor units (~$21.4M) per column; BIGINT is parked in #2373.\n- **SDK dependency**: requires `@happyvertical/repos` and `@happyvertical/projects` from SDK\n- **tokenConfigKey not tokenValue**: never store actual tokens in the database\n- **synthesisCount tracks incorporateFeedback calls**: incremented on each apply\n"
|
|
5460
5511
|
}
|
|
@@ -10,10 +10,23 @@ export interface Props {
|
|
|
10
10
|
let { entries = [] }: Props = $props();
|
|
11
11
|
const { t } = useI18n();
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Format a minor-units amount for display.
|
|
15
|
+
*
|
|
16
|
+
* Charge and compensation amounts are integer minor units (#2401), so the
|
|
17
|
+
* scale has to be undone before `Intl.NumberFormat`, which expects major units.
|
|
18
|
+
* The currency's own exponent is used rather than a hard-coded 100, so
|
|
19
|
+
* zero-decimal currencies (JPY, KRW) are left alone. The margin below is a
|
|
20
|
+
* subtraction of two integers, so it is exact and needs no tolerance.
|
|
21
|
+
*/
|
|
22
|
+
const money = (amount = 0, currency = 'USD') => {
|
|
23
|
+
const format = new Intl.NumberFormat(undefined, {
|
|
24
|
+
style: 'currency',
|
|
25
|
+
currency,
|
|
26
|
+
});
|
|
27
|
+
const digits = format.resolvedOptions().maximumFractionDigits ?? 2;
|
|
28
|
+
return format.format(amount / 10 ** digits);
|
|
29
|
+
};
|
|
17
30
|
</script>
|
|
18
31
|
|
|
19
32
|
<section
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceEvidenceList.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/ServiceEvidenceList.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAI/D,MAAM,WAAW,KAAK;IACpB,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACjC;
|
|
1
|
+
{"version":3,"file":"ServiceEvidenceList.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/ServiceEvidenceList.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAI/D,MAAM,WAAW,KAAK;IACpB,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACjC;AAkED,QAAA,MAAM,mBAAmB,2CAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}
|
|
@@ -11,8 +11,8 @@ const entry = {
|
|
|
11
11
|
description: 'Implement feature',
|
|
12
12
|
status: 'draft',
|
|
13
13
|
hours: 3,
|
|
14
|
-
hourlyRate: 100
|
|
15
|
-
amount:
|
|
14
|
+
hourlyRate: 10000, // $100.00/h in cents (#2401)
|
|
15
|
+
amount: 30000, // 3 h x $100.00
|
|
16
16
|
workerName: 'Ada Lovelace',
|
|
17
17
|
};
|
|
18
18
|
describe('TimeEntryCard', () => {
|
|
@@ -14,9 +14,11 @@ export interface TimeEntry {
|
|
|
14
14
|
hours: number;
|
|
15
15
|
description: string;
|
|
16
16
|
status: TimeEntryStatus;
|
|
17
|
+
/** Integer minor units of the display currency — $19.99 is 1999 (#2401). */
|
|
17
18
|
amount?: number;
|
|
18
19
|
workerName?: string;
|
|
19
20
|
mileage?: number;
|
|
21
|
+
/** Minor units per hour, so `hours * hourlyRate` is minor units (#2401). */
|
|
20
22
|
hourlyRate?: number;
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
@@ -28,7 +30,14 @@ export declare const statusColors: Record<TimeEntryStatus, string>;
|
|
|
28
30
|
*/
|
|
29
31
|
export declare function formatDate(date: Date | string): string;
|
|
30
32
|
/**
|
|
31
|
-
* Format
|
|
33
|
+
* Format a minor-units amount for display.
|
|
34
|
+
*
|
|
35
|
+
* Money in this package is integer minor units (#2401) — `$19.99` is `1999` —
|
|
36
|
+
* and `Intl.NumberFormat` expects major units, so the scale is undone here.
|
|
37
|
+
* Without it a $19.99 charge renders as $1,999.00.
|
|
38
|
+
*
|
|
39
|
+
* The currency's own minor-unit exponent is used rather than a hard-coded 100,
|
|
40
|
+
* so zero-decimal currencies (JPY, KRW) are not divided by anything.
|
|
32
41
|
*/
|
|
33
42
|
export declare function formatCurrency(amount: number, currency?: Currency): string;
|
|
34
43
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC;AAErC,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,CAAC;AAE9E,uDAAuD;AACvD,MAAM,MAAM,cAAc,GAAG,eAAe,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,eAAe,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAKxD,CAAC;AAEF;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAGtD;AAED
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC;AAErC,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,CAAC;AAE9E,uDAAuD;AACvD,MAAM,MAAM,cAAc,GAAG,eAAe,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,eAAe,CAAC;IACxB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAKxD,CAAC;AAEF;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAGtD;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,QAAgB,GACzB,MAAM,CAcR;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIrD"}
|
|
@@ -18,14 +18,29 @@ export function formatDate(date) {
|
|
|
18
18
|
return d.toLocaleDateString('en-CA', { month: 'short', day: 'numeric' });
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
|
-
* Format
|
|
21
|
+
* Format a minor-units amount for display.
|
|
22
|
+
*
|
|
23
|
+
* Money in this package is integer minor units (#2401) — `$19.99` is `1999` —
|
|
24
|
+
* and `Intl.NumberFormat` expects major units, so the scale is undone here.
|
|
25
|
+
* Without it a $19.99 charge renders as $1,999.00.
|
|
26
|
+
*
|
|
27
|
+
* The currency's own minor-unit exponent is used rather than a hard-coded 100,
|
|
28
|
+
* so zero-decimal currencies (JPY, KRW) are not divided by anything.
|
|
22
29
|
*/
|
|
23
30
|
export function formatCurrency(amount, currency = 'CAD') {
|
|
24
|
-
|
|
31
|
+
// No fraction-digit override: the currency's own exponent is both the scale
|
|
32
|
+
// to undo and the precision to print. Forcing `minimumFractionDigits: 2`
|
|
33
|
+
// (as this did before minor units) would pin `maximumFractionDigits` to 2 as
|
|
34
|
+
// well, so a zero-decimal currency like JPY would report a scale of 2 — and
|
|
35
|
+
// then render `¥1,999.00` for a currency that has no fractional part at all.
|
|
36
|
+
// For CAD/USD the resolved default is already 2, so their output is
|
|
37
|
+
// unchanged.
|
|
38
|
+
const format = new Intl.NumberFormat('en-CA', {
|
|
25
39
|
style: 'currency',
|
|
26
40
|
currency,
|
|
27
|
-
|
|
28
|
-
|
|
41
|
+
});
|
|
42
|
+
const digits = format.resolvedOptions().maximumFractionDigits ?? 2;
|
|
43
|
+
return format.format(amount / 10 ** digits);
|
|
29
44
|
}
|
|
30
45
|
/**
|
|
31
46
|
* Format hours for display (e.g., "8.5h")
|
|
@@ -29,7 +29,9 @@ export interface ServiceEvidenceView {
|
|
|
29
29
|
participant: string;
|
|
30
30
|
durationSeconds: number;
|
|
31
31
|
status: string;
|
|
32
|
+
/** Integer minor units of `currency` (#2401). */
|
|
32
33
|
chargeAmount?: number;
|
|
34
|
+
/** Integer minor units of `currency` (#2401). */
|
|
33
35
|
compensationAmount?: number;
|
|
34
36
|
currency?: string;
|
|
35
37
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delivery-types.d.ts","sourceRoot":"","sources":["../../src/svelte/delivery-types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;CAC7B;AACD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,IAAI,GAAG,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}
|
|
1
|
+
{"version":3,"file":"delivery-types.d.ts","sourceRoot":"","sources":["../../src/svelte/delivery-types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;CAC7B;AACD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,IAAI,GAAG,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playground.d.ts","sourceRoot":"","sources":["../../src/svelte/playground.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"playground.d.ts","sourceRoot":"","sources":["../../src/svelte/playground.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDA,wBA4HE"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PROJECTS_MODULE_META } from '../ui.js';
|
|
2
2
|
const noop = () => { };
|
|
3
|
+
// Money is integer minor units (#2401): 6.5 h x 12000 (=$120.00/h) = 78000.
|
|
3
4
|
const sampleTimeEntries = [
|
|
4
5
|
{
|
|
5
6
|
id: 'time-entry-1',
|
|
@@ -7,9 +8,9 @@ const sampleTimeEntries = [
|
|
|
7
8
|
hours: 6.5,
|
|
8
9
|
description: 'Editorial governance review and fact-linking pass',
|
|
9
10
|
status: 'submitted',
|
|
10
|
-
amount:
|
|
11
|
+
amount: 78000,
|
|
11
12
|
workerName: 'Taylor Rowan',
|
|
12
|
-
hourlyRate:
|
|
13
|
+
hourlyRate: 12000,
|
|
13
14
|
mileage: 18,
|
|
14
15
|
},
|
|
15
16
|
{
|
|
@@ -18,9 +19,9 @@ const sampleTimeEntries = [
|
|
|
18
19
|
hours: 4.25,
|
|
19
20
|
description: 'Content workflow instrumentation and approval QA',
|
|
20
21
|
status: 'approved',
|
|
21
|
-
amount:
|
|
22
|
+
amount: 51000,
|
|
22
23
|
workerName: 'Jordan Lee',
|
|
23
|
-
hourlyRate:
|
|
24
|
+
hourlyRate: 12000,
|
|
24
25
|
},
|
|
25
26
|
{
|
|
26
27
|
id: 'time-entry-3',
|
|
@@ -28,9 +29,9 @@ const sampleTimeEntries = [
|
|
|
28
29
|
hours: 2,
|
|
29
30
|
description: 'Follow-up revisions for contributor feedback',
|
|
30
31
|
status: 'draft',
|
|
31
|
-
amount:
|
|
32
|
+
amount: 24000,
|
|
32
33
|
workerName: 'Casey Tran',
|
|
33
|
-
hourlyRate:
|
|
34
|
+
hourlyRate: 12000,
|
|
34
35
|
},
|
|
35
36
|
];
|
|
36
37
|
const totalHours = sampleTimeEntries.reduce((sum, entry) => sum + entry.hours, 0);
|
package/dist/svelte/utils.d.ts
CHANGED
|
@@ -14,9 +14,11 @@ export interface TimeEntry {
|
|
|
14
14
|
hours: number;
|
|
15
15
|
description: string;
|
|
16
16
|
status: TimeEntryStatus;
|
|
17
|
+
/** Integer minor units of the display currency — $19.99 is 1999 (#2401). */
|
|
17
18
|
amount?: number;
|
|
18
19
|
workerName?: string;
|
|
19
20
|
mileage?: number;
|
|
21
|
+
/** Minor units per hour, so `hours * hourlyRate` is minor units (#2401). */
|
|
20
22
|
hourlyRate?: number;
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
@@ -28,7 +30,14 @@ export declare const statusColors: Record<TimeEntryStatus, string>;
|
|
|
28
30
|
*/
|
|
29
31
|
export declare function formatDate(date: Date | string): string;
|
|
30
32
|
/**
|
|
31
|
-
* Format
|
|
33
|
+
* Format a minor-units amount for display.
|
|
34
|
+
*
|
|
35
|
+
* Money in this package is integer minor units (#2401) — `$19.99` is `1999` —
|
|
36
|
+
* and `Intl.NumberFormat` expects major units, so the scale is undone here.
|
|
37
|
+
* Without it a $19.99 charge renders as $1,999.00.
|
|
38
|
+
*
|
|
39
|
+
* The currency's own minor-unit exponent is used rather than a hard-coded 100,
|
|
40
|
+
* so zero-decimal currencies (JPY, KRW) are not divided by anything.
|
|
32
41
|
*/
|
|
33
42
|
export declare function formatCurrency(amount: number, currency?: Currency): string;
|
|
34
43
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/svelte/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC;AAErC,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,CAAC;AAE9E,uDAAuD;AACvD,MAAM,MAAM,cAAc,GAAG,eAAe,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,eAAe,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAKxD,CAAC;AAEF;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAGtD;AAED
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/svelte/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC;AAErC,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,CAAC;AAE9E,uDAAuD;AACvD,MAAM,MAAM,cAAc,GAAG,eAAe,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,eAAe,CAAC;IACxB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAKxD,CAAC;AAEF;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAGtD;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,QAAgB,GACzB,MAAM,CAcR;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIrD"}
|
package/dist/svelte/utils.js
CHANGED
|
@@ -18,14 +18,29 @@ export function formatDate(date) {
|
|
|
18
18
|
return d.toLocaleDateString('en-CA', { month: 'short', day: 'numeric' });
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
|
-
* Format
|
|
21
|
+
* Format a minor-units amount for display.
|
|
22
|
+
*
|
|
23
|
+
* Money in this package is integer minor units (#2401) — `$19.99` is `1999` —
|
|
24
|
+
* and `Intl.NumberFormat` expects major units, so the scale is undone here.
|
|
25
|
+
* Without it a $19.99 charge renders as $1,999.00.
|
|
26
|
+
*
|
|
27
|
+
* The currency's own minor-unit exponent is used rather than a hard-coded 100,
|
|
28
|
+
* so zero-decimal currencies (JPY, KRW) are not divided by anything.
|
|
22
29
|
*/
|
|
23
30
|
export function formatCurrency(amount, currency = 'CAD') {
|
|
24
|
-
|
|
31
|
+
// No fraction-digit override: the currency's own exponent is both the scale
|
|
32
|
+
// to undo and the precision to print. Forcing `minimumFractionDigits: 2`
|
|
33
|
+
// (as this did before minor units) would pin `maximumFractionDigits` to 2 as
|
|
34
|
+
// well, so a zero-decimal currency like JPY would report a scale of 2 — and
|
|
35
|
+
// then render `¥1,999.00` for a currency that has no fractional part at all.
|
|
36
|
+
// For CAD/USD the resolved default is already 2, so their output is
|
|
37
|
+
// unchanged.
|
|
38
|
+
const format = new Intl.NumberFormat('en-CA', {
|
|
25
39
|
style: 'currency',
|
|
26
40
|
currency,
|
|
27
|
-
|
|
28
|
-
|
|
41
|
+
});
|
|
42
|
+
const digits = format.resolvedOptions().maximumFractionDigits ?? 2;
|
|
43
|
+
return format.format(amount / 10 ** digits);
|
|
29
44
|
}
|
|
30
45
|
/**
|
|
31
46
|
* Format hours for display (e.g., "8.5h")
|