@open-mercato/core 0.8.1-develop.7266.1.8e520bbe03 → 0.8.1-develop.7268.1.033c0546d5

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.
Files changed (128) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities.ids.generated.js +0 -4
  3. package/dist/generated/entities.ids.generated.js.map +2 -2
  4. package/dist/generated/entity-fields-registry.js +0 -21
  5. package/dist/generated/entity-fields-registry.js.map +2 -2
  6. package/dist/modules/customers/backend/customers/companies/create/page.js +5 -0
  7. package/dist/modules/customers/backend/customers/companies/create/page.js.map +2 -2
  8. package/dist/modules/wms/di.js +0 -3
  9. package/dist/modules/wms/di.js.map +2 -2
  10. package/generated/entities.ids.generated.ts +0 -4
  11. package/generated/entity-fields-registry.ts +0 -21
  12. package/package.json +7 -7
  13. package/src/modules/auth/i18n/de.json +0 -3
  14. package/src/modules/auth/i18n/en.json +0 -3
  15. package/src/modules/auth/i18n/es.json +0 -3
  16. package/src/modules/auth/i18n/ko.json +0 -3
  17. package/src/modules/auth/i18n/pl.json +0 -3
  18. package/src/modules/customer_accounts/AGENTS.md +1 -1
  19. package/src/modules/customers/backend/customers/companies/create/page.tsx +6 -0
  20. package/src/modules/wms/di.ts +0 -6
  21. package/dist/generated/entities/availability_policy/index.js +0 -41
  22. package/dist/generated/entities/availability_policy/index.js.map +0 -7
  23. package/dist/modules/availability/acl.js +0 -16
  24. package/dist/modules/availability/acl.js.map +0 -7
  25. package/dist/modules/availability/api/check/route.js +0 -95
  26. package/dist/modules/availability/api/check/route.js.map +0 -7
  27. package/dist/modules/availability/api/openapi.js +0 -27
  28. package/dist/modules/availability/api/openapi.js.map +0 -7
  29. package/dist/modules/availability/api/policies/resolve-preview/route.js +0 -58
  30. package/dist/modules/availability/api/policies/resolve-preview/route.js.map +0 -7
  31. package/dist/modules/availability/api/policies/route.js +0 -188
  32. package/dist/modules/availability/api/policies/route.js.map +0 -7
  33. package/dist/modules/availability/backend/availability/check/page.js +0 -185
  34. package/dist/modules/availability/backend/availability/check/page.js.map +0 -7
  35. package/dist/modules/availability/backend/availability/check/page.meta.js +0 -16
  36. package/dist/modules/availability/backend/availability/check/page.meta.js.map +0 -7
  37. package/dist/modules/availability/backend/availability/policies/ResolutionPreviewPanel.js +0 -79
  38. package/dist/modules/availability/backend/availability/policies/ResolutionPreviewPanel.js.map +0 -7
  39. package/dist/modules/availability/backend/availability/policies/ScopeFields.js +0 -53
  40. package/dist/modules/availability/backend/availability/policies/ScopeFields.js.map +0 -7
  41. package/dist/modules/availability/backend/availability/policies/[id]/page.js +0 -152
  42. package/dist/modules/availability/backend/availability/policies/[id]/page.js.map +0 -7
  43. package/dist/modules/availability/backend/availability/policies/[id]/page.meta.js +0 -12
  44. package/dist/modules/availability/backend/availability/policies/[id]/page.meta.js.map +0 -7
  45. package/dist/modules/availability/backend/availability/policies/create/page.js +0 -94
  46. package/dist/modules/availability/backend/availability/policies/create/page.js.map +0 -7
  47. package/dist/modules/availability/backend/availability/policies/create/page.meta.js +0 -12
  48. package/dist/modules/availability/backend/availability/policies/create/page.meta.js.map +0 -7
  49. package/dist/modules/availability/backend/availability/policies/formGroups.js +0 -75
  50. package/dist/modules/availability/backend/availability/policies/formGroups.js.map +0 -7
  51. package/dist/modules/availability/backend/availability/policies/page.js +0 -176
  52. package/dist/modules/availability/backend/availability/policies/page.js.map +0 -7
  53. package/dist/modules/availability/backend/availability/policies/page.meta.js +0 -16
  54. package/dist/modules/availability/backend/availability/policies/page.meta.js.map +0 -7
  55. package/dist/modules/availability/commands/policies.js +0 -312
  56. package/dist/modules/availability/commands/policies.js.map +0 -7
  57. package/dist/modules/availability/commands/scope.js +0 -19
  58. package/dist/modules/availability/commands/scope.js.map +0 -7
  59. package/dist/modules/availability/data/entities.js +0 -95
  60. package/dist/modules/availability/data/entities.js.map +0 -7
  61. package/dist/modules/availability/data/validators.js +0 -53
  62. package/dist/modules/availability/data/validators.js.map +0 -7
  63. package/dist/modules/availability/di.js +0 -41
  64. package/dist/modules/availability/di.js.map +0 -7
  65. package/dist/modules/availability/events.js +0 -18
  66. package/dist/modules/availability/events.js.map +0 -7
  67. package/dist/modules/availability/index.js +0 -15
  68. package/dist/modules/availability/index.js.map +0 -7
  69. package/dist/modules/availability/lib/policyResolution.js +0 -155
  70. package/dist/modules/availability/lib/policyResolution.js.map +0 -7
  71. package/dist/modules/availability/lib/tryResolve.js +0 -11
  72. package/dist/modules/availability/lib/tryResolve.js.map +0 -7
  73. package/dist/modules/availability/migrations/Migration20260922095844_availability.js +0 -16
  74. package/dist/modules/availability/migrations/Migration20260922095844_availability.js.map +0 -7
  75. package/dist/modules/availability/setup.js +0 -12
  76. package/dist/modules/availability/setup.js.map +0 -7
  77. package/dist/modules/wms/lib/availabilityCache.js +0 -85
  78. package/dist/modules/wms/lib/availabilityCache.js.map +0 -7
  79. package/dist/modules/wms/lib/availabilityCalculation.js +0 -178
  80. package/dist/modules/wms/lib/availabilityCalculation.js.map +0 -7
  81. package/dist/modules/wms/lib/availabilityProvider.js +0 -14
  82. package/dist/modules/wms/lib/availabilityProvider.js.map +0 -7
  83. package/dist/modules/wms/lib/sqlInClause.js +0 -9
  84. package/dist/modules/wms/lib/sqlInClause.js.map +0 -7
  85. package/dist/modules/wms/lib/tryResolve.js +0 -11
  86. package/dist/modules/wms/lib/tryResolve.js.map +0 -7
  87. package/dist/modules/wms/subscribers/invalidate-availability-cache.js +0 -16
  88. package/dist/modules/wms/subscribers/invalidate-availability-cache.js.map +0 -7
  89. package/generated/entities/availability_policy/index.ts +0 -19
  90. package/src/modules/availability/acl.ts +0 -12
  91. package/src/modules/availability/api/check/route.ts +0 -114
  92. package/src/modules/availability/api/openapi.ts +0 -28
  93. package/src/modules/availability/api/policies/resolve-preview/route.ts +0 -67
  94. package/src/modules/availability/api/policies/route.ts +0 -224
  95. package/src/modules/availability/backend/availability/check/page.meta.ts +0 -12
  96. package/src/modules/availability/backend/availability/check/page.tsx +0 -223
  97. package/src/modules/availability/backend/availability/policies/ResolutionPreviewPanel.tsx +0 -106
  98. package/src/modules/availability/backend/availability/policies/ScopeFields.tsx +0 -55
  99. package/src/modules/availability/backend/availability/policies/[id]/page.meta.ts +0 -8
  100. package/src/modules/availability/backend/availability/policies/[id]/page.tsx +0 -182
  101. package/src/modules/availability/backend/availability/policies/create/page.meta.ts +0 -8
  102. package/src/modules/availability/backend/availability/policies/create/page.tsx +0 -105
  103. package/src/modules/availability/backend/availability/policies/formGroups.ts +0 -77
  104. package/src/modules/availability/backend/availability/policies/page.meta.ts +0 -12
  105. package/src/modules/availability/backend/availability/policies/page.tsx +0 -196
  106. package/src/modules/availability/commands/policies.ts +0 -358
  107. package/src/modules/availability/commands/scope.ts +0 -26
  108. package/src/modules/availability/data/entities.ts +0 -92
  109. package/src/modules/availability/data/validators.ts +0 -70
  110. package/src/modules/availability/di.ts +0 -54
  111. package/src/modules/availability/events.ts +0 -17
  112. package/src/modules/availability/i18n/de.json +0 -81
  113. package/src/modules/availability/i18n/en.json +0 -81
  114. package/src/modules/availability/i18n/es.json +0 -81
  115. package/src/modules/availability/i18n/ko.json +0 -81
  116. package/src/modules/availability/i18n/pl.json +0 -81
  117. package/src/modules/availability/index.ts +0 -13
  118. package/src/modules/availability/lib/policyResolution.ts +0 -264
  119. package/src/modules/availability/lib/tryResolve.ts +0 -8
  120. package/src/modules/availability/migrations/.snapshot-open-mercato.json +0 -375
  121. package/src/modules/availability/migrations/Migration20260922095844_availability.ts +0 -13
  122. package/src/modules/availability/setup.ts +0 -10
  123. package/src/modules/wms/lib/availabilityCache.ts +0 -136
  124. package/src/modules/wms/lib/availabilityCalculation.ts +0 -289
  125. package/src/modules/wms/lib/availabilityProvider.ts +0 -29
  126. package/src/modules/wms/lib/sqlInClause.ts +0 -21
  127. package/src/modules/wms/lib/tryResolve.ts +0 -8
  128. package/src/modules/wms/subscribers/invalidate-availability-cache.ts +0 -30
