@dainamite/billing 0.18.0 → 0.19.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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @dainamite/billing
|
|
2
2
|
|
|
3
|
+
## 0.19.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 8834b8b: Require Open Mercato `0.6.7`. Peer ranges move from `^0.6.0` to `^0.6.7` for
|
|
8
|
+
`@open-mercato/core`, `shared`, `ui`, `events` and `queue`, and the MikroORM
|
|
9
|
+
peers from `^7.0.0` to `^7.1.5` (7.1 split the SQL layer into
|
|
10
|
+
`@mikro-orm/sql`, so a shared 7.1 instance is required).
|
|
11
|
+
|
|
12
|
+
No package source changes — this only narrows the supported framework range.
|
|
13
|
+
Consumers on Open Mercato `0.6.0`–`0.6.6` must upgrade before taking these
|
|
14
|
+
versions.
|
|
15
|
+
|
|
16
|
+
Note for consumers running commands with a system identity (`ctx.auth: null`):
|
|
17
|
+
`0.6.7` hardened `ensureTenantScope` / `ensureOrganizationScope`. Those calls
|
|
18
|
+
are still no-ops with `auth: null`, but an unscoped organization command now
|
|
19
|
+
logs a warning and will throw `403` if `OM_ENFORCE_ORG_SCOPE_STRICT=true`.
|
|
20
|
+
|
|
3
21
|
## 0.18.0
|
|
4
22
|
|
|
5
23
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dainamite/billing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Dainamite Billing — lightweight recurring-billing engine for Open Mercato (Bill Runs, one-time / recurring / usage items, draft invoices in core/sales with human approval).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/modules/billing/index.js",
|
|
@@ -117,14 +117,14 @@
|
|
|
117
117
|
}
|
|
118
118
|
},
|
|
119
119
|
"peerDependencies": {
|
|
120
|
-
"@mikro-orm/core": "^7.
|
|
121
|
-
"@mikro-orm/decorators": "^7.
|
|
122
|
-
"@mikro-orm/postgresql": "^7.
|
|
123
|
-
"@open-mercato/core": "^0.6.
|
|
124
|
-
"@open-mercato/events": "^0.6.
|
|
125
|
-
"@open-mercato/queue": "^0.6.
|
|
126
|
-
"@open-mercato/shared": "^0.6.
|
|
127
|
-
"@open-mercato/ui": "^0.6.
|
|
120
|
+
"@mikro-orm/core": "^7.1.5",
|
|
121
|
+
"@mikro-orm/decorators": "^7.1.5",
|
|
122
|
+
"@mikro-orm/postgresql": "^7.1.5",
|
|
123
|
+
"@open-mercato/core": "^0.6.7",
|
|
124
|
+
"@open-mercato/events": "^0.6.7",
|
|
125
|
+
"@open-mercato/queue": "^0.6.7",
|
|
126
|
+
"@open-mercato/shared": "^0.6.7",
|
|
127
|
+
"@open-mercato/ui": "^0.6.7",
|
|
128
128
|
"@tanstack/react-table": "^8.0.0 || ^9.0.0",
|
|
129
129
|
"awilix": "^12.0.0",
|
|
130
130
|
"lucide-react": "^0.400.0",
|
|
@@ -106,7 +106,7 @@ function makeLine(invoice: FakeInvoice, overrides: Partial<FakeLine> = {}): Fake
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
type Env = {
|
|
109
|
-
ctx: { container: { resolve: jest.MockedFunction<(name: string) => unknown> }; auth: { sub?: string } | null }
|
|
109
|
+
ctx: { container: { resolve: jest.MockedFunction<(name: string) => unknown> }; auth: { sub?: string; tenantId?: string; orgId?: string } | null }
|
|
110
110
|
em: {
|
|
111
111
|
findOne: jest.MockedFunction<(entity: unknown, where: unknown) => Promise<unknown>>
|
|
112
112
|
find: jest.MockedFunction<(entity: unknown, where: unknown) => Promise<unknown[]>>
|
|
@@ -131,7 +131,7 @@ function createEnv(
|
|
|
131
131
|
statusEntryPosted?: string | null
|
|
132
132
|
initialLines?: FakeLine[]
|
|
133
133
|
invoiceFinalLines?: FakeLine[]
|
|
134
|
-
auth?: { sub?: string } | null
|
|
134
|
+
auth?: { sub?: string; tenantId?: string; orgId?: string } | null
|
|
135
135
|
testInvoiceRows?: Array<{ id: string }>
|
|
136
136
|
} = {},
|
|
137
137
|
): Env {
|
|
@@ -199,7 +199,7 @@ function createEnv(
|
|
|
199
199
|
return {
|
|
200
200
|
ctx: {
|
|
201
201
|
container,
|
|
202
|
-
auth: options.auth ?? { sub: '99999999-9999-4999-8999-999999999999' },
|
|
202
|
+
auth: options.auth ?? { sub: '99999999-9999-4999-8999-999999999999', tenantId: TENANT, orgId: ORG },
|
|
203
203
|
},
|
|
204
204
|
em,
|
|
205
205
|
persistedEntities,
|
|
@@ -23,7 +23,7 @@ function makeCtx(em: MockEm, gateway: unknown) {
|
|
|
23
23
|
flushOrmEntityChanges: jest.fn(async () => undefined),
|
|
24
24
|
}
|
|
25
25
|
return {
|
|
26
|
-
auth: { sub: '99999999-9999-4999-8999-999999999999' },
|
|
26
|
+
auth: { sub: '99999999-9999-4999-8999-999999999999', tenantId: TENANT, orgId: ORG },
|
|
27
27
|
container: {
|
|
28
28
|
resolve: jest.fn((name: string) => {
|
|
29
29
|
if (name === 'em') return em
|
|
@@ -17,13 +17,15 @@ function prepaidAccount(overrides: Record<string, unknown> = {}) {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
type CtxAuth = { sub?: string; tenantId?: string; orgId?: string } | null
|
|
21
|
+
|
|
22
|
+
function makeCtx(em: MockEm, auth: CtxAuth = { sub: '99999999-9999-4999-8999-999999999999', tenantId: TENANT, orgId: ORG }) {
|
|
21
23
|
const dataEngine = {
|
|
22
24
|
markOrmEntityChange: jest.fn(),
|
|
23
25
|
flushOrmEntityChanges: jest.fn(async () => undefined),
|
|
24
26
|
}
|
|
25
27
|
return {
|
|
26
|
-
auth
|
|
28
|
+
auth,
|
|
27
29
|
container: {
|
|
28
30
|
resolve: jest.fn((name: string) => {
|
|
29
31
|
if (name === 'em') return em
|
|
@@ -54,6 +56,27 @@ describe('adjustTransactionCommand', () => {
|
|
|
54
56
|
expect(em.transactions[0].userId).toBe('99999999-9999-4999-8999-999999999999')
|
|
55
57
|
})
|
|
56
58
|
|
|
59
|
+
// The CPQ↔billing connector runs as a system identity, not a user: it calls
|
|
60
|
+
// the command bus with `auth: null` and carries tenant/organization in the
|
|
61
|
+
// payload instead. Open Mercato 0.6.7 hardened ensureTenantScope from
|
|
62
|
+
// fail-open to fail-closed, but kept `auth: null` a no-op — this test pins
|
|
63
|
+
// that, because the connector has no other guarantee than prose. If a future
|
|
64
|
+
// release closes this branch too, the connector breaks and this fails first.
|
|
65
|
+
it('accepts a system-identity call (auth: null) without a scope error', async () => {
|
|
66
|
+
const em = createPrepaidMockEm({
|
|
67
|
+
account: prepaidAccount(),
|
|
68
|
+
balance: { tenantId: TENANT, billAccountId: ACCT, balance: '100.0000' },
|
|
69
|
+
})
|
|
70
|
+
const ctx = makeCtx(em, null)
|
|
71
|
+
const result = await adjustTransactionCommand.execute(
|
|
72
|
+
{ tenantId: TENANT, organizationId: ORG, billAccountId: ACCT, amount: -10, description: 'Connector debit' } as never,
|
|
73
|
+
ctx as never,
|
|
74
|
+
)
|
|
75
|
+
expect(result.balance).toBe('90.0000')
|
|
76
|
+
expect(em.transactions).toHaveLength(1)
|
|
77
|
+
expect(em.transactions[0].userId).toBeFalsy()
|
|
78
|
+
})
|
|
79
|
+
|
|
57
80
|
it('credits the balance', async () => {
|
|
58
81
|
const em = createPrepaidMockEm({
|
|
59
82
|
account: prepaidAccount(),
|