@open-mercato/core 0.6.8-develop.7042.1.413df59570 → 0.6.8-develop.7046.1.153faed87a
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/dist/modules/audit_logs/lib/display-helpers.js +19 -11
- package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/domain-mappings.js +9 -0
- package/dist/modules/customer_accounts/api/admin/domain-mappings.js.map +2 -2
- package/dist/modules/customer_accounts/services/domainMappingService.js +10 -0
- package/dist/modules/customer_accounts/services/domainMappingService.js.map +2 -2
- package/dist/modules/sales/api/documents/factory.js +0 -35
- package/dist/modules/sales/api/documents/factory.js.map +2 -2
- package/dist/modules/sales/commands/returns.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/audit_logs/lib/display-helpers.tsx +42 -32
- package/src/modules/customer_accounts/api/admin/domain-mappings.ts +7 -0
- package/src/modules/customer_accounts/services/domainMappingService.ts +10 -0
- package/src/modules/sales/api/documents/factory.ts +0 -41
- package/src/modules/sales/commands/returns.ts +4 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.6.8-develop.
|
|
3
|
+
"version": "0.6.8-develop.7046.1.153faed87a",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -252,16 +252,16 @@
|
|
|
252
252
|
"zod": "^4.4.3"
|
|
253
253
|
},
|
|
254
254
|
"peerDependencies": {
|
|
255
|
-
"@open-mercato/ai-assistant": "0.6.8-develop.
|
|
256
|
-
"@open-mercato/shared": "0.6.8-develop.
|
|
257
|
-
"@open-mercato/ui": "0.6.8-develop.
|
|
255
|
+
"@open-mercato/ai-assistant": "0.6.8-develop.7046.1.153faed87a",
|
|
256
|
+
"@open-mercato/shared": "0.6.8-develop.7046.1.153faed87a",
|
|
257
|
+
"@open-mercato/ui": "0.6.8-develop.7046.1.153faed87a",
|
|
258
258
|
"react": "^19.0.0",
|
|
259
259
|
"react-dom": "^19.0.0"
|
|
260
260
|
},
|
|
261
261
|
"devDependencies": {
|
|
262
|
-
"@open-mercato/ai-assistant": "0.6.8-develop.
|
|
263
|
-
"@open-mercato/shared": "0.6.8-develop.
|
|
264
|
-
"@open-mercato/ui": "0.6.8-develop.
|
|
262
|
+
"@open-mercato/ai-assistant": "0.6.8-develop.7046.1.153faed87a",
|
|
263
|
+
"@open-mercato/shared": "0.6.8-develop.7046.1.153faed87a",
|
|
264
|
+
"@open-mercato/ui": "0.6.8-develop.7046.1.153faed87a",
|
|
265
265
|
"@testing-library/dom": "^10.4.1",
|
|
266
266
|
"@testing-library/jest-dom": "^7.0.0",
|
|
267
267
|
"@testing-library/react": "^16.3.1",
|
|
@@ -33,9 +33,9 @@ export function renderValue(value: unknown, fallback: string) {
|
|
|
33
33
|
if (typeof value === 'boolean') return <span>{value ? 'true' : 'false'}</span>
|
|
34
34
|
if (typeof value === 'number' || typeof value === 'bigint') return <span>{String(value)}</span>
|
|
35
35
|
if (value instanceof Date) return <span>{value.toISOString()}</span>
|
|
36
|
-
if (typeof value === 'string') return <span className="
|
|
36
|
+
if (typeof value === 'string') return <span className="wrap-anywhere">{value}</span>
|
|
37
37
|
return (
|
|
38
|
-
<pre className="max-h-40 overflow-y-auto whitespace-pre-wrap
|
|
38
|
+
<pre className="max-h-40 overflow-y-auto whitespace-pre-wrap wrap-anywhere rounded-md bg-muted/50 px-2 py-1 text-xs leading-5 text-muted-foreground">
|
|
39
39
|
{safeStringify(value)}
|
|
40
40
|
</pre>
|
|
41
41
|
)
|
|
@@ -76,43 +76,53 @@ export type ChangedFieldsTableProps = {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
export function ChangedFieldsTable({ changeRows, noneLabel, t, beforeLabel, afterLabel }: ChangedFieldsTableProps) {
|
|
79
|
+
const beforeHeading = beforeLabel ?? t('audit_logs.actions.details.before')
|
|
80
|
+
const afterHeading = afterLabel ?? t('audit_logs.actions.details.after')
|
|
79
81
|
return (
|
|
80
82
|
<section>
|
|
81
83
|
<h3 className="text-sm font-semibold">
|
|
82
84
|
{t('audit_logs.actions.details.changed_fields')}
|
|
83
85
|
</h3>
|
|
84
86
|
{changeRows.length ? (
|
|
85
|
-
<div className="mt-2
|
|
86
|
-
<
|
|
87
|
-
<
|
|
88
|
-
<
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
</thead>
|
|
100
|
-
<tbody className="divide-y">
|
|
101
|
-
{changeRows.map((row) => (
|
|
102
|
-
<tr key={row.field} className="align-top">
|
|
103
|
-
<td className="px-4 py-2 align-top font-medium">
|
|
104
|
-
{humanizeField(normalizeChangeField(row.field))}
|
|
105
|
-
</td>
|
|
106
|
-
<td className="px-4 py-2">
|
|
107
|
-
{renderValue(row.from, noneLabel)}
|
|
108
|
-
</td>
|
|
109
|
-
<td className="px-4 py-2">
|
|
110
|
-
{renderValue(row.to, noneLabel)}
|
|
111
|
-
</td>
|
|
87
|
+
<div className="@container/changes mt-2">
|
|
88
|
+
<div className="overflow-x-auto rounded-lg border">
|
|
89
|
+
<table className="block w-full divide-y text-sm @lg/changes:table @lg/changes:min-w-full">
|
|
90
|
+
<thead className="hidden bg-muted/50 @lg/changes:table-header-group">
|
|
91
|
+
<tr>
|
|
92
|
+
<th scope="col" className="px-4 py-2 text-left font-medium text-muted-foreground">
|
|
93
|
+
{t('audit_logs.actions.details.field')}
|
|
94
|
+
</th>
|
|
95
|
+
<th scope="col" className="px-4 py-2 text-left font-medium text-muted-foreground">
|
|
96
|
+
{beforeHeading}
|
|
97
|
+
</th>
|
|
98
|
+
<th scope="col" className="px-4 py-2 text-left font-medium text-muted-foreground">
|
|
99
|
+
{afterHeading}
|
|
100
|
+
</th>
|
|
112
101
|
</tr>
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
102
|
+
</thead>
|
|
103
|
+
<tbody className="block divide-y @lg/changes:table-row-group">
|
|
104
|
+
{changeRows.map((row) => (
|
|
105
|
+
<tr key={row.field} className="block px-4 py-3 align-top @lg/changes:table-row @lg/changes:p-0">
|
|
106
|
+
<td className="block font-medium @lg/changes:table-cell @lg/changes:px-4 @lg/changes:py-2 @lg/changes:align-top">
|
|
107
|
+
{humanizeField(normalizeChangeField(row.field))}
|
|
108
|
+
</td>
|
|
109
|
+
<td className="mt-2 block @lg/changes:mt-0 @lg/changes:table-cell @lg/changes:px-4 @lg/changes:py-2">
|
|
110
|
+
<span className="mb-0.5 block text-xs font-medium uppercase tracking-wide text-muted-foreground @lg/changes:hidden">
|
|
111
|
+
{beforeHeading}
|
|
112
|
+
</span>
|
|
113
|
+
{renderValue(row.from, noneLabel)}
|
|
114
|
+
</td>
|
|
115
|
+
<td className="mt-2 block @lg/changes:mt-0 @lg/changes:table-cell @lg/changes:px-4 @lg/changes:py-2">
|
|
116
|
+
<span className="mb-0.5 block text-xs font-medium uppercase tracking-wide text-muted-foreground @lg/changes:hidden">
|
|
117
|
+
{afterHeading}
|
|
118
|
+
</span>
|
|
119
|
+
{renderValue(row.to, noneLabel)}
|
|
120
|
+
</td>
|
|
121
|
+
</tr>
|
|
122
|
+
))}
|
|
123
|
+
</tbody>
|
|
124
|
+
</table>
|
|
125
|
+
</div>
|
|
116
126
|
</div>
|
|
117
127
|
) : (
|
|
118
128
|
<p className="mt-2 text-sm text-muted-foreground">
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { registerDomainSchema } from '@open-mercato/core/modules/customer_accounts/data/validators'
|
|
15
15
|
import {
|
|
16
16
|
DomainMappingService,
|
|
17
|
+
DomainMappingOrgScopeError,
|
|
17
18
|
type ResolveResult,
|
|
18
19
|
} from '@open-mercato/core/modules/customer_accounts/services/domainMappingService'
|
|
19
20
|
import { DomainMapping } from '@open-mercato/core/modules/customer_accounts/data/entities'
|
|
@@ -142,6 +143,12 @@ export async function POST(req: Request) {
|
|
|
142
143
|
{ status: 409 },
|
|
143
144
|
)
|
|
144
145
|
}
|
|
146
|
+
if (err instanceof DomainMappingOrgScopeError) {
|
|
147
|
+
return NextResponse.json(
|
|
148
|
+
{ ok: false, error: 'Organization was not found in the current tenant.' },
|
|
149
|
+
{ status: 400 },
|
|
150
|
+
)
|
|
151
|
+
}
|
|
145
152
|
const message = err instanceof Error ? err.message : 'Failed to register domain'
|
|
146
153
|
return NextResponse.json({ ok: false, error: message }, { status: 500 })
|
|
147
154
|
}
|
|
@@ -9,9 +9,17 @@ import {
|
|
|
9
9
|
import { Organization } from '@open-mercato/core/modules/directory/data/entities'
|
|
10
10
|
import { emitCustomerAccountsEvent } from '@open-mercato/core/modules/customer_accounts/events'
|
|
11
11
|
import { normalizeHostname, tryNormalizeHostname } from '@open-mercato/core/modules/customer_accounts/lib/hostname'
|
|
12
|
+
import { findOrganizationInTenant } from '@open-mercato/core/modules/customer_accounts/lib/organizationLookup'
|
|
12
13
|
import { platformDomains } from '@open-mercato/core/modules/customer_accounts/lib/platformDomains'
|
|
13
14
|
import { detectProxy, isInKnownProxyRange } from '@open-mercato/core/modules/customer_accounts/lib/proxyRanges'
|
|
14
15
|
|
|
16
|
+
export class DomainMappingOrgScopeError extends Error {
|
|
17
|
+
constructor(organizationId: string) {
|
|
18
|
+
super(`[internal] organizationId ${organizationId} does not belong to the caller's tenant`)
|
|
19
|
+
this.name = 'DomainMappingOrgScopeError'
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
15
23
|
const DOMAIN_ROUTING_TAG = 'domain_routing'
|
|
16
24
|
const RESOLVE_KEY_PREFIX = 'domain_routing:resolve'
|
|
17
25
|
const ACTIVE_BY_ORG_KEY_PREFIX = 'domain_routing:active-by-org'
|
|
@@ -269,6 +277,8 @@ export class DomainMappingService {
|
|
|
269
277
|
|
|
270
278
|
async register(input: RegisterInput): Promise<DomainMapping> {
|
|
271
279
|
const hostname = normalizeHostname(input.hostname)
|
|
280
|
+
const organization = await findOrganizationInTenant(this.em, input.organizationId, input.tenantId)
|
|
281
|
+
if (!organization) throw new DomainMappingOrgScopeError(input.organizationId)
|
|
272
282
|
|
|
273
283
|
let replacesDomain: DomainMapping | null = null
|
|
274
284
|
if (input.replacesDomainId) {
|
|
@@ -26,7 +26,6 @@ import { buildIlikeTerm } from '@open-mercato/shared/lib/db/buildIlikeTerm'
|
|
|
26
26
|
import { parseBooleanToken } from '@open-mercato/shared/lib/boolean'
|
|
27
27
|
import { parseIdsParam } from '@open-mercato/shared/lib/crud/ids'
|
|
28
28
|
import type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'
|
|
29
|
-
import { recalculateOrderTotalsForDisplay } from '../../commands/returns'
|
|
30
29
|
import { parseDecryptedFieldValue } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'
|
|
31
30
|
|
|
32
31
|
type DocumentKind = 'order' | 'quote'
|
|
@@ -616,46 +615,6 @@ export function buildDocumentCrudOptions(binding: DocumentBinding) {
|
|
|
616
615
|
afterList: async (payload: any, ctx: CrudCtx) => {
|
|
617
616
|
await attachTags(payload, { ...ctx, bindingKind: binding.kind })
|
|
618
617
|
await attachChannelNames(payload, ctx)
|
|
619
|
-
if (binding.kind === 'order' && Array.isArray(payload?.items) && payload.items.length === 1) {
|
|
620
|
-
const item = payload.items[0] as Record<string, unknown>
|
|
621
|
-
const orderId = typeof item?.id === 'string' ? item.id : null
|
|
622
|
-
const tenantId = typeof item?.tenantId === 'string' ? item.tenantId : ctx?.auth?.tenantId ?? null
|
|
623
|
-
const organizationId =
|
|
624
|
-
typeof item?.organizationId === 'string' ? item.organizationId : ctx?.selectedOrganizationId ?? ctx?.auth?.orgId ?? null
|
|
625
|
-
if (orderId && tenantId && organizationId) {
|
|
626
|
-
const requestEm = ctx?.container?.resolve?.('em') as import('@mikro-orm/postgresql').EntityManager | undefined
|
|
627
|
-
// Display-only totals recalculation: run on a forked EntityManager so
|
|
628
|
-
// the order/line/adjustment entities loaded here never enter the
|
|
629
|
-
// request's Unit of Work. This guarantees a GET can never flush an
|
|
630
|
-
// UPDATE (and thus never advance `updated_at`), which would otherwise
|
|
631
|
-
// surface as a spurious optimistic-lock 409 in another tab.
|
|
632
|
-
const em = requestEm?.fork()
|
|
633
|
-
if (em) {
|
|
634
|
-
const totals = await recalculateOrderTotalsForDisplay(
|
|
635
|
-
em,
|
|
636
|
-
ctx.container,
|
|
637
|
-
orderId,
|
|
638
|
-
{ tenantId, organizationId },
|
|
639
|
-
)
|
|
640
|
-
if (totals) {
|
|
641
|
-
Object.assign(item, {
|
|
642
|
-
subtotalNetAmount: totals.subtotalNetAmount,
|
|
643
|
-
subtotalGrossAmount: totals.subtotalGrossAmount,
|
|
644
|
-
discountTotalAmount: totals.discountTotalAmount,
|
|
645
|
-
taxTotalAmount: totals.taxTotalAmount,
|
|
646
|
-
shippingNetAmount: totals.shippingNetAmount,
|
|
647
|
-
shippingGrossAmount: totals.shippingGrossAmount,
|
|
648
|
-
surchargeTotalAmount: totals.surchargeTotalAmount,
|
|
649
|
-
grandTotalNetAmount: totals.grandTotalNetAmount,
|
|
650
|
-
grandTotalGrossAmount: totals.grandTotalGrossAmount,
|
|
651
|
-
paidTotalAmount: totals.paidTotalAmount,
|
|
652
|
-
refundedTotalAmount: totals.refundedTotalAmount,
|
|
653
|
-
outstandingAmount: totals.outstandingAmount,
|
|
654
|
-
})
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
618
|
},
|
|
660
619
|
},
|
|
661
620
|
}
|
|
@@ -198,8 +198,10 @@ function buildCalculationContext(order: SalesOrder) {
|
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
/**
|
|
201
|
-
* Recalculates order totals (including line-scoped return adjustments)
|
|
202
|
-
*
|
|
201
|
+
* Recalculates order totals (including line-scoped return adjustments) from lines and
|
|
202
|
+
* adjustments. Do not merge this into GET /api/sales/orders responses: provider
|
|
203
|
+
* calculators re-emit shipping/payment fees on top of already-persisted adjustments
|
|
204
|
+
* and make list vs detail totals diverge (#5438). Persist via commands instead.
|
|
203
205
|
*/
|
|
204
206
|
export async function recalculateOrderTotalsForDisplay(
|
|
205
207
|
em: EntityManager,
|