@@ -1,264 +0,0 @@
1
- /**
2
- * `AvailabilityPolicy` resolution chain — six levels, most specific wins.
3
- *
4
- * @see .ai/specs/2026-08-14-availability-contract.md §5.2
5
- *
6
- * Resolution design (documented here because §5.2 does not fully spell it
7
- * out — see PLAN.md § Key design decisions):
8
- *
9
- * - Boolean columns (`isStockManaged`, `allowBackorder`, `hideWhenOutOfStock`,
10
- * `isActive`) are NOT NULL, so a matched row's own value is always
11
- * concrete — there is no "unset" to fall through. The single most specific
12
- * EXISTING row decides every boolean field.
13
- * - Nullable columns (`backorderLeadTimeDays`, `preorderReleaseAt`,
14
- * `lowStockThreshold`, `minOrderQuantity`, `maxOrderQuantity`,
15
- * `quantityIncrement`) genuinely cascade: a matched row that leaves the
16
- * field `null` defers to the next-less-specific row, per US-A2's "which
17
- * level currently decides each field" requirement.
18
- *
19
- * `resolveMany()` exists so `wms`'s batched `check()` (§4.2/R4 — one policy
20
- * lookup regardless of item count) can soft-resolve this service and still
21
- * issue exactly one query for the whole batch, rather than one per item.
22
- * `resolve()` is `resolveMany([scope])[0]`, so single-item callers (the admin
23
- * check tool, the resolve-preview endpoint) are unaffected.
24
- */
25
-
26
- import type { EntityManager } from '@mikro-orm/postgresql'
27
- import { AvailabilityPolicy } from '../data/entities'
28
- import { tryResolve } from './tryResolve'
29
-
30
- export type PolicyResolutionScope = {
31
- tenantId: string
32
- organizationId: string
33
- storeId?: string | null
34
- productId: string
35
- variantId?: string | null
36
- }
37
-
38
- export type ResolvedField<T> = {
39
- value: T
40
- /** The `AvailabilityPolicy` row id that decided, or `null` for the module default. */
41
- policySourceId: string | null
42
- }
43
-
44
- export type ResolvedAvailabilityPolicy = {
45
- isStockManaged: ResolvedField<boolean>
46
- allowBackorder: ResolvedField<boolean>
47
- backorderLeadTimeDays: ResolvedField<number | null>
48
- preorderReleaseAt: ResolvedField<Date | null>
49
- lowStockThreshold: ResolvedField<number | null>
50
- minOrderQuantity: ResolvedField<number | null>
51
- maxOrderQuantity: ResolvedField<number | null>
52
- quantityIncrement: ResolvedField<number | null>
53
- hideWhenOutOfStock: ResolvedField<boolean>
54
- isActive: ResolvedField<boolean>
55
- }
56
-
57
- /** The six chain levels, most specific first. `null` = "no row matched this level". */
58
- export type PolicyChainLevel =
59
- | 'variant_store'
60
- | 'variant'
61
- | 'product_store'
62
- | 'product'
63
- | 'store_default'
64
- | 'module_default'
65
-
66
- export const POLICY_CHAIN_LEVELS: PolicyChainLevel[] = [
67
- 'variant_store',
68
- 'variant',
69
- 'product_store',
70
- 'product',
71
- 'store_default',
72
- 'module_default',
73
- ]
74
-
75
- const NULLABLE_FIELDS = [
76
- 'backorderLeadTimeDays',
77
- 'preorderReleaseAt',
78
- 'lowStockThreshold',
79
- 'minOrderQuantity',
80
- 'maxOrderQuantity',
81
- 'quantityIncrement',
82
- ] as const
83
-
84
- const BOOLEAN_FIELDS = ['isStockManaged', 'allowBackorder', 'hideWhenOutOfStock', 'isActive'] as const
85
-
86
- function candidateFilters(scope: PolicyResolutionScope): Array<Record<string, unknown>> {
87
- const storeId = scope.storeId ?? null
88
- const variantId = scope.variantId ?? null
89
- const filters: Array<Record<string, unknown>> = []
90
- if (variantId) {
91
- filters.push({ variantId, storeId })
92
- filters.push({ variantId, storeId: null })
93
- }
94
- filters.push({ productId: scope.productId, variantId: null, storeId })
95
- filters.push({ productId: scope.productId, variantId: null, storeId: null })
96
- filters.push({ productId: null, variantId: null, storeId })
97
- if (storeId) filters.push({ productId: null, variantId: null, storeId: null })
98
- return filters
99
- }
100
-
101
- /** Picks the (up to) five candidate rows for one scope out of a shared, already-loaded candidate pool. */
102
- function matchChainRows(scope: PolicyResolutionScope, pool: AvailabilityPolicy[]): Array<AvailabilityPolicy | null> {
103
- const storeId = scope.storeId ?? null
104
- const variantId = scope.variantId ?? null
105
- const findMatch = (predicate: (row: AvailabilityPolicy) => boolean) => pool.find(predicate) ?? null
106
-
107
- const rows: Array<AvailabilityPolicy | null> = []
108
- if (variantId) {
109
- rows.push(findMatch((r) => r.variantId === variantId && (r.storeId ?? null) === storeId))
110
- rows.push(findMatch((r) => r.variantId === variantId && (r.storeId ?? null) === null))
111
- }
112
- rows.push(findMatch((r) => r.productId === scope.productId && !r.variantId && (r.storeId ?? null) === storeId))
113
- rows.push(findMatch((r) => r.productId === scope.productId && !r.variantId && (r.storeId ?? null) === null))
114
- rows.push(findMatch((r) => !r.productId && !r.variantId && (r.storeId ?? null) === storeId))
115
- // The store-default level cascades store-specific → all-stores, same as
116
- // the variant/product levels above it ("store_id null = applies to all
117
- // stores in the organization", §5.1) — otherwise an org-wide default row
118
- // is invisible to any query that names a concrete store.
119
- if (storeId) rows.push(findMatch((r) => !r.productId && !r.variantId && (r.storeId ?? null) === null))
120
- return rows
121
- }
122
-
123
- function resolveFromRows(
124
- rows: Array<AvailabilityPolicy | null>,
125
- isStockManagedModuleDefault: boolean,
126
- ): ResolvedAvailabilityPolicy {
127
- const firstRow = rows.find((row): row is AvailabilityPolicy => row != null) ?? null
128
- const result = {} as ResolvedAvailabilityPolicy
129
-
130
- for (const field of BOOLEAN_FIELDS) {
131
- if (firstRow) {
132
- ;(result as any)[field] = { value: (firstRow as any)[field], policySourceId: firstRow.id }
133
- } else {
134
- ;(result as any)[field] = { value: false, policySourceId: null }
135
- }
136
- }
137
-
138
- // is_stock_managed's module default is dynamic (wms + profile existence), not a flat `false`.
139
- if (!firstRow) result.isStockManaged = { value: isStockManagedModuleDefault, policySourceId: null }
140
- // is_active's module default is "active" (nothing to deactivate).
141
- if (!firstRow) result.isActive = { value: true, policySourceId: null }
142
-
143
- for (const field of NULLABLE_FIELDS) {
144
- let resolved: ResolvedField<unknown> = { value: null, policySourceId: null }
145
- for (const row of rows) {
146
- if (row && (row as any)[field] != null) {
147
- resolved = { value: (row as any)[field], policySourceId: row.id }
148
- break
149
- }
150
- }
151
- ;(result as any)[field] = resolved
152
- }
153
-
154
- return result
155
- }
156
-
157
- /** `is_stock_managed`'s module default: true when `wms` is enabled and a `ProductInventoryProfile` exists for the item. */
158
- export async function resolveIsStockManagedModuleDefault(
159
- em: EntityManager,
160
- container: { resolve: <T = unknown>(name: string) => T },
161
- scope: { tenantId: string; organizationId: string; productId: string; variantId?: string | null },
162
- ): Promise<boolean> {
163
- const ProductInventoryProfile = tryResolve<new () => unknown>(container, 'ProductInventoryProfile')
164
- if (!ProductInventoryProfile) return false
165
-
166
- const baseFilter = {
167
- tenantId: scope.tenantId,
168
- organizationId: scope.organizationId,
169
- catalogProductId: scope.productId,
170
- deletedAt: null,
171
- }
172
-
173
- if (scope.variantId) {
174
- const variantRow = await em.findOne(ProductInventoryProfile as any, { ...baseFilter, catalogVariantId: scope.variantId })
175
- if (variantRow) return true
176
- }
177
-
178
- const productRow = await em.findOne(ProductInventoryProfile as any, { ...baseFilter, catalogVariantId: null })
179
- return !!productRow
180
- }
181
-
182
- /** Batched module-default check for `resolveMany` — one query for every scope that might need it. */
183
- async function resolveIsStockManagedModuleDefaultMany(
184
- em: EntityManager,
185
- container: { resolve: <T = unknown>(name: string) => T },
186
- scopes: PolicyResolutionScope[],
187
- ): Promise<Map<string, boolean>> {
188
- const ProductInventoryProfile = tryResolve<new () => unknown>(container, 'ProductInventoryProfile')
189
- const results = new Map<string, boolean>()
190
- if (!ProductInventoryProfile || scopes.length === 0) return results
191
-
192
- const first = scopes[0]
193
- const productIds = Array.from(new Set(scopes.map((s) => s.productId)))
194
- const rows = (await em.find(ProductInventoryProfile as any, {
195
- tenantId: first.tenantId,
196
- organizationId: first.organizationId,
197
- deletedAt: null,
198
- catalogProductId: { $in: productIds },
199
- } as any)) as Array<{ catalogProductId: string; catalogVariantId: string | null }>
200
-
201
- const exists = new Set(rows.map((row) => `${row.catalogProductId}:${row.catalogVariantId ?? ''}`))
202
- for (const scope of scopes) {
203
- const variantHit = scope.variantId ? exists.has(`${scope.productId}:${scope.variantId}`) : false
204
- const productHit = exists.has(`${scope.productId}:`)
205
- results.set(scopeKey(scope), variantHit || productHit)
206
- }
207
- return results
208
- }
209
-
210
- function scopeKey(scope: PolicyResolutionScope): string {
211
- return `${scope.productId}:${scope.variantId ?? ''}:${scope.storeId ?? ''}`
212
- }
213
-
214
- export interface PolicyResolutionService {
215
- resolve(em: EntityManager, scope: PolicyResolutionScope): Promise<ResolvedAvailabilityPolicy>
216
- resolveMany(em: EntityManager, scopes: PolicyResolutionScope[]): Promise<ResolvedAvailabilityPolicy[]>
217
- }
218
-
219
- export function createPolicyResolutionService(container: {
220
- resolve: <T = unknown>(name: string) => T
221
- }): PolicyResolutionService {
222
- async function resolveMany(em: EntityManager, scopes: PolicyResolutionScope[]): Promise<ResolvedAvailabilityPolicy[]> {
223
- if (scopes.length === 0) return []
224
-
225
- const first = scopes[0]
226
- const seen = new Set<string>()
227
- const orFilters: Array<Record<string, unknown>> = []
228
- for (const scope of scopes) {
229
- for (const filter of candidateFilters(scope)) {
230
- const key = JSON.stringify(filter)
231
- if (seen.has(key)) continue
232
- seen.add(key)
233
- orFilters.push(filter)
234
- }
235
- }
236
-
237
- const pool = orFilters.length
238
- ? await em.find(AvailabilityPolicy, {
239
- tenantId: first.tenantId,
240
- organizationId: first.organizationId,
241
- deletedAt: null,
242
- $or: orFilters as any,
243
- })
244
- : []
245
-
246
- // Only scopes that resolve to no row at all need the dynamic is_stock_managed
247
- // module default — batch just those.
248
- const rowsByScope = scopes.map((scope) => matchChainRows(scope, pool))
249
- const needsModuleDefault = scopes.filter((scope, index) => !rowsByScope[index].some((row) => row != null))
250
- const moduleDefaults = await resolveIsStockManagedModuleDefaultMany(em, container, needsModuleDefault)
251
-
252
- return scopes.map((scope, index) =>
253
- resolveFromRows(rowsByScope[index], moduleDefaults.get(scopeKey(scope)) ?? false),
254
- )
255
- }
256
-
257
- return {
258
- async resolve(em, scope) {
259
- const [result] = await resolveMany(em, [scope])
260
- return result
261
- },
262
- resolveMany,
263
- }
264
- }
@@ -1,8 +0,0 @@
1
- /** Per-module local soft-resolve helper — see `packages/core/AGENTS.md` § Cross-Module Coupling. */
2
- export function tryResolve<T>(resolver: { resolve: <R = unknown>(name: string) => R }, name: string): T | undefined {
3
- try {
4
- return resolver.resolve<T>(name)
5
- } catch {
6
- return undefined
7
- }
8
- }
@@ -1,375 +0,0 @@
1
- {
2
- "name": "public",
3
- "namespaces": [
4
- "public"
5
- ],
6
- "tables": [
7
- {
8
- "name": "availability_policies",
9
- "schema": "public",
10
- "columns": {
11
- "allow_backorder": {
12
- "name": "allow_backorder",
13
- "type": "boolean",
14
- "unsigned": false,
15
- "autoincrement": false,
16
- "primary": false,
17
- "nullable": false,
18
- "unique": false,
19
- "length": null,
20
- "precision": null,
21
- "scale": null,
22
- "default": "false",
23
- "comment": null,
24
- "collation": null,
25
- "enumItems": [],
26
- "mappedType": "boolean"
27
- },
28
- "backorder_lead_time_days": {
29
- "name": "backorder_lead_time_days",
30
- "type": "int",
31
- "unsigned": false,
32
- "autoincrement": false,
33
- "primary": false,
34
- "nullable": true,
35
- "unique": false,
36
- "length": null,
37
- "precision": null,
38
- "scale": null,
39
- "default": null,
40
- "comment": null,
41
- "collation": null,
42
- "enumItems": [],
43
- "mappedType": "integer"
44
- },
45
- "created_at": {
46
- "name": "created_at",
47
- "type": "timestamptz(6)",
48
- "unsigned": false,
49
- "autoincrement": false,
50
- "primary": false,
51
- "nullable": false,
52
- "unique": false,
53
- "length": 6,
54
- "precision": null,
55
- "scale": null,
56
- "default": null,
57
- "comment": null,
58
- "collation": null,
59
- "enumItems": [],
60
- "mappedType": "datetime"
61
- },
62
- "deleted_at": {
63
- "name": "deleted_at",
64
- "type": "timestamptz(6)",
65
- "unsigned": false,
66
- "autoincrement": false,
67
- "primary": false,
68
- "nullable": true,
69
- "unique": false,
70
- "length": 6,
71
- "precision": null,
72
- "scale": null,
73
- "default": null,
74
- "comment": null,
75
- "collation": null,
76
- "enumItems": [],
77
- "mappedType": "datetime"
78
- },
79
- "hide_when_out_of_stock": {
80
- "name": "hide_when_out_of_stock",
81
- "type": "boolean",
82
- "unsigned": false,
83
- "autoincrement": false,
84
- "primary": false,
85
- "nullable": false,
86
- "unique": false,
87
- "length": null,
88
- "precision": null,
89
- "scale": null,
90
- "default": "false",
91
- "comment": null,
92
- "collation": null,
93
- "enumItems": [],
94
- "mappedType": "boolean"
95
- },
96
- "id": {
97
- "name": "id",
98
- "type": "uuid",
99
- "unsigned": false,
100
- "autoincrement": false,
101
- "primary": true,
102
- "nullable": false,
103
- "unique": false,
104
- "length": null,
105
- "precision": null,
106
- "scale": null,
107
- "default": "gen_random_uuid()",
108
- "comment": null,
109
- "collation": null,
110
- "enumItems": [],
111
- "mappedType": "uuid"
112
- },
113
- "is_active": {
114
- "name": "is_active",
115
- "type": "boolean",
116
- "unsigned": false,
117
- "autoincrement": false,
118
- "primary": false,
119
- "nullable": false,
120
- "unique": false,
121
- "length": null,
122
- "precision": null,
123
- "scale": null,
124
- "default": "true",
125
- "comment": null,
126
- "collation": null,
127
- "enumItems": [],
128
- "mappedType": "boolean"
129
- },
130
- "is_stock_managed": {
131
- "name": "is_stock_managed",
132
- "type": "boolean",
133
- "unsigned": false,
134
- "autoincrement": false,
135
- "primary": false,
136
- "nullable": false,
137
- "unique": false,
138
- "length": null,
139
- "precision": null,
140
- "scale": null,
141
- "default": "false",
142
- "comment": null,
143
- "collation": null,
144
- "enumItems": [],
145
- "mappedType": "boolean"
146
- },
147
- "low_stock_threshold": {
148
- "name": "low_stock_threshold",
149
- "type": "int",
150
- "unsigned": false,
151
- "autoincrement": false,
152
- "primary": false,
153
- "nullable": true,
154
- "unique": false,
155
- "length": null,
156
- "precision": null,
157
- "scale": null,
158
- "default": null,
159
- "comment": null,
160
- "collation": null,
161
- "enumItems": [],
162
- "mappedType": "integer"
163
- },
164
- "max_order_quantity": {
165
- "name": "max_order_quantity",
166
- "type": "int",
167
- "unsigned": false,
168
- "autoincrement": false,
169
- "primary": false,
170
- "nullable": true,
171
- "unique": false,
172
- "length": null,
173
- "precision": null,
174
- "scale": null,
175
- "default": null,
176
- "comment": null,
177
- "collation": null,
178
- "enumItems": [],
179
- "mappedType": "integer"
180
- },
181
- "min_order_quantity": {
182
- "name": "min_order_quantity",
183
- "type": "int",
184
- "unsigned": false,
185
- "autoincrement": false,
186
- "primary": false,
187
- "nullable": true,
188
- "unique": false,
189
- "length": null,
190
- "precision": null,
191
- "scale": null,
192
- "default": null,
193
- "comment": null,
194
- "collation": null,
195
- "enumItems": [],
196
- "mappedType": "integer"
197
- },
198
- "organization_id": {
199
- "name": "organization_id",
200
- "type": "uuid",
201
- "unsigned": false,
202
- "autoincrement": false,
203
- "primary": false,
204
- "nullable": false,
205
- "unique": false,
206
- "length": null,
207
- "precision": null,
208
- "scale": null,
209
- "default": null,
210
- "comment": null,
211
- "collation": null,
212
- "enumItems": [],
213
- "mappedType": "uuid"
214
- },
215
- "preorder_release_at": {
216
- "name": "preorder_release_at",
217
- "type": "timestamptz(6)",
218
- "unsigned": false,
219
- "autoincrement": false,
220
- "primary": false,
221
- "nullable": true,
222
- "unique": false,
223
- "length": 6,
224
- "precision": null,
225
- "scale": null,
226
- "default": null,
227
- "comment": null,
228
- "collation": null,
229
- "enumItems": [],
230
- "mappedType": "datetime"
231
- },
232
- "product_id": {
233
- "name": "product_id",
234
- "type": "uuid",
235
- "unsigned": false,
236
- "autoincrement": false,
237
- "primary": false,
238
- "nullable": true,
239
- "unique": false,
240
- "length": null,
241
- "precision": null,
242
- "scale": null,
243
- "default": null,
244
- "comment": null,
245
- "collation": null,
246
- "enumItems": [],
247
- "mappedType": "uuid"
248
- },
249
- "quantity_increment": {
250
- "name": "quantity_increment",
251
- "type": "int",
252
- "unsigned": false,
253
- "autoincrement": false,
254
- "primary": false,
255
- "nullable": true,
256
- "unique": false,
257
- "length": null,
258
- "precision": null,
259
- "scale": null,
260
- "default": null,
261
- "comment": null,
262
- "collation": null,
263
- "enumItems": [],
264
- "mappedType": "integer"
265
- },
266
- "store_id": {
267
- "name": "store_id",
268
- "type": "uuid",
269
- "unsigned": false,
270
- "autoincrement": false,
271
- "primary": false,
272
- "nullable": true,
273
- "unique": false,
274
- "length": null,
275
- "precision": null,
276
- "scale": null,
277
- "default": null,
278
- "comment": null,
279
- "collation": null,
280
- "enumItems": [],
281
- "mappedType": "uuid"
282
- },
283
- "tenant_id": {
284
- "name": "tenant_id",
285
- "type": "uuid",
286
- "unsigned": false,
287
- "autoincrement": false,
288
- "primary": false,
289
- "nullable": false,
290
- "unique": false,
291
- "length": null,
292
- "precision": null,
293
- "scale": null,
294
- "default": null,
295
- "comment": null,
296
- "collation": null,
297
- "enumItems": [],
298
- "mappedType": "uuid"
299
- },
300
- "updated_at": {
301
- "name": "updated_at",
302
- "type": "timestamptz(6)",
303
- "unsigned": false,
304
- "autoincrement": false,
305
- "primary": false,
306
- "nullable": false,
307
- "unique": false,
308
- "length": 6,
309
- "precision": null,
310
- "scale": null,
311
- "default": null,
312
- "comment": null,
313
- "collation": null,
314
- "enumItems": [],
315
- "mappedType": "datetime"
316
- },
317
- "variant_id": {
318
- "name": "variant_id",
319
- "type": "uuid",
320
- "unsigned": false,
321
- "autoincrement": false,
322
- "primary": false,
323
- "nullable": true,
324
- "unique": false,
325
- "length": null,
326
- "precision": null,
327
- "scale": null,
328
- "default": null,
329
- "comment": null,
330
- "collation": null,
331
- "enumItems": [],
332
- "mappedType": "uuid"
333
- }
334
- },
335
- "indexes": [
336
- {
337
- "columnNames": [
338
- "id"
339
- ],
340
- "composite": false,
341
- "constraint": true,
342
- "keyName": "availability_policies_pkey",
343
- "primary": true,
344
- "unique": true
345
- },
346
- {
347
- "columnNames": [
348
- "tenant_id",
349
- "organization_id"
350
- ],
351
- "composite": true,
352
- "constraint": false,
353
- "keyName": "availability_policies_scope_idx",
354
- "primary": false,
355
- "unique": false
356
- },
357
- {
358
- "columnNames": [],
359
- "composite": false,
360
- "constraint": false,
361
- "keyName": "availability_policies_scope_target_unique",
362
- "primary": false,
363
- "unique": false,
364
- "expression": "create unique index \"availability_policies_scope_target_unique\" on \"availability_policies\" (\"tenant_id\", \"organization_id\", \"store_id\", \"product_id\", \"variant_id\") nulls not distinct where deleted_at is null"
365
- }
366
- ],
367
- "checks": [],
368
- "triggers": [],
369
- "foreignKeys": {},
370
- "comment": null
371
- }
372
- ],
373
- "views": [],
374
- "nativeEnums": {}
375
- }
@@ -1,13 +0,0 @@
1
- import { Migration } from '@mikro-orm/migrations';
2
-
3
- export class Migration20260922095844_availability extends Migration {
4
-
5
- override name = 'Migration20260922095844';
6
-
7
- override up(): void | Promise<void> {
8
- this.addSql(`create table "availability_policies" ("id" uuid not null default gen_random_uuid(), "organization_id" uuid not null, "tenant_id" uuid not null, "store_id" uuid null, "product_id" uuid null, "variant_id" uuid null, "is_stock_managed" boolean not null default false, "allow_backorder" boolean not null default false, "backorder_lead_time_days" int null, "preorder_release_at" timestamptz null, "low_stock_threshold" int null, "min_order_quantity" int null, "max_order_quantity" int null, "quantity_increment" int null, "hide_when_out_of_stock" boolean not null default false, "is_active" boolean not null default true, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, primary key ("id"));`);
9
- this.addSql(`create unique index "availability_policies_scope_target_unique" on "availability_policies" ("tenant_id", "organization_id", "store_id", "product_id", "variant_id") nulls not distinct where deleted_at is null;`);
10
- this.addSql(`create index "availability_policies_scope_idx" on "availability_policies" ("tenant_id", "organization_id");`);
11
- }
12
-
13
- }
@@ -1,10 +0,0 @@
1
- import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
-
3
- export const setup: ModuleSetupConfig = {
4
- defaultRoleFeatures: {
5
- admin: ['availability.*'],
6
- employee: ['availability.policies.view'],
7
- },
8
- }
9
-
10
- export default setup