@open-mercato/core 0.6.8-develop.7054.1.3c75040822 → 0.6.8-develop.7057.1.61440fc3bc
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/customers/api/people/check-phone/route.js +51 -9
- package/dist/modules/customers/api/people/check-phone/route.js.map +2 -2
- package/dist/modules/customers/lib/findPeopleByAddresses.js +1 -0
- package/dist/modules/customers/lib/findPeopleByAddresses.js.map +2 -2
- package/dist/modules/eudr/commands/statements.js +0 -3
- package/dist/modules/eudr/commands/statements.js.map +2 -2
- package/dist/modules/eudr/data/validators.js +4 -1
- package/dist/modules/eudr/data/validators.js.map +2 -2
- package/dist/modules/warranty_claims/api/assignees/route.js +3 -3
- package/dist/modules/warranty_claims/api/assignees/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/route.js +12 -9
- package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/customers/api/people/check-phone/route.ts +75 -10
- package/src/modules/customers/lib/findPeopleByAddresses.ts +8 -6
- package/src/modules/eudr/commands/statements.ts +0 -3
- package/src/modules/eudr/data/validators.ts +16 -1
- package/src/modules/warranty_claims/api/assignees/route.ts +3 -3
- package/src/modules/warranty_claims/api/portal/claims/route.ts +12 -9
|
@@ -4,12 +4,18 @@ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
|
4
4
|
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
5
5
|
import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
|
|
6
6
|
import { CustomerEntity } from "../../../data/entities.js";
|
|
7
|
+
import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
8
|
+
import { isTenantDataEncryptionEnabled } from "@open-mercato/shared/lib/encryption/toggles";
|
|
9
|
+
import { MATCH_CANDIDATE_LIMIT } from "../../../lib/findPeopleByAddresses.js";
|
|
7
10
|
const querySchema = z.object({
|
|
8
11
|
digits: z.string().regex(/^\d{4,}$/).transform((value) => value.trim())
|
|
9
12
|
});
|
|
10
13
|
const metadata = {
|
|
11
14
|
GET: { requireAuth: true, requireFeatures: ["customers.people.view"] }
|
|
12
15
|
};
|
|
16
|
+
function normalizePhoneDigits(value) {
|
|
17
|
+
return typeof value === "string" ? value.replace(/\D/g, "") : "";
|
|
18
|
+
}
|
|
13
19
|
async function GET(req) {
|
|
14
20
|
const url = new URL(req.url);
|
|
15
21
|
const rawQuery = { digits: url.searchParams.get("digits") };
|
|
@@ -31,17 +37,53 @@ async function GET(req) {
|
|
|
31
37
|
if (allowedOrgIds.size === 0) {
|
|
32
38
|
return NextResponse.json({ match: null });
|
|
33
39
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
if (!isTenantDataEncryptionEnabled()) {
|
|
41
|
+
const qb = em.createQueryBuilder(CustomerEntity, "person");
|
|
42
|
+
qb.select(["person.id", "person.displayName"]);
|
|
43
|
+
qb.where({ kind: "person", deletedAt: null });
|
|
44
|
+
qb.andWhere("person.primary_phone is not null");
|
|
45
|
+
qb.andWhere("regexp_replace(person.primary_phone, '\\D', '', 'g') = ?", [parse.data.digits]);
|
|
46
|
+
if (auth.tenantId) {
|
|
47
|
+
qb.andWhere({ tenantId: auth.tenantId });
|
|
48
|
+
}
|
|
49
|
+
qb.andWhere({ organizationId: { $in: Array.from(allowedOrgIds) } });
|
|
50
|
+
qb.limit(1);
|
|
51
|
+
const fastMatch = await qb.getSingleResult();
|
|
52
|
+
if (fastMatch) {
|
|
53
|
+
return NextResponse.json({
|
|
54
|
+
match: {
|
|
55
|
+
id: fastMatch.id,
|
|
56
|
+
displayName: fastMatch.displayName
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const where = {
|
|
62
|
+
kind: "person",
|
|
63
|
+
deletedAt: null,
|
|
64
|
+
primaryPhone: { $ne: null },
|
|
65
|
+
organizationId: { $in: Array.from(allowedOrgIds) }
|
|
66
|
+
};
|
|
39
67
|
if (auth.tenantId) {
|
|
40
|
-
|
|
68
|
+
where.tenantId = auth.tenantId;
|
|
41
69
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
70
|
+
const candidates = await findWithDecryption(
|
|
71
|
+
em,
|
|
72
|
+
CustomerEntity,
|
|
73
|
+
where,
|
|
74
|
+
{
|
|
75
|
+
limit: MATCH_CANDIDATE_LIMIT,
|
|
76
|
+
orderBy: { createdAt: "DESC" },
|
|
77
|
+
fields: ["id", "displayName", "primaryPhone", "tenantId", "organizationId"]
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
tenantId: auth.tenantId ?? null,
|
|
81
|
+
organizationId: scope?.selectedId ?? auth.orgId ?? null
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
const match = candidates.find(
|
|
85
|
+
(candidate) => normalizePhoneDigits(candidate.primaryPhone) === parse.data.digits
|
|
86
|
+
);
|
|
45
87
|
if (!match) {
|
|
46
88
|
return NextResponse.json({ match: null });
|
|
47
89
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/customers/api/people/check-phone/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CustomerEntity } from '../../../data/entities'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\n\nconst querySchema = z.object({\n digits: z\n .string()\n .regex(/^\\d{4,}$/)\n .transform((value) => value.trim()),\n})\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.people.view'] },\n}\n\nexport async function GET(req: Request) {\n const url = new URL(req.url)\n const rawQuery: Record<string, string | null> = { digits: url.searchParams.get('digits') }\n const parse = querySchema.safeParse(rawQuery)\n\n if (!parse.success) {\n return NextResponse.json({ match: null })\n }\n\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const em = (container.resolve('em') as EntityManager)\n\n const allowedOrgIds = new Set<string>()\n if (scope?.selectedId) allowedOrgIds.add(scope.selectedId)\n if (scope?.filterIds?.length) scope.filterIds.forEach((id) => allowedOrgIds.add(id))\n if (!allowedOrgIds.size && auth.orgId) allowedOrgIds.add(auth.orgId)\n\n if (allowedOrgIds.size === 0) {\n return NextResponse.json({ match: null })\n }\n\n const qb = em.createQueryBuilder(CustomerEntity, 'person')\n
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,0CAA0C;AAEnD,SAAS,sBAAsB;
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport { CustomerEntity } from '../../../data/entities'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { isTenantDataEncryptionEnabled } from '@open-mercato/shared/lib/encryption/toggles'\nimport { MATCH_CANDIDATE_LIMIT } from '../../../lib/findPeopleByAddresses'\n\nconst querySchema = z.object({\n digits: z\n .string()\n .regex(/^\\d{4,}$/)\n .transform((value) => value.trim()),\n})\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.people.view'] },\n}\n\nfunction normalizePhoneDigits(value: string | null | undefined): string {\n return typeof value === 'string' ? value.replace(/\\D/g, '') : ''\n}\n\nexport async function GET(req: Request) {\n const url = new URL(req.url)\n const rawQuery: Record<string, string | null> = { digits: url.searchParams.get('digits') }\n const parse = querySchema.safeParse(rawQuery)\n\n if (!parse.success) {\n return NextResponse.json({ match: null })\n }\n\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const em = (container.resolve('em') as EntityManager)\n\n const allowedOrgIds = new Set<string>()\n if (scope?.selectedId) allowedOrgIds.add(scope.selectedId)\n if (scope?.filterIds?.length) scope.filterIds.forEach((id) => allowedOrgIds.add(id))\n if (!allowedOrgIds.size && auth.orgId) allowedOrgIds.add(auth.orgId)\n\n if (allowedOrgIds.size === 0) {\n return NextResponse.json({ match: null })\n }\n\n // SQL fast path, gated on the encryption toggle: it can only match stored\n // plaintext digits, so running it while tenant data encryption is enabled\n // (the default) would pay a per-row scan that provably returns nothing.\n // When encryption is off it serves the pre-encryption single-query behavior,\n // including legacy plaintext rows. Encrypted rows written before the toggle\n // was turned off are not resolvable by either path by design; plaintext\n // legacy rows under an enabled toggle still resolve through the decrypted\n // scan below, where decryption no-ops on non-ciphertext values.\n if (!isTenantDataEncryptionEnabled()) {\n const qb = em.createQueryBuilder(CustomerEntity, 'person')\n qb.select(['person.id', 'person.displayName'])\n qb.where({ kind: 'person', deletedAt: null })\n qb.andWhere('person.primary_phone is not null')\n qb.andWhere(\"regexp_replace(person.primary_phone, '\\\\D', '', 'g') = ?\", [parse.data.digits])\n if (auth.tenantId) {\n qb.andWhere({ tenantId: auth.tenantId })\n }\n qb.andWhere({ organizationId: { $in: Array.from(allowedOrgIds) } })\n qb.limit(1)\n\n const fastMatch = await qb.getSingleResult()\n if (fastMatch) {\n return NextResponse.json({\n match: {\n id: fastMatch.id,\n displayName: fastMatch.displayName,\n },\n })\n }\n }\n\n // Encryption-on path: primary_phone holds random-IV ciphertext, so digit\n // normalization must run in application code over decrypted rows instead of\n // SQL against the stored column (issue #3840).\n // Encryption-on path: primary_phone holds random-IV ciphertext, so digit\n // normalization must run in application code over decrypted rows instead of\n // SQL against the stored column (issue #3840). The scan is bounded newest-\n // first and projected to the columns the route uses plus tenantId/\n // organizationId, which the decryption path reads per row to resolve each\n // row's own key (a request-level fallback cannot cover multi-org scans or\n // null-tenant sessions). A primary_phone blind index is the exact O(1)\n // follow-up (#5515).\n const where: FilterQuery<CustomerEntity> = {\n kind: 'person',\n deletedAt: null,\n primaryPhone: { $ne: null },\n organizationId: { $in: Array.from(allowedOrgIds) },\n }\n if (auth.tenantId) {\n where.tenantId = auth.tenantId\n }\n\n const candidates = await findWithDecryption(\n em,\n CustomerEntity,\n where,\n {\n limit: MATCH_CANDIDATE_LIMIT,\n orderBy: { createdAt: 'DESC' },\n fields: ['id', 'displayName', 'primaryPhone', 'tenantId', 'organizationId'],\n },\n {\n tenantId: auth.tenantId ?? null,\n organizationId: scope?.selectedId ?? auth.orgId ?? null,\n },\n )\n\n const match = candidates.find(\n (candidate) => normalizePhoneDigits(candidate.primaryPhone) === parse.data.digits,\n )\n if (!match) {\n return NextResponse.json({ match: null })\n }\n\n return NextResponse.json({\n match: {\n id: match.id,\n displayName: match.displayName,\n },\n })\n}\n\nconst phoneCheckSuccessSchema = z.object({\n match: z\n .object({\n id: z.string().uuid(),\n displayName: z.string().nullable(),\n })\n .nullable(),\n})\n\nconst phoneCheckErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Check customer phone number',\n methods: {\n GET: {\n summary: 'Find person by phone digits',\n description: 'Performs an exact digits comparison (stripping non-numeric characters) to determine whether a customer contact matches the provided phone fragment.',\n query: querySchema,\n responses: [\n { status: 200, description: 'Matching contact (if any)', schema: phoneCheckSuccessSchema },\n { status: 401, description: 'Unauthorized', schema: phoneCheckErrorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/lib/findPeopleByAddresses.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerEntity } from '../data/entities'\n\n/**\n * Lower-cases, trims, and dedupes a list of email-shaped strings.\n * Rejects anything that doesn't look like `x@y` (single `@`, not at the start\n * or end, no consecutive `@`).\n */\nexport function normalizeAddresses(input: unknown): string[] {\n if (!Array.isArray(input)) return []\n const seen = new Set<string>()\n const out: string[] = []\n for (const value of input) {\n if (typeof value !== 'string') continue\n const trimmed = value.trim().toLowerCase()\n if (!trimmed) continue\n const at = trimmed.indexOf('@')\n if (at <= 0 || at === trimmed.length - 1 || trimmed.lastIndexOf('@') !== at) continue\n if (seen.has(trimmed)) continue\n seen.add(trimmed)\n out.push(trimmed)\n }\n return out\n}\n\nexport interface MatchedPerson {\n /** customer_entities.id (the anchor for customer_interactions.entity_id). */\n id: string\n /** Lowercased email address. */\n email: string\n}\n\n/**\n * Max
|
|
5
|
-
"mappings": "AACA,SAAS,0BAA0B;AACnC,SAAS,sBAAsB;AAOxB,SAAS,mBAAmB,OAA0B;AAC3D,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO,CAAC;AACnC,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,MAAgB,CAAC;AACvB,aAAW,SAAS,OAAO;AACzB,QAAI,OAAO,UAAU,SAAU;AAC/B,UAAM,UAAU,MAAM,KAAK,EAAE,YAAY;AACzC,QAAI,CAAC,QAAS;AACd,UAAM,KAAK,QAAQ,QAAQ,GAAG;AAC9B,QAAI,MAAM,KAAK,OAAO,QAAQ,SAAS,KAAK,QAAQ,YAAY,GAAG,MAAM,GAAI;AAC7E,QAAI,KAAK,IAAI,OAAO,EAAG;AACvB,SAAK,IAAI,OAAO;AAChB,QAAI,KAAK,OAAO;AAAA,EAClB;AACA,SAAO;AACT;
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerEntity } from '../data/entities'\n\n/**\n * Lower-cases, trims, and dedupes a list of email-shaped strings.\n * Rejects anything that doesn't look like `x@y` (single `@`, not at the start\n * or end, no consecutive `@`).\n */\nexport function normalizeAddresses(input: unknown): string[] {\n if (!Array.isArray(input)) return []\n const seen = new Set<string>()\n const out: string[] = []\n for (const value of input) {\n if (typeof value !== 'string') continue\n const trimmed = value.trim().toLowerCase()\n if (!trimmed) continue\n const at = trimmed.indexOf('@')\n if (at <= 0 || at === trimmed.length - 1 || trimmed.lastIndexOf('@') !== at) continue\n if (seen.has(trimmed)) continue\n seen.add(trimmed)\n out.push(trimmed)\n }\n return out\n}\n\nexport interface MatchedPerson {\n /** customer_entities.id (the anchor for customer_interactions.entity_id). */\n id: string\n /** Lowercased email address. */\n email: string\n}\n\n/**\n * Max rows scanned by in-memory fallback matches over encrypted contact\n * columns (`primary_email` here, `primary_phone` in the check-phone route).\n * These columns are GDPR-encrypted with a random IV (see\n * `customers/encryption.ts`), so they cannot be filtered by value in SQL when\n * tenant data encryption is on \u2014 fallbacks decrypt recent rows and compare in\n * memory instead. Bounded to keep interactive lookups cheap; a blind-index\n * (hash) column per field is the follow-up if tenants outgrow it (#5515).\n */\nexport const MATCH_CANDIDATE_LIMIT = 500\n\n/**\n * Batch lookup of CustomerEntity rows (kind='person') whose `primaryEmail`\n * matches any of the given addresses (case-insensitive), scoped to the tenant\n * and organization. Returns at most one MatchedPerson per resolved person.\n *\n * `primary_email` is encrypted with a non-deterministic IV, so a `WHERE\n * primary_email = ?` filter silently matches nothing when encryption is on. We\n * therefore try a direct equality match first (the fast path when encryption is\n * off) and, for any address it leaves unresolved, fall back to scanning recent\n * decrypted person rows and comparing in memory \u2014 the same dual-mode pattern as\n * `inbox-actions.ts`.\n */\nexport async function findPeopleByAddresses(\n em: EntityManager,\n addresses: string[],\n tenantId: string,\n organizationId: string | null = null,\n): Promise<MatchedPerson[]> {\n const normalized = normalizeAddresses(addresses)\n if (normalized.length === 0) return []\n if (!organizationId) return []\n const dscope = { tenantId, organizationId }\n const resolved = new Map<string, string>()\n\n // Fast path: direct equality match. Matches exactly when tenant data encryption\n // is off; returns nothing against encrypted (random-IV) ciphertext, which the\n // in-memory fallback below covers.\n const direct = (await findWithDecryption(\n em,\n CustomerEntity,\n { primaryEmail: { $in: normalized }, kind: 'person', tenantId, organizationId, deletedAt: null },\n undefined,\n dscope,\n )) as Array<{ id: string; primaryEmail?: string | null }>\n for (const row of direct) {\n const rowEmail = row.primaryEmail?.trim().toLowerCase()\n if (rowEmail && !resolved.has(rowEmail)) resolved.set(rowEmail, row.id)\n }\n\n // Fallback for unresolved addresses (the encryption-on path): scan recent person\n // rows and compare decrypted emails in memory.\n if (normalized.some((email) => !resolved.has(email))) {\n const candidates = (await findWithDecryption(\n em,\n CustomerEntity,\n { kind: 'person', tenantId, organizationId, deletedAt: null },\n { limit: MATCH_CANDIDATE_LIMIT, orderBy: { createdAt: 'DESC' } },\n dscope,\n )) as Array<{ id: string; primaryEmail?: string | null }>\n for (const row of candidates) {\n const rowEmail = row.primaryEmail?.trim().toLowerCase()\n if (rowEmail && !resolved.has(rowEmail)) resolved.set(rowEmail, row.id)\n }\n }\n\n const seen = new Set<string>()\n const out: MatchedPerson[] = []\n for (const email of normalized) {\n const id = resolved.get(email)\n if (!id || seen.has(id)) continue\n seen.add(id)\n out.push({ id, email })\n }\n return out\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,0BAA0B;AACnC,SAAS,sBAAsB;AAOxB,SAAS,mBAAmB,OAA0B;AAC3D,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO,CAAC;AACnC,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,MAAgB,CAAC;AACvB,aAAW,SAAS,OAAO;AACzB,QAAI,OAAO,UAAU,SAAU;AAC/B,UAAM,UAAU,MAAM,KAAK,EAAE,YAAY;AACzC,QAAI,CAAC,QAAS;AACd,UAAM,KAAK,QAAQ,QAAQ,GAAG;AAC9B,QAAI,MAAM,KAAK,OAAO,QAAQ,SAAS,KAAK,QAAQ,YAAY,GAAG,MAAM,GAAI;AAC7E,QAAI,KAAK,IAAI,OAAO,EAAG;AACvB,SAAK,IAAI,OAAO;AAChB,QAAI,KAAK,OAAO;AAAA,EAClB;AACA,SAAO;AACT;AAkBO,MAAM,wBAAwB;AAcrC,eAAsB,sBACpB,IACA,WACA,UACA,iBAAgC,MACN;AAC1B,QAAM,aAAa,mBAAmB,SAAS;AAC/C,MAAI,WAAW,WAAW,EAAG,QAAO,CAAC;AACrC,MAAI,CAAC,eAAgB,QAAO,CAAC;AAC7B,QAAM,SAAS,EAAE,UAAU,eAAe;AAC1C,QAAM,WAAW,oBAAI,IAAoB;AAKzC,QAAM,SAAU,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA,EAAE,cAAc,EAAE,KAAK,WAAW,GAAG,MAAM,UAAU,UAAU,gBAAgB,WAAW,KAAK;AAAA,IAC/F;AAAA,IACA;AAAA,EACF;AACA,aAAW,OAAO,QAAQ;AACxB,UAAM,WAAW,IAAI,cAAc,KAAK,EAAE,YAAY;AACtD,QAAI,YAAY,CAAC,SAAS,IAAI,QAAQ,EAAG,UAAS,IAAI,UAAU,IAAI,EAAE;AAAA,EACxE;AAIA,MAAI,WAAW,KAAK,CAAC,UAAU,CAAC,SAAS,IAAI,KAAK,CAAC,GAAG;AACpD,UAAM,aAAc,MAAM;AAAA,MACxB;AAAA,MACA;AAAA,MACA,EAAE,MAAM,UAAU,UAAU,gBAAgB,WAAW,KAAK;AAAA,MAC5D,EAAE,OAAO,uBAAuB,SAAS,EAAE,WAAW,OAAO,EAAE;AAAA,MAC/D;AAAA,IACF;AACA,eAAW,OAAO,YAAY;AAC5B,YAAM,WAAW,IAAI,cAAc,KAAK,EAAE,YAAY;AACtD,UAAI,YAAY,CAAC,SAAS,IAAI,QAAQ,EAAG,UAAS,IAAI,UAAU,IAAI,EAAE;AAAA,IACxE;AAAA,EACF;AAEA,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,MAAuB,CAAC;AAC9B,aAAW,SAAS,YAAY;AAC9B,UAAM,KAAK,SAAS,IAAI,KAAK;AAC7B,QAAI,CAAC,MAAM,KAAK,IAAI,EAAE,EAAG;AACzB,SAAK,IAAI,EAAE;AACX,QAAI,KAAK,EAAE,IAAI,MAAM,CAAC;AAAA,EACxB;AACA,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -411,9 +411,6 @@ const createStatementCommand = {
|
|
|
411
411
|
if (parsed.status !== void 0 && parsed.status !== "draft") {
|
|
412
412
|
throw new CrudHttpError(400, { error: "eudr.errors.invalidTransition" });
|
|
413
413
|
}
|
|
414
|
-
if (parsed.referenceIssuedAt !== void 0) {
|
|
415
|
-
throw new CrudHttpError(400, { error: "eudr.errors.referenceIssuedAtImmutable" });
|
|
416
|
-
}
|
|
417
414
|
const entityManager = ctx.container.resolve("em").fork();
|
|
418
415
|
let record;
|
|
419
416
|
await runCrudCommandWrite({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/eudr/commands/statements.ts"],
|
|
4
|
-
"sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport type { RequiredEntityData } from '@mikro-orm/core'\nimport {\n parseWithCustomFields,\n emitCrudSideEffects,\n emitCrudUndoSideEffects,\n requireId,\n setCustomFieldsIfAny,\n snapshotsEqual,\n} from '@open-mercato/shared/lib/commands/helpers'\nimport { extractUndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { makeCreateRedo } from '@open-mercato/shared/lib/commands/redo'\nimport { runCrudCommandWrite } from '@open-mercato/shared/lib/commands/runCrudCommandWrite'\nimport { ensureOrganizationScope, ensureTenantScope } from '@open-mercato/shared/lib/commands/scope'\nimport {\n loadCustomFieldSnapshot,\n buildCustomFieldResetMap,\n} from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { CrudEventsConfig, CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { emitEudrLifecycleEvent } from './lifecycle-events'\nimport { E } from '#generated/entities.ids.generated'\nimport { sql } from 'kysely'\nimport { z } from 'zod'\nimport {\n EudrDueDiligenceStatement,\n EudrEvidenceSubmission,\n EudrMitigationAction,\n EudrRiskAssessment,\n} from '../data/entities'\nimport {\n EUDR_STATEMENT_STATUSES,\n statementCreateSchema,\n statementUpdateSchema,\n type EudrStatementStatus,\n type StatementCreateInput,\n type StatementUpdateInput,\n} from '../data/validators'\nimport {\n EUDR_AMEND_GUARDED_FIELDS,\n canTransition,\n evaluateSubmissionGate,\n isAmendWindowOpen,\n type GateAssessmentView,\n type GateSubmissionView,\n} from '../lib/statement-lifecycle'\n\nconst STATEMENT_ENTITY_ID = 'eudr:eudr_due_diligence_statement'\n\ntype ScopedCommandInput = {\n tenantId: string\n organizationId: string\n}\n\ntype StatementSnapshot = {\n id: string\n organizationId: string\n tenantId: string\n title: string\n commodity: string\n referenceNumber: string | null\n verificationNumber: string | null\n status: string\n activityType: string | null\n actorRole: string | null\n referencedStatements: Array<{ referenceNumber: string; verificationNumber?: string | null }>\n quantityKg: string | null\n supplementaryUnit: string | null\n supplementaryQuantity: string | null\n orderId: string | null\n submittedAt: string | null\n referenceIssuedAt: string | null\n orderSnapshot: { orderNumber?: string | null } | null\n notes: string | null\n createdAt: string\n updatedAt: string\n deletedAt: string | null\n custom?: Record<string, unknown> | null\n}\n\ntype StatementUndoPayload = {\n before?: StatementSnapshot | null\n after?: StatementSnapshot | null\n}\n\ntype ScopedStatementCreateInput = StatementCreateInput & ScopedCommandInput\ntype ScopedStatementUpdateInput = StatementUpdateInput & Partial<ScopedCommandInput>\n\ntype StatementCommandResult = {\n entityId: string\n updatedAt?: Date\n}\n\nconst scopedCommandInputSchema = z.object({\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid(),\n})\n\nconst statementCrudIndexer: CrudIndexerConfig<EudrDueDiligenceStatement> = {\n entityType: E.eudr.eudr_due_diligence_statement,\n}\n\nconst statementCrudEvents: CrudEventsConfig<EudrDueDiligenceStatement> = {\n module: 'eudr',\n entity: 'due_diligence_statement',\n persistent: true,\n buildPayload: (emitContext) => ({\n id: emitContext.identifiers.id,\n entityId: emitContext.entity?.id ?? emitContext.identifiers.id,\n organizationId: emitContext.identifiers.organizationId,\n tenantId: emitContext.identifiers.tenantId,\n }),\n}\n\nfunction parseScopedCommandInput(input: unknown): ScopedCommandInput {\n return scopedCommandInputSchema.parse(input)\n}\n\nfunction toNumericString(value: number | null | undefined): string | null {\n return value == null ? null : String(value)\n}\n\nfunction toDate(value: string | null): Date | null {\n return value ? new Date(value) : null\n}\n\nfunction statementSeedFromSnapshot(snapshot: StatementSnapshot): RequiredEntityData<EudrDueDiligenceStatement> {\n return {\n id: snapshot.id,\n organizationId: snapshot.organizationId,\n tenantId: snapshot.tenantId,\n title: snapshot.title,\n commodity: snapshot.commodity,\n referenceNumber: snapshot.referenceNumber,\n verificationNumber: snapshot.verificationNumber,\n status: snapshot.status,\n activityType: snapshot.activityType,\n actorRole: snapshot.actorRole,\n referencedStatements: snapshot.referencedStatements.map((entry) => ({ ...entry })),\n quantityKg: snapshot.quantityKg,\n supplementaryUnit: snapshot.supplementaryUnit,\n supplementaryQuantity: snapshot.supplementaryQuantity,\n orderId: snapshot.orderId,\n submittedAt: toDate(snapshot.submittedAt),\n referenceIssuedAt: toDate(snapshot.referenceIssuedAt),\n orderSnapshot: snapshot.orderSnapshot,\n notes: snapshot.notes,\n createdAt: new Date(snapshot.createdAt),\n updatedAt: new Date(snapshot.updatedAt),\n deletedAt: toDate(snapshot.deletedAt),\n }\n}\n\nasync function loadStatementSnapshot(em: EntityManager, entityId: string): Promise<StatementSnapshot | null> {\n const record = await em.findOne(EudrDueDiligenceStatement, { id: entityId })\n if (!record) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: STATEMENT_ENTITY_ID,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n return {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n title: record.title,\n commodity: record.commodity,\n referenceNumber: record.referenceNumber ?? null,\n verificationNumber: record.verificationNumber ?? null,\n status: record.status,\n activityType: record.activityType ?? null,\n actorRole: record.actorRole ?? null,\n referencedStatements: Array.isArray(record.referencedStatements)\n ? record.referencedStatements.map((entry) => ({ ...entry }))\n : [],\n quantityKg: record.quantityKg ?? null,\n supplementaryUnit: record.supplementaryUnit ?? null,\n supplementaryQuantity: record.supplementaryQuantity ?? null,\n orderId: record.orderId ?? null,\n submittedAt: record.submittedAt ? record.submittedAt.toISOString() : null,\n referenceIssuedAt: record.referenceIssuedAt ? record.referenceIssuedAt.toISOString() : null,\n orderSnapshot: record.orderSnapshot ?? null,\n notes: record.notes ?? null,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString(),\n deletedAt: record.deletedAt ? record.deletedAt.toISOString() : null,\n custom: Object.keys(custom).length ? custom : null,\n }\n}\n\nfunction applyStatementUpdate(record: EudrDueDiligenceStatement, parsed: StatementUpdateInput): void {\n if (parsed.title !== undefined) record.title = parsed.title\n if (parsed.commodity !== undefined) record.commodity = parsed.commodity\n if (parsed.referenceNumber !== undefined) record.referenceNumber = parsed.referenceNumber ?? null\n if (parsed.verificationNumber !== undefined) record.verificationNumber = parsed.verificationNumber ?? null\n if (parsed.status !== undefined) record.status = parsed.status\n if (parsed.activityType !== undefined) record.activityType = parsed.activityType ?? null\n if (parsed.actorRole !== undefined) record.actorRole = parsed.actorRole ?? null\n if (parsed.referencedStatements !== undefined) {\n record.referencedStatements = parsed.referencedStatements.map((entry) => ({ ...entry }))\n }\n if (parsed.quantityKg !== undefined) record.quantityKg = toNumericString(parsed.quantityKg)\n if (parsed.supplementaryUnit !== undefined) record.supplementaryUnit = parsed.supplementaryUnit ?? null\n if (parsed.supplementaryQuantity !== undefined) record.supplementaryQuantity = toNumericString(parsed.supplementaryQuantity)\n if (parsed.orderId !== undefined) record.orderId = parsed.orderId ?? null\n if (parsed.referenceIssuedAt !== undefined) record.referenceIssuedAt = parsed.referenceIssuedAt\n if (parsed.orderSnapshot !== undefined) record.orderSnapshot = parsed.orderSnapshot ?? null\n if (parsed.notes !== undefined) record.notes = parsed.notes ?? null\n}\n\nfunction restoreStatement(record: EudrDueDiligenceStatement, snapshot: StatementSnapshot): void {\n record.organizationId = snapshot.organizationId\n record.tenantId = snapshot.tenantId\n record.title = snapshot.title\n record.commodity = snapshot.commodity\n record.referenceNumber = snapshot.referenceNumber\n record.verificationNumber = snapshot.verificationNumber\n record.status = snapshot.status\n record.activityType = snapshot.activityType\n record.actorRole = snapshot.actorRole\n record.referencedStatements = snapshot.referencedStatements.map((entry) => ({ ...entry }))\n record.quantityKg = snapshot.quantityKg\n record.supplementaryUnit = snapshot.supplementaryUnit\n record.supplementaryQuantity = snapshot.supplementaryQuantity\n record.orderId = snapshot.orderId\n record.submittedAt = toDate(snapshot.submittedAt)\n record.referenceIssuedAt = toDate(snapshot.referenceIssuedAt)\n record.orderSnapshot = snapshot.orderSnapshot\n record.notes = snapshot.notes\n record.createdAt = new Date(snapshot.createdAt)\n record.updatedAt = new Date(snapshot.updatedAt)\n record.deletedAt = toDate(snapshot.deletedAt)\n}\n\nasync function setStatementCustomFields(\n dataEngine: DataEngine,\n entityId: string,\n organizationId: string,\n tenantId: string,\n values: Record<string, unknown>,\n): Promise<void> {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: STATEMENT_ENTITY_ID,\n recordId: entityId,\n organizationId,\n tenantId,\n values,\n notify: false,\n })\n}\n\ntype PatchedStatementView = {\n referenceNumber: string | null\n verificationNumber: string | null\n actorRole: string | null\n referencedStatements: Array<{ referenceNumber: string; verificationNumber?: string | null }>\n}\n\ntype StatementServerFields = {\n submittedAt?: Date\n referenceIssuedAt?: Date | null\n}\n\nconst STATEMENT_STATUS_SET = new Set<string>(EUDR_STATEMENT_STATUSES)\n\nconst STATEMENT_UPDATE_FIELDS = [\n 'title',\n 'commodity',\n 'referenceNumber',\n 'verificationNumber',\n 'status',\n 'activityType',\n 'actorRole',\n 'referencedStatements',\n 'quantityKg',\n 'supplementaryUnit',\n 'supplementaryQuantity',\n 'orderId',\n 'referenceIssuedAt',\n 'orderSnapshot',\n 'notes',\n] as const\n\ntype StatementUpdateField = (typeof STATEMENT_UPDATE_FIELDS)[number]\n\nfunction isStatementStatus(value: string): value is EudrStatementStatus {\n return STATEMENT_STATUS_SET.has(value)\n}\n\nfunction isNonEmpty(value: string | null | undefined): boolean {\n return typeof value === 'string' && value.trim().length > 0\n}\n\nfunction dateValuesEqual(left: Date | null | undefined, right: Date | null | undefined): boolean {\n const leftTime = left ? left.getTime() : null\n const rightTime = right ? right.getTime() : null\n return leftTime === rightTime\n}\n\nfunction jsonValuesEqual(left: unknown, right: unknown): boolean {\n return JSON.stringify(left ?? null) === JSON.stringify(right ?? null)\n}\n\n// PG numeric columns read back scale-padded ('100.000'); compare numerically so\n// an unchanged echo from a whole-document save is not treated as an amendment.\nfunction numericValuesEqual(left: string | null | undefined, right: string | null | undefined): boolean {\n const leftNumber = left === null || left === undefined || left === '' ? null : Number(left)\n const rightNumber = right === null || right === undefined || right === '' ? null : Number(right)\n if (leftNumber === null || rightNumber === null) return leftNumber === rightNumber\n return Number.isFinite(leftNumber) && Number.isFinite(rightNumber) && leftNumber === rightNumber\n}\n\nfunction referencedStatementsEqual(\n left: Array<{ referenceNumber: string; verificationNumber?: string | null }> | null | undefined,\n right: Array<{ referenceNumber: string; verificationNumber?: string | null }> | null | undefined,\n): boolean {\n return JSON.stringify(left ?? []) === JSON.stringify(right ?? [])\n}\n\nfunction statementFieldChanged(\n record: EudrDueDiligenceStatement,\n parsed: StatementUpdateInput,\n field: StatementUpdateField,\n): boolean {\n switch (field) {\n case 'title':\n return parsed.title !== undefined && parsed.title !== record.title\n case 'commodity':\n return parsed.commodity !== undefined && parsed.commodity !== record.commodity\n case 'referenceNumber':\n return parsed.referenceNumber !== undefined && (parsed.referenceNumber ?? null) !== (record.referenceNumber ?? null)\n case 'verificationNumber':\n return parsed.verificationNumber !== undefined && (parsed.verificationNumber ?? null) !== (record.verificationNumber ?? null)\n case 'status':\n return parsed.status !== undefined && parsed.status !== record.status\n case 'activityType':\n return parsed.activityType !== undefined && (parsed.activityType ?? null) !== (record.activityType ?? null)\n case 'actorRole':\n return parsed.actorRole !== undefined && (parsed.actorRole ?? null) !== (record.actorRole ?? null)\n case 'referencedStatements':\n return parsed.referencedStatements !== undefined && !referencedStatementsEqual(parsed.referencedStatements, record.referencedStatements)\n case 'quantityKg':\n return parsed.quantityKg !== undefined && !numericValuesEqual(toNumericString(parsed.quantityKg), record.quantityKg ?? null)\n case 'supplementaryUnit':\n return parsed.supplementaryUnit !== undefined && (parsed.supplementaryUnit ?? null) !== (record.supplementaryUnit ?? null)\n case 'supplementaryQuantity':\n return parsed.supplementaryQuantity !== undefined && !numericValuesEqual(toNumericString(parsed.supplementaryQuantity), record.supplementaryQuantity ?? null)\n case 'orderId':\n return parsed.orderId !== undefined && (parsed.orderId ?? null) !== (record.orderId ?? null)\n case 'referenceIssuedAt':\n return parsed.referenceIssuedAt !== undefined && !dateValuesEqual(parsed.referenceIssuedAt, record.referenceIssuedAt ?? null)\n case 'orderSnapshot':\n return parsed.orderSnapshot !== undefined && !jsonValuesEqual(parsed.orderSnapshot ?? null, record.orderSnapshot ?? null)\n case 'notes':\n return parsed.notes !== undefined && (parsed.notes ?? null) !== (record.notes ?? null)\n }\n}\n\nfunction hasStatementFieldChanges(record: EudrDueDiligenceStatement, parsed: StatementUpdateInput): boolean {\n return STATEMENT_UPDATE_FIELDS.some((field) => statementFieldChanged(record, parsed, field))\n}\n\nfunction buildPatchedStatementView(record: EudrDueDiligenceStatement, parsed: StatementUpdateInput): PatchedStatementView {\n return {\n referenceNumber: parsed.referenceNumber !== undefined ? parsed.referenceNumber ?? null : record.referenceNumber ?? null,\n verificationNumber: parsed.verificationNumber !== undefined ? parsed.verificationNumber ?? null : record.verificationNumber ?? null,\n actorRole: parsed.actorRole !== undefined ? parsed.actorRole ?? null : record.actorRole ?? null,\n referencedStatements: parsed.referencedStatements !== undefined\n ? parsed.referencedStatements.map((entry) => ({ ...entry }))\n : Array.isArray(record.referencedStatements)\n ? record.referencedStatements.map((entry) => ({ ...entry }))\n : [],\n }\n}\n\nfunction hasChangedAmendGuardedField(record: EudrDueDiligenceStatement, parsed: StatementUpdateInput): boolean {\n return EUDR_AMEND_GUARDED_FIELDS.some((field) => statementFieldChanged(record, parsed, field))\n}\n\nfunction hasConcernAnswers(criteria: Record<string, { answer: string; note?: string | null }>): boolean {\n return Object.values(criteria).some((entry) => entry.answer === 'concern')\n}\n\nexport async function loadStatementSubmissionsForGate(\n em: EntityManager,\n record: EudrDueDiligenceStatement,\n): Promise<GateSubmissionView[]> {\n const submissions = await findWithDecryption(\n em,\n EudrEvidenceSubmission,\n {\n statementId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: record.tenantId, organizationId: record.organizationId },\n )\n return submissions.map((submission) => ({\n status: submission.status,\n completenessScore: submission.completenessScore,\n originCountry: submission.originCountry ?? null,\n }))\n}\n\nexport async function loadLatestAssessmentForGate(\n em: EntityManager,\n record: EudrDueDiligenceStatement,\n): Promise<GateAssessmentView> {\n const assessments = await findWithDecryption(\n em,\n EudrRiskAssessment,\n {\n statementId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n deletedAt: null,\n },\n {\n orderBy: { assessedAt: 'desc', createdAt: 'desc' },\n limit: 1,\n },\n { tenantId: record.tenantId, organizationId: record.organizationId },\n )\n const assessment = assessments[0]\n if (!assessment) return null\n const completedMitigationCount = await em.count(EudrMitigationAction, {\n riskAssessmentId: assessment.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n status: 'completed',\n deletedAt: null,\n })\n return {\n conclusion: assessment.conclusion,\n countryRisks: assessment.countryRisks.map((risk) => ({ country: risk.country, tier: risk.tier })),\n reviewDueAt: assessment.reviewDueAt ?? null,\n hasConcernAnswers: hasConcernAnswers(assessment.criteria),\n hasCompletedMitigation: completedMitigationCount > 0,\n }\n}\n\nasync function assertNoDownstreamReferences(\n em: EntityManager,\n record: EudrDueDiligenceStatement,\n): Promise<void> {\n const referenceNumber = record.referenceNumber?.trim().toUpperCase() ?? ''\n if (!referenceNumber) return\n const db = em.getKysely<{\n eudr_due_diligence_statements: {\n id: string\n tenant_id: string\n organization_id: string\n deleted_at: Date | null\n referenced_statements: unknown\n }\n }>()\n const containment = JSON.stringify([{ referenceNumber }])\n const downstreamRow = await db\n .selectFrom('eudr_due_diligence_statements')\n .select(sql<number>`count(*)`.as('total'))\n .where('tenant_id', '=', record.tenantId)\n .where('organization_id', '=', record.organizationId)\n .where('deleted_at', 'is', null)\n .where('id', '!=', record.id)\n .where(sql<boolean>`referenced_statements @> ${containment}::jsonb`)\n .executeTakeFirst()\n if (Number(downstreamRow?.total ?? 0) > 0) {\n throw new CrudHttpError(400, { error: 'eudr.errors.referencedDownstream' })\n }\n}\n\nasync function validateStatementUpdate(\n em: EntityManager,\n record: EudrDueDiligenceStatement,\n parsed: StatementUpdateInput,\n custom: Record<string, unknown>,\n): Promise<StatementServerFields> {\n if (!isStatementStatus(record.status)) {\n throw new CrudHttpError(400, { error: 'eudr.errors.invalidTransition' })\n }\n\n const requestedStatus = parsed.status\n const statusChanged = requestedStatus !== undefined && requestedStatus !== record.status\n if (statusChanged && (!isStatementStatus(requestedStatus) || !canTransition(record.status, requestedStatus))) {\n throw new CrudHttpError(400, { error: 'eudr.errors.invalidTransition' })\n }\n\n const hasBaseChanges = hasStatementFieldChanges(record, parsed)\n if (record.status === 'archived' && (hasBaseChanges || Object.keys(custom).length > 0)) {\n throw new CrudHttpError(400, { error: 'eudr.errors.archivedReadOnly' })\n }\n\n const patched = buildPatchedStatementView(record, parsed)\n const serverFields: StatementServerFields = {}\n const isSubmittedToAvailable = record.status === 'submitted' && requestedStatus === 'available'\n\n if (statusChanged) {\n if (record.status === 'draft' && requestedStatus === 'submitted') {\n const submissions = await loadStatementSubmissionsForGate(em, record)\n const latestAssessment = await loadLatestAssessmentForGate(em, record)\n const gate = evaluateSubmissionGate({\n actorRole: patched.actorRole,\n referencedStatementsCount: patched.referencedStatements.length,\n submissions,\n latestAssessment,\n })\n if (!gate.allowed) {\n throw new CrudHttpError(400, {\n error: 'eudr.errors.gateFailed',\n details: {\n reasons: gate.reasons.map((reason) => `eudr.gate.${reason}`),\n },\n })\n }\n serverFields.submittedAt = new Date()\n }\n\n if (isSubmittedToAvailable) {\n if (!isNonEmpty(patched.referenceNumber) || !isNonEmpty(patched.verificationNumber)) {\n throw new CrudHttpError(400, {\n error: 'eudr.errors.referenceNumbersRequired',\n details: {\n reasons: ['eudr.gate.referenceNumbersRequired'],\n },\n })\n }\n const issuedAt = parsed.referenceIssuedAt ?? new Date()\n if (issuedAt.getTime() > Date.now()) {\n throw new CrudHttpError(400, { error: 'eudr.errors.referenceIssuedAtInvalid' })\n }\n serverFields.referenceIssuedAt = issuedAt\n }\n\n if (record.status === 'available' && requestedStatus === 'withdrawn') {\n if (!isAmendWindowOpen(record.referenceIssuedAt ?? null)) {\n throw new CrudHttpError(400, { error: 'eudr.errors.amendWindowElapsed' })\n }\n await assertNoDownstreamReferences(em, record)\n }\n }\n\n if (\n parsed.referenceIssuedAt !== undefined\n && !isSubmittedToAvailable\n && !dateValuesEqual(parsed.referenceIssuedAt, record.referenceIssuedAt ?? null)\n ) {\n throw new CrudHttpError(400, { error: 'eudr.errors.referenceIssuedAtImmutable' })\n }\n\n // Guarded fields freeze once the amend window elapses, regardless of any\n // status transition requested in the same call (available\u2192archived must not\n // smuggle in a quantity/commodity change).\n if (\n record.status === 'available'\n && !isAmendWindowOpen(record.referenceIssuedAt ?? null)\n && hasChangedAmendGuardedField(record, parsed)\n ) {\n throw new CrudHttpError(400, { error: 'eudr.errors.amendWindowElapsed' })\n }\n\n return serverFields\n}\n\nconst createStatementCommand: CommandHandler<ScopedStatementCreateInput, StatementCommandResult> = {\n id: 'eudr.statements.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(statementCreateSchema, rawInput)\n const scope = parseScopedCommandInput(rawInput)\n ensureTenantScope(ctx, scope.tenantId)\n ensureOrganizationScope(ctx, scope.organizationId)\n if (parsed.status !== undefined && parsed.status !== 'draft') {\n throw new CrudHttpError(400, { error: 'eudr.errors.invalidTransition' })\n }\n if (parsed.referenceIssuedAt !== undefined) {\n throw new CrudHttpError(400, { error: 'eudr.errors.referenceIssuedAtImmutable' })\n }\n\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n let record!: EudrDueDiligenceStatement\n\n await runCrudCommandWrite({\n ctx,\n em: entityManager,\n entityId: STATEMENT_ENTITY_ID,\n action: 'created',\n scope,\n customFields: custom,\n events: statementCrudEvents,\n indexer: statementCrudIndexer,\n sideEffect: () => ({\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n }),\n phases: [\n () => {\n record = entityManager.create(EudrDueDiligenceStatement, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n title: parsed.title,\n commodity: parsed.commodity,\n referenceNumber: parsed.referenceNumber ?? null,\n verificationNumber: parsed.verificationNumber ?? null,\n status: parsed.status ?? 'draft',\n activityType: parsed.activityType ?? null,\n actorRole: parsed.actorRole ?? null,\n referencedStatements: parsed.referencedStatements ? parsed.referencedStatements.map((entry) => ({ ...entry })) : [],\n quantityKg: toNumericString(parsed.quantityKg),\n supplementaryUnit: parsed.supplementaryUnit ?? null,\n supplementaryQuantity: toNumericString(parsed.supplementaryQuantity),\n orderId: parsed.orderId ?? null,\n referenceIssuedAt: null,\n orderSnapshot: parsed.orderSnapshot ?? null,\n notes: parsed.notes ?? null,\n })\n entityManager.persist(record)\n },\n ],\n })\n\n return { entityId: record.id }\n },\n captureAfter: async (_rawInput, result, ctx) => {\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n return loadStatementSnapshot(entityManager, result.entityId)\n },\n buildLog: async ({ snapshots }) => {\n const after = snapshots.after as StatementSnapshot | undefined\n if (!after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('eudr.audit.statements.create', 'Create EUDR due diligence statement'),\n resourceKind: 'eudr.due_diligence_statement',\n resourceId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n snapshotAfter: after,\n payload: {\n undo: { after } satisfies StatementUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<StatementUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await entityManager.findOne(EudrDueDiligenceStatement, { id: after.id })\n if (!record) return\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n record.deletedAt = new Date()\n await entityManager.flush()\n\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const resetValues = buildCustomFieldResetMap(undefined, after.custom ?? undefined)\n await setStatementCustomFields(dataEngine, after.id, after.organizationId, after.tenantId, resetValues)\n await emitCrudUndoSideEffects({\n dataEngine,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n indexer: statementCrudIndexer,\n events: statementCrudEvents,\n })\n },\n redo: makeCreateRedo<EudrDueDiligenceStatement, StatementSnapshot, ScopedStatementCreateInput, StatementCommandResult>({\n entityClass: EudrDueDiligenceStatement,\n seedFromSnapshot: statementSeedFromSnapshot,\n buildResult: (entity) => ({ entityId: entity.id }),\n indexer: statementCrudIndexer,\n events: statementCrudEvents,\n afterRestore: async ({ ctx, entity, snapshot }) => {\n if (!snapshot.custom || !Object.keys(snapshot.custom).length) return\n await setStatementCustomFields(\n ctx.container.resolve('dataEngine') as DataEngine,\n entity.id,\n entity.organizationId,\n entity.tenantId,\n snapshot.custom,\n )\n },\n }),\n}\n\nconst updateStatementCommand: CommandHandler<ScopedStatementUpdateInput, StatementCommandResult> = {\n id: 'eudr.statements.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseWithCustomFields(statementUpdateSchema, rawInput)\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadStatementSnapshot(entityManager, parsed.id)\n if (snapshot) {\n ensureTenantScope(ctx, snapshot.tenantId)\n ensureOrganizationScope(ctx, snapshot.organizationId)\n }\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(statementUpdateSchema, rawInput)\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await entityManager.findOne(EudrDueDiligenceStatement, { id: parsed.id, deletedAt: null })\n if (!record) throw new CrudHttpError(404, { error: 'EUDR due diligence statement not found' })\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n const previousStatus = record.status\n\n await runCrudCommandWrite({\n ctx,\n em: entityManager,\n entityId: STATEMENT_ENTITY_ID,\n action: 'updated',\n scope: { tenantId: record.tenantId, organizationId: record.organizationId },\n customFields: custom,\n events: statementCrudEvents,\n indexer: statementCrudIndexer,\n sideEffect: () => ({\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n }),\n phases: [\n async () => {\n const serverFields = await validateStatementUpdate(entityManager, record, parsed, custom)\n applyStatementUpdate(record, parsed)\n if (serverFields.submittedAt !== undefined) record.submittedAt = serverFields.submittedAt\n if (serverFields.referenceIssuedAt !== undefined) record.referenceIssuedAt = serverFields.referenceIssuedAt\n },\n ],\n })\n\n const lifecycleEventId = record.status === previousStatus\n ? null\n : previousStatus === 'draft' && record.status === 'submitted'\n ? 'eudr.due_diligence_statement.submitted'\n : previousStatus === 'submitted' && record.status === 'available'\n ? 'eudr.due_diligence_statement.reference_issued'\n : previousStatus === 'available' && record.status === 'withdrawn'\n ? 'eudr.due_diligence_statement.withdrawn'\n : null\n if (lifecycleEventId) {\n await emitEudrLifecycleEvent(ctx.container, lifecycleEventId, {\n id: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n title: record.title,\n referenceNumber: record.referenceNumber ?? null,\n })\n }\n\n return { entityId: record.id, updatedAt: record.updatedAt }\n },\n captureAfter: async (_rawInput, result, ctx) => {\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n return loadStatementSnapshot(entityManager, result.entityId)\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as StatementSnapshot | undefined\n const after = snapshots.after as StatementSnapshot | undefined\n if (!before) return null\n if (after && snapshotsEqual(before, after)) return { skipLog: true }\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('eudr.audit.statements.update', 'Update EUDR due diligence statement'),\n resourceKind: 'eudr.due_diligence_statement',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: after ?? null,\n payload: {\n undo: { before, after: after ?? null } satisfies StatementUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<StatementUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n let record = await entityManager.findOne(EudrDueDiligenceStatement, { id: before.id })\n if (!record) {\n record = entityManager.create(EudrDueDiligenceStatement, statementSeedFromSnapshot(before))\n entityManager.persist(record)\n } else {\n ensureTenantScope(ctx, before.tenantId)\n ensureOrganizationScope(ctx, before.organizationId)\n restoreStatement(record, before)\n }\n await entityManager.flush()\n\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const resetValues = buildCustomFieldResetMap(before.custom ?? undefined, payload?.after?.custom ?? undefined)\n await setStatementCustomFields(dataEngine, before.id, before.organizationId, before.tenantId, resetValues)\n await emitCrudUndoSideEffects({\n dataEngine,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n indexer: statementCrudIndexer,\n events: statementCrudEvents,\n })\n },\n}\n\nconst deleteStatementCommand: CommandHandler<{ body?: Record<string, unknown>; query?: Record<string, unknown> }, StatementCommandResult> = {\n id: 'eudr.statements.delete',\n async prepare(input, ctx) {\n const entityId = requireId(input, 'EUDR due diligence statement id required')\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadStatementSnapshot(entityManager, entityId)\n if (snapshot) {\n ensureTenantScope(ctx, snapshot.tenantId)\n ensureOrganizationScope(ctx, snapshot.organizationId)\n }\n return snapshot ? { before: snapshot } : {}\n },\n async execute(input, ctx) {\n const entityId = requireId(input, 'EUDR due diligence statement id required')\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await entityManager.findOne(EudrDueDiligenceStatement, { id: entityId, deletedAt: null })\n if (!record) throw new CrudHttpError(404, { error: 'EUDR due diligence statement not found' })\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n if (record.status === 'archived') {\n throw new CrudHttpError(400, { error: 'eudr.errors.archivedReadOnly' })\n }\n if (record.status === 'available') {\n if (!isAmendWindowOpen(record.referenceIssuedAt ?? null)) {\n throw new CrudHttpError(400, { error: 'eudr.errors.amendWindowElapsed' })\n }\n await assertNoDownstreamReferences(entityManager, record)\n }\n\n const snapshot = await loadStatementSnapshot(entityManager, entityId)\n record.deletedAt = new Date()\n await entityManager.flush()\n\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n if (snapshot?.custom) {\n const resetValues = buildCustomFieldResetMap(snapshot.custom, undefined)\n await setStatementCustomFields(dataEngine, snapshot.id, snapshot.organizationId, snapshot.tenantId, resetValues)\n }\n await emitCrudSideEffects({\n dataEngine,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n indexer: statementCrudIndexer,\n events: statementCrudEvents,\n })\n return { entityId: record.id, updatedAt: record.updatedAt }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as StatementSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('eudr.audit.statements.delete', 'Delete EUDR due diligence statement'),\n resourceKind: 'eudr.due_diligence_statement',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: { before } satisfies StatementUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<StatementUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n let record = await entityManager.findOne(EudrDueDiligenceStatement, { id: before.id })\n if (!record) {\n record = entityManager.create(EudrDueDiligenceStatement, statementSeedFromSnapshot(before))\n entityManager.persist(record)\n } else {\n ensureTenantScope(ctx, before.tenantId)\n ensureOrganizationScope(ctx, before.organizationId)\n restoreStatement(record, before)\n }\n await entityManager.flush()\n\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n if (before.custom) {\n await setStatementCustomFields(dataEngine, before.id, before.organizationId, before.tenantId, before.custom)\n }\n await emitCrudUndoSideEffects({\n dataEngine,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n indexer: statementCrudIndexer,\n events: statementCrudEvents,\n })\n },\n}\n\nregisterCommand(createStatementCommand)\nregisterCommand(updateStatementCommand)\nregisterCommand(deleteStatementCommand)\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport type { RequiredEntityData } from '@mikro-orm/core'\nimport {\n parseWithCustomFields,\n emitCrudSideEffects,\n emitCrudUndoSideEffects,\n requireId,\n setCustomFieldsIfAny,\n snapshotsEqual,\n} from '@open-mercato/shared/lib/commands/helpers'\nimport { extractUndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { makeCreateRedo } from '@open-mercato/shared/lib/commands/redo'\nimport { runCrudCommandWrite } from '@open-mercato/shared/lib/commands/runCrudCommandWrite'\nimport { ensureOrganizationScope, ensureTenantScope } from '@open-mercato/shared/lib/commands/scope'\nimport {\n loadCustomFieldSnapshot,\n buildCustomFieldResetMap,\n} from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { CrudEventsConfig, CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { emitEudrLifecycleEvent } from './lifecycle-events'\nimport { E } from '#generated/entities.ids.generated'\nimport { sql } from 'kysely'\nimport { z } from 'zod'\nimport {\n EudrDueDiligenceStatement,\n EudrEvidenceSubmission,\n EudrMitigationAction,\n EudrRiskAssessment,\n} from '../data/entities'\nimport {\n EUDR_STATEMENT_STATUSES,\n statementCreateSchema,\n statementUpdateSchema,\n type EudrStatementStatus,\n type StatementCreateInput,\n type StatementUpdateInput,\n} from '../data/validators'\nimport {\n EUDR_AMEND_GUARDED_FIELDS,\n canTransition,\n evaluateSubmissionGate,\n isAmendWindowOpen,\n type GateAssessmentView,\n type GateSubmissionView,\n} from '../lib/statement-lifecycle'\n\nconst STATEMENT_ENTITY_ID = 'eudr:eudr_due_diligence_statement'\n\ntype ScopedCommandInput = {\n tenantId: string\n organizationId: string\n}\n\ntype StatementSnapshot = {\n id: string\n organizationId: string\n tenantId: string\n title: string\n commodity: string\n referenceNumber: string | null\n verificationNumber: string | null\n status: string\n activityType: string | null\n actorRole: string | null\n referencedStatements: Array<{ referenceNumber: string; verificationNumber?: string | null }>\n quantityKg: string | null\n supplementaryUnit: string | null\n supplementaryQuantity: string | null\n orderId: string | null\n submittedAt: string | null\n referenceIssuedAt: string | null\n orderSnapshot: { orderNumber?: string | null } | null\n notes: string | null\n createdAt: string\n updatedAt: string\n deletedAt: string | null\n custom?: Record<string, unknown> | null\n}\n\ntype StatementUndoPayload = {\n before?: StatementSnapshot | null\n after?: StatementSnapshot | null\n}\n\ntype ScopedStatementCreateInput = StatementCreateInput & ScopedCommandInput\ntype ScopedStatementUpdateInput = StatementUpdateInput & Partial<ScopedCommandInput>\n\ntype StatementCommandResult = {\n entityId: string\n updatedAt?: Date\n}\n\nconst scopedCommandInputSchema = z.object({\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid(),\n})\n\nconst statementCrudIndexer: CrudIndexerConfig<EudrDueDiligenceStatement> = {\n entityType: E.eudr.eudr_due_diligence_statement,\n}\n\nconst statementCrudEvents: CrudEventsConfig<EudrDueDiligenceStatement> = {\n module: 'eudr',\n entity: 'due_diligence_statement',\n persistent: true,\n buildPayload: (emitContext) => ({\n id: emitContext.identifiers.id,\n entityId: emitContext.entity?.id ?? emitContext.identifiers.id,\n organizationId: emitContext.identifiers.organizationId,\n tenantId: emitContext.identifiers.tenantId,\n }),\n}\n\nfunction parseScopedCommandInput(input: unknown): ScopedCommandInput {\n return scopedCommandInputSchema.parse(input)\n}\n\nfunction toNumericString(value: number | null | undefined): string | null {\n return value == null ? null : String(value)\n}\n\nfunction toDate(value: string | null): Date | null {\n return value ? new Date(value) : null\n}\n\nfunction statementSeedFromSnapshot(snapshot: StatementSnapshot): RequiredEntityData<EudrDueDiligenceStatement> {\n return {\n id: snapshot.id,\n organizationId: snapshot.organizationId,\n tenantId: snapshot.tenantId,\n title: snapshot.title,\n commodity: snapshot.commodity,\n referenceNumber: snapshot.referenceNumber,\n verificationNumber: snapshot.verificationNumber,\n status: snapshot.status,\n activityType: snapshot.activityType,\n actorRole: snapshot.actorRole,\n referencedStatements: snapshot.referencedStatements.map((entry) => ({ ...entry })),\n quantityKg: snapshot.quantityKg,\n supplementaryUnit: snapshot.supplementaryUnit,\n supplementaryQuantity: snapshot.supplementaryQuantity,\n orderId: snapshot.orderId,\n submittedAt: toDate(snapshot.submittedAt),\n referenceIssuedAt: toDate(snapshot.referenceIssuedAt),\n orderSnapshot: snapshot.orderSnapshot,\n notes: snapshot.notes,\n createdAt: new Date(snapshot.createdAt),\n updatedAt: new Date(snapshot.updatedAt),\n deletedAt: toDate(snapshot.deletedAt),\n }\n}\n\nasync function loadStatementSnapshot(em: EntityManager, entityId: string): Promise<StatementSnapshot | null> {\n const record = await em.findOne(EudrDueDiligenceStatement, { id: entityId })\n if (!record) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: STATEMENT_ENTITY_ID,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n return {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n title: record.title,\n commodity: record.commodity,\n referenceNumber: record.referenceNumber ?? null,\n verificationNumber: record.verificationNumber ?? null,\n status: record.status,\n activityType: record.activityType ?? null,\n actorRole: record.actorRole ?? null,\n referencedStatements: Array.isArray(record.referencedStatements)\n ? record.referencedStatements.map((entry) => ({ ...entry }))\n : [],\n quantityKg: record.quantityKg ?? null,\n supplementaryUnit: record.supplementaryUnit ?? null,\n supplementaryQuantity: record.supplementaryQuantity ?? null,\n orderId: record.orderId ?? null,\n submittedAt: record.submittedAt ? record.submittedAt.toISOString() : null,\n referenceIssuedAt: record.referenceIssuedAt ? record.referenceIssuedAt.toISOString() : null,\n orderSnapshot: record.orderSnapshot ?? null,\n notes: record.notes ?? null,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString(),\n deletedAt: record.deletedAt ? record.deletedAt.toISOString() : null,\n custom: Object.keys(custom).length ? custom : null,\n }\n}\n\nfunction applyStatementUpdate(record: EudrDueDiligenceStatement, parsed: StatementUpdateInput): void {\n if (parsed.title !== undefined) record.title = parsed.title\n if (parsed.commodity !== undefined) record.commodity = parsed.commodity\n if (parsed.referenceNumber !== undefined) record.referenceNumber = parsed.referenceNumber ?? null\n if (parsed.verificationNumber !== undefined) record.verificationNumber = parsed.verificationNumber ?? null\n if (parsed.status !== undefined) record.status = parsed.status\n if (parsed.activityType !== undefined) record.activityType = parsed.activityType ?? null\n if (parsed.actorRole !== undefined) record.actorRole = parsed.actorRole ?? null\n if (parsed.referencedStatements !== undefined) {\n record.referencedStatements = parsed.referencedStatements.map((entry) => ({ ...entry }))\n }\n if (parsed.quantityKg !== undefined) record.quantityKg = toNumericString(parsed.quantityKg)\n if (parsed.supplementaryUnit !== undefined) record.supplementaryUnit = parsed.supplementaryUnit ?? null\n if (parsed.supplementaryQuantity !== undefined) record.supplementaryQuantity = toNumericString(parsed.supplementaryQuantity)\n if (parsed.orderId !== undefined) record.orderId = parsed.orderId ?? null\n if (parsed.referenceIssuedAt !== undefined) record.referenceIssuedAt = parsed.referenceIssuedAt\n if (parsed.orderSnapshot !== undefined) record.orderSnapshot = parsed.orderSnapshot ?? null\n if (parsed.notes !== undefined) record.notes = parsed.notes ?? null\n}\n\nfunction restoreStatement(record: EudrDueDiligenceStatement, snapshot: StatementSnapshot): void {\n record.organizationId = snapshot.organizationId\n record.tenantId = snapshot.tenantId\n record.title = snapshot.title\n record.commodity = snapshot.commodity\n record.referenceNumber = snapshot.referenceNumber\n record.verificationNumber = snapshot.verificationNumber\n record.status = snapshot.status\n record.activityType = snapshot.activityType\n record.actorRole = snapshot.actorRole\n record.referencedStatements = snapshot.referencedStatements.map((entry) => ({ ...entry }))\n record.quantityKg = snapshot.quantityKg\n record.supplementaryUnit = snapshot.supplementaryUnit\n record.supplementaryQuantity = snapshot.supplementaryQuantity\n record.orderId = snapshot.orderId\n record.submittedAt = toDate(snapshot.submittedAt)\n record.referenceIssuedAt = toDate(snapshot.referenceIssuedAt)\n record.orderSnapshot = snapshot.orderSnapshot\n record.notes = snapshot.notes\n record.createdAt = new Date(snapshot.createdAt)\n record.updatedAt = new Date(snapshot.updatedAt)\n record.deletedAt = toDate(snapshot.deletedAt)\n}\n\nasync function setStatementCustomFields(\n dataEngine: DataEngine,\n entityId: string,\n organizationId: string,\n tenantId: string,\n values: Record<string, unknown>,\n): Promise<void> {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: STATEMENT_ENTITY_ID,\n recordId: entityId,\n organizationId,\n tenantId,\n values,\n notify: false,\n })\n}\n\ntype PatchedStatementView = {\n referenceNumber: string | null\n verificationNumber: string | null\n actorRole: string | null\n referencedStatements: Array<{ referenceNumber: string; verificationNumber?: string | null }>\n}\n\ntype StatementServerFields = {\n submittedAt?: Date\n referenceIssuedAt?: Date | null\n}\n\nconst STATEMENT_STATUS_SET = new Set<string>(EUDR_STATEMENT_STATUSES)\n\nconst STATEMENT_UPDATE_FIELDS = [\n 'title',\n 'commodity',\n 'referenceNumber',\n 'verificationNumber',\n 'status',\n 'activityType',\n 'actorRole',\n 'referencedStatements',\n 'quantityKg',\n 'supplementaryUnit',\n 'supplementaryQuantity',\n 'orderId',\n 'referenceIssuedAt',\n 'orderSnapshot',\n 'notes',\n] as const\n\ntype StatementUpdateField = (typeof STATEMENT_UPDATE_FIELDS)[number]\n\nfunction isStatementStatus(value: string): value is EudrStatementStatus {\n return STATEMENT_STATUS_SET.has(value)\n}\n\nfunction isNonEmpty(value: string | null | undefined): boolean {\n return typeof value === 'string' && value.trim().length > 0\n}\n\nfunction dateValuesEqual(left: Date | null | undefined, right: Date | null | undefined): boolean {\n const leftTime = left ? left.getTime() : null\n const rightTime = right ? right.getTime() : null\n return leftTime === rightTime\n}\n\nfunction jsonValuesEqual(left: unknown, right: unknown): boolean {\n return JSON.stringify(left ?? null) === JSON.stringify(right ?? null)\n}\n\n// PG numeric columns read back scale-padded ('100.000'); compare numerically so\n// an unchanged echo from a whole-document save is not treated as an amendment.\nfunction numericValuesEqual(left: string | null | undefined, right: string | null | undefined): boolean {\n const leftNumber = left === null || left === undefined || left === '' ? null : Number(left)\n const rightNumber = right === null || right === undefined || right === '' ? null : Number(right)\n if (leftNumber === null || rightNumber === null) return leftNumber === rightNumber\n return Number.isFinite(leftNumber) && Number.isFinite(rightNumber) && leftNumber === rightNumber\n}\n\nfunction referencedStatementsEqual(\n left: Array<{ referenceNumber: string; verificationNumber?: string | null }> | null | undefined,\n right: Array<{ referenceNumber: string; verificationNumber?: string | null }> | null | undefined,\n): boolean {\n return JSON.stringify(left ?? []) === JSON.stringify(right ?? [])\n}\n\nfunction statementFieldChanged(\n record: EudrDueDiligenceStatement,\n parsed: StatementUpdateInput,\n field: StatementUpdateField,\n): boolean {\n switch (field) {\n case 'title':\n return parsed.title !== undefined && parsed.title !== record.title\n case 'commodity':\n return parsed.commodity !== undefined && parsed.commodity !== record.commodity\n case 'referenceNumber':\n return parsed.referenceNumber !== undefined && (parsed.referenceNumber ?? null) !== (record.referenceNumber ?? null)\n case 'verificationNumber':\n return parsed.verificationNumber !== undefined && (parsed.verificationNumber ?? null) !== (record.verificationNumber ?? null)\n case 'status':\n return parsed.status !== undefined && parsed.status !== record.status\n case 'activityType':\n return parsed.activityType !== undefined && (parsed.activityType ?? null) !== (record.activityType ?? null)\n case 'actorRole':\n return parsed.actorRole !== undefined && (parsed.actorRole ?? null) !== (record.actorRole ?? null)\n case 'referencedStatements':\n return parsed.referencedStatements !== undefined && !referencedStatementsEqual(parsed.referencedStatements, record.referencedStatements)\n case 'quantityKg':\n return parsed.quantityKg !== undefined && !numericValuesEqual(toNumericString(parsed.quantityKg), record.quantityKg ?? null)\n case 'supplementaryUnit':\n return parsed.supplementaryUnit !== undefined && (parsed.supplementaryUnit ?? null) !== (record.supplementaryUnit ?? null)\n case 'supplementaryQuantity':\n return parsed.supplementaryQuantity !== undefined && !numericValuesEqual(toNumericString(parsed.supplementaryQuantity), record.supplementaryQuantity ?? null)\n case 'orderId':\n return parsed.orderId !== undefined && (parsed.orderId ?? null) !== (record.orderId ?? null)\n case 'referenceIssuedAt':\n return parsed.referenceIssuedAt !== undefined && !dateValuesEqual(parsed.referenceIssuedAt, record.referenceIssuedAt ?? null)\n case 'orderSnapshot':\n return parsed.orderSnapshot !== undefined && !jsonValuesEqual(parsed.orderSnapshot ?? null, record.orderSnapshot ?? null)\n case 'notes':\n return parsed.notes !== undefined && (parsed.notes ?? null) !== (record.notes ?? null)\n }\n}\n\nfunction hasStatementFieldChanges(record: EudrDueDiligenceStatement, parsed: StatementUpdateInput): boolean {\n return STATEMENT_UPDATE_FIELDS.some((field) => statementFieldChanged(record, parsed, field))\n}\n\nfunction buildPatchedStatementView(record: EudrDueDiligenceStatement, parsed: StatementUpdateInput): PatchedStatementView {\n return {\n referenceNumber: parsed.referenceNumber !== undefined ? parsed.referenceNumber ?? null : record.referenceNumber ?? null,\n verificationNumber: parsed.verificationNumber !== undefined ? parsed.verificationNumber ?? null : record.verificationNumber ?? null,\n actorRole: parsed.actorRole !== undefined ? parsed.actorRole ?? null : record.actorRole ?? null,\n referencedStatements: parsed.referencedStatements !== undefined\n ? parsed.referencedStatements.map((entry) => ({ ...entry }))\n : Array.isArray(record.referencedStatements)\n ? record.referencedStatements.map((entry) => ({ ...entry }))\n : [],\n }\n}\n\nfunction hasChangedAmendGuardedField(record: EudrDueDiligenceStatement, parsed: StatementUpdateInput): boolean {\n return EUDR_AMEND_GUARDED_FIELDS.some((field) => statementFieldChanged(record, parsed, field))\n}\n\nfunction hasConcernAnswers(criteria: Record<string, { answer: string; note?: string | null }>): boolean {\n return Object.values(criteria).some((entry) => entry.answer === 'concern')\n}\n\nexport async function loadStatementSubmissionsForGate(\n em: EntityManager,\n record: EudrDueDiligenceStatement,\n): Promise<GateSubmissionView[]> {\n const submissions = await findWithDecryption(\n em,\n EudrEvidenceSubmission,\n {\n statementId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: record.tenantId, organizationId: record.organizationId },\n )\n return submissions.map((submission) => ({\n status: submission.status,\n completenessScore: submission.completenessScore,\n originCountry: submission.originCountry ?? null,\n }))\n}\n\nexport async function loadLatestAssessmentForGate(\n em: EntityManager,\n record: EudrDueDiligenceStatement,\n): Promise<GateAssessmentView> {\n const assessments = await findWithDecryption(\n em,\n EudrRiskAssessment,\n {\n statementId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n deletedAt: null,\n },\n {\n orderBy: { assessedAt: 'desc', createdAt: 'desc' },\n limit: 1,\n },\n { tenantId: record.tenantId, organizationId: record.organizationId },\n )\n const assessment = assessments[0]\n if (!assessment) return null\n const completedMitigationCount = await em.count(EudrMitigationAction, {\n riskAssessmentId: assessment.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n status: 'completed',\n deletedAt: null,\n })\n return {\n conclusion: assessment.conclusion,\n countryRisks: assessment.countryRisks.map((risk) => ({ country: risk.country, tier: risk.tier })),\n reviewDueAt: assessment.reviewDueAt ?? null,\n hasConcernAnswers: hasConcernAnswers(assessment.criteria),\n hasCompletedMitigation: completedMitigationCount > 0,\n }\n}\n\nasync function assertNoDownstreamReferences(\n em: EntityManager,\n record: EudrDueDiligenceStatement,\n): Promise<void> {\n const referenceNumber = record.referenceNumber?.trim().toUpperCase() ?? ''\n if (!referenceNumber) return\n const db = em.getKysely<{\n eudr_due_diligence_statements: {\n id: string\n tenant_id: string\n organization_id: string\n deleted_at: Date | null\n referenced_statements: unknown\n }\n }>()\n const containment = JSON.stringify([{ referenceNumber }])\n const downstreamRow = await db\n .selectFrom('eudr_due_diligence_statements')\n .select(sql<number>`count(*)`.as('total'))\n .where('tenant_id', '=', record.tenantId)\n .where('organization_id', '=', record.organizationId)\n .where('deleted_at', 'is', null)\n .where('id', '!=', record.id)\n .where(sql<boolean>`referenced_statements @> ${containment}::jsonb`)\n .executeTakeFirst()\n if (Number(downstreamRow?.total ?? 0) > 0) {\n throw new CrudHttpError(400, { error: 'eudr.errors.referencedDownstream' })\n }\n}\n\nasync function validateStatementUpdate(\n em: EntityManager,\n record: EudrDueDiligenceStatement,\n parsed: StatementUpdateInput,\n custom: Record<string, unknown>,\n): Promise<StatementServerFields> {\n if (!isStatementStatus(record.status)) {\n throw new CrudHttpError(400, { error: 'eudr.errors.invalidTransition' })\n }\n\n const requestedStatus = parsed.status\n const statusChanged = requestedStatus !== undefined && requestedStatus !== record.status\n if (statusChanged && (!isStatementStatus(requestedStatus) || !canTransition(record.status, requestedStatus))) {\n throw new CrudHttpError(400, { error: 'eudr.errors.invalidTransition' })\n }\n\n const hasBaseChanges = hasStatementFieldChanges(record, parsed)\n if (record.status === 'archived' && (hasBaseChanges || Object.keys(custom).length > 0)) {\n throw new CrudHttpError(400, { error: 'eudr.errors.archivedReadOnly' })\n }\n\n const patched = buildPatchedStatementView(record, parsed)\n const serverFields: StatementServerFields = {}\n const isSubmittedToAvailable = record.status === 'submitted' && requestedStatus === 'available'\n\n if (statusChanged) {\n if (record.status === 'draft' && requestedStatus === 'submitted') {\n const submissions = await loadStatementSubmissionsForGate(em, record)\n const latestAssessment = await loadLatestAssessmentForGate(em, record)\n const gate = evaluateSubmissionGate({\n actorRole: patched.actorRole,\n referencedStatementsCount: patched.referencedStatements.length,\n submissions,\n latestAssessment,\n })\n if (!gate.allowed) {\n throw new CrudHttpError(400, {\n error: 'eudr.errors.gateFailed',\n details: {\n reasons: gate.reasons.map((reason) => `eudr.gate.${reason}`),\n },\n })\n }\n serverFields.submittedAt = new Date()\n }\n\n if (isSubmittedToAvailable) {\n if (!isNonEmpty(patched.referenceNumber) || !isNonEmpty(patched.verificationNumber)) {\n throw new CrudHttpError(400, {\n error: 'eudr.errors.referenceNumbersRequired',\n details: {\n reasons: ['eudr.gate.referenceNumbersRequired'],\n },\n })\n }\n const issuedAt = parsed.referenceIssuedAt ?? new Date()\n if (issuedAt.getTime() > Date.now()) {\n throw new CrudHttpError(400, { error: 'eudr.errors.referenceIssuedAtInvalid' })\n }\n serverFields.referenceIssuedAt = issuedAt\n }\n\n if (record.status === 'available' && requestedStatus === 'withdrawn') {\n if (!isAmendWindowOpen(record.referenceIssuedAt ?? null)) {\n throw new CrudHttpError(400, { error: 'eudr.errors.amendWindowElapsed' })\n }\n await assertNoDownstreamReferences(em, record)\n }\n }\n\n if (\n parsed.referenceIssuedAt !== undefined\n && !isSubmittedToAvailable\n && !dateValuesEqual(parsed.referenceIssuedAt, record.referenceIssuedAt ?? null)\n ) {\n throw new CrudHttpError(400, { error: 'eudr.errors.referenceIssuedAtImmutable' })\n }\n\n // Guarded fields freeze once the amend window elapses, regardless of any\n // status transition requested in the same call (available\u2192archived must not\n // smuggle in a quantity/commodity change).\n if (\n record.status === 'available'\n && !isAmendWindowOpen(record.referenceIssuedAt ?? null)\n && hasChangedAmendGuardedField(record, parsed)\n ) {\n throw new CrudHttpError(400, { error: 'eudr.errors.amendWindowElapsed' })\n }\n\n return serverFields\n}\n\nconst createStatementCommand: CommandHandler<ScopedStatementCreateInput, StatementCommandResult> = {\n id: 'eudr.statements.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(statementCreateSchema, rawInput)\n const scope = parseScopedCommandInput(rawInput)\n ensureTenantScope(ctx, scope.tenantId)\n ensureOrganizationScope(ctx, scope.organizationId)\n if (parsed.status !== undefined && parsed.status !== 'draft') {\n throw new CrudHttpError(400, { error: 'eudr.errors.invalidTransition' })\n }\n\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n let record!: EudrDueDiligenceStatement\n\n await runCrudCommandWrite({\n ctx,\n em: entityManager,\n entityId: STATEMENT_ENTITY_ID,\n action: 'created',\n scope,\n customFields: custom,\n events: statementCrudEvents,\n indexer: statementCrudIndexer,\n sideEffect: () => ({\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n }),\n phases: [\n () => {\n record = entityManager.create(EudrDueDiligenceStatement, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n title: parsed.title,\n commodity: parsed.commodity,\n referenceNumber: parsed.referenceNumber ?? null,\n verificationNumber: parsed.verificationNumber ?? null,\n status: parsed.status ?? 'draft',\n activityType: parsed.activityType ?? null,\n actorRole: parsed.actorRole ?? null,\n referencedStatements: parsed.referencedStatements ? parsed.referencedStatements.map((entry) => ({ ...entry })) : [],\n quantityKg: toNumericString(parsed.quantityKg),\n supplementaryUnit: parsed.supplementaryUnit ?? null,\n supplementaryQuantity: toNumericString(parsed.supplementaryQuantity),\n orderId: parsed.orderId ?? null,\n referenceIssuedAt: null,\n orderSnapshot: parsed.orderSnapshot ?? null,\n notes: parsed.notes ?? null,\n })\n entityManager.persist(record)\n },\n ],\n })\n\n return { entityId: record.id }\n },\n captureAfter: async (_rawInput, result, ctx) => {\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n return loadStatementSnapshot(entityManager, result.entityId)\n },\n buildLog: async ({ snapshots }) => {\n const after = snapshots.after as StatementSnapshot | undefined\n if (!after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('eudr.audit.statements.create', 'Create EUDR due diligence statement'),\n resourceKind: 'eudr.due_diligence_statement',\n resourceId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n snapshotAfter: after,\n payload: {\n undo: { after } satisfies StatementUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<StatementUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await entityManager.findOne(EudrDueDiligenceStatement, { id: after.id })\n if (!record) return\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n record.deletedAt = new Date()\n await entityManager.flush()\n\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const resetValues = buildCustomFieldResetMap(undefined, after.custom ?? undefined)\n await setStatementCustomFields(dataEngine, after.id, after.organizationId, after.tenantId, resetValues)\n await emitCrudUndoSideEffects({\n dataEngine,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n indexer: statementCrudIndexer,\n events: statementCrudEvents,\n })\n },\n redo: makeCreateRedo<EudrDueDiligenceStatement, StatementSnapshot, ScopedStatementCreateInput, StatementCommandResult>({\n entityClass: EudrDueDiligenceStatement,\n seedFromSnapshot: statementSeedFromSnapshot,\n buildResult: (entity) => ({ entityId: entity.id }),\n indexer: statementCrudIndexer,\n events: statementCrudEvents,\n afterRestore: async ({ ctx, entity, snapshot }) => {\n if (!snapshot.custom || !Object.keys(snapshot.custom).length) return\n await setStatementCustomFields(\n ctx.container.resolve('dataEngine') as DataEngine,\n entity.id,\n entity.organizationId,\n entity.tenantId,\n snapshot.custom,\n )\n },\n }),\n}\n\nconst updateStatementCommand: CommandHandler<ScopedStatementUpdateInput, StatementCommandResult> = {\n id: 'eudr.statements.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseWithCustomFields(statementUpdateSchema, rawInput)\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadStatementSnapshot(entityManager, parsed.id)\n if (snapshot) {\n ensureTenantScope(ctx, snapshot.tenantId)\n ensureOrganizationScope(ctx, snapshot.organizationId)\n }\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(statementUpdateSchema, rawInput)\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await entityManager.findOne(EudrDueDiligenceStatement, { id: parsed.id, deletedAt: null })\n if (!record) throw new CrudHttpError(404, { error: 'EUDR due diligence statement not found' })\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n const previousStatus = record.status\n\n await runCrudCommandWrite({\n ctx,\n em: entityManager,\n entityId: STATEMENT_ENTITY_ID,\n action: 'updated',\n scope: { tenantId: record.tenantId, organizationId: record.organizationId },\n customFields: custom,\n events: statementCrudEvents,\n indexer: statementCrudIndexer,\n sideEffect: () => ({\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n }),\n phases: [\n async () => {\n const serverFields = await validateStatementUpdate(entityManager, record, parsed, custom)\n applyStatementUpdate(record, parsed)\n if (serverFields.submittedAt !== undefined) record.submittedAt = serverFields.submittedAt\n if (serverFields.referenceIssuedAt !== undefined) record.referenceIssuedAt = serverFields.referenceIssuedAt\n },\n ],\n })\n\n const lifecycleEventId = record.status === previousStatus\n ? null\n : previousStatus === 'draft' && record.status === 'submitted'\n ? 'eudr.due_diligence_statement.submitted'\n : previousStatus === 'submitted' && record.status === 'available'\n ? 'eudr.due_diligence_statement.reference_issued'\n : previousStatus === 'available' && record.status === 'withdrawn'\n ? 'eudr.due_diligence_statement.withdrawn'\n : null\n if (lifecycleEventId) {\n await emitEudrLifecycleEvent(ctx.container, lifecycleEventId, {\n id: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n title: record.title,\n referenceNumber: record.referenceNumber ?? null,\n })\n }\n\n return { entityId: record.id, updatedAt: record.updatedAt }\n },\n captureAfter: async (_rawInput, result, ctx) => {\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n return loadStatementSnapshot(entityManager, result.entityId)\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as StatementSnapshot | undefined\n const after = snapshots.after as StatementSnapshot | undefined\n if (!before) return null\n if (after && snapshotsEqual(before, after)) return { skipLog: true }\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('eudr.audit.statements.update', 'Update EUDR due diligence statement'),\n resourceKind: 'eudr.due_diligence_statement',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: after ?? null,\n payload: {\n undo: { before, after: after ?? null } satisfies StatementUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<StatementUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n let record = await entityManager.findOne(EudrDueDiligenceStatement, { id: before.id })\n if (!record) {\n record = entityManager.create(EudrDueDiligenceStatement, statementSeedFromSnapshot(before))\n entityManager.persist(record)\n } else {\n ensureTenantScope(ctx, before.tenantId)\n ensureOrganizationScope(ctx, before.organizationId)\n restoreStatement(record, before)\n }\n await entityManager.flush()\n\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const resetValues = buildCustomFieldResetMap(before.custom ?? undefined, payload?.after?.custom ?? undefined)\n await setStatementCustomFields(dataEngine, before.id, before.organizationId, before.tenantId, resetValues)\n await emitCrudUndoSideEffects({\n dataEngine,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n indexer: statementCrudIndexer,\n events: statementCrudEvents,\n })\n },\n}\n\nconst deleteStatementCommand: CommandHandler<{ body?: Record<string, unknown>; query?: Record<string, unknown> }, StatementCommandResult> = {\n id: 'eudr.statements.delete',\n async prepare(input, ctx) {\n const entityId = requireId(input, 'EUDR due diligence statement id required')\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadStatementSnapshot(entityManager, entityId)\n if (snapshot) {\n ensureTenantScope(ctx, snapshot.tenantId)\n ensureOrganizationScope(ctx, snapshot.organizationId)\n }\n return snapshot ? { before: snapshot } : {}\n },\n async execute(input, ctx) {\n const entityId = requireId(input, 'EUDR due diligence statement id required')\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await entityManager.findOne(EudrDueDiligenceStatement, { id: entityId, deletedAt: null })\n if (!record) throw new CrudHttpError(404, { error: 'EUDR due diligence statement not found' })\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n if (record.status === 'archived') {\n throw new CrudHttpError(400, { error: 'eudr.errors.archivedReadOnly' })\n }\n if (record.status === 'available') {\n if (!isAmendWindowOpen(record.referenceIssuedAt ?? null)) {\n throw new CrudHttpError(400, { error: 'eudr.errors.amendWindowElapsed' })\n }\n await assertNoDownstreamReferences(entityManager, record)\n }\n\n const snapshot = await loadStatementSnapshot(entityManager, entityId)\n record.deletedAt = new Date()\n await entityManager.flush()\n\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n if (snapshot?.custom) {\n const resetValues = buildCustomFieldResetMap(snapshot.custom, undefined)\n await setStatementCustomFields(dataEngine, snapshot.id, snapshot.organizationId, snapshot.tenantId, resetValues)\n }\n await emitCrudSideEffects({\n dataEngine,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n indexer: statementCrudIndexer,\n events: statementCrudEvents,\n })\n return { entityId: record.id, updatedAt: record.updatedAt }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as StatementSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('eudr.audit.statements.delete', 'Delete EUDR due diligence statement'),\n resourceKind: 'eudr.due_diligence_statement',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: { before } satisfies StatementUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<StatementUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const entityManager = (ctx.container.resolve('em') as EntityManager).fork()\n let record = await entityManager.findOne(EudrDueDiligenceStatement, { id: before.id })\n if (!record) {\n record = entityManager.create(EudrDueDiligenceStatement, statementSeedFromSnapshot(before))\n entityManager.persist(record)\n } else {\n ensureTenantScope(ctx, before.tenantId)\n ensureOrganizationScope(ctx, before.organizationId)\n restoreStatement(record, before)\n }\n await entityManager.flush()\n\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n if (before.custom) {\n await setStatementCustomFields(dataEngine, before.id, before.organizationId, before.tenantId, before.custom)\n }\n await emitCrudUndoSideEffects({\n dataEngine,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n indexer: statementCrudIndexer,\n events: statementCrudEvents,\n })\n },\n}\n\nregisterCommand(createStatementCommand)\nregisterCommand(updateStatementCommand)\nregisterCommand(deleteStatementCommand)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -43,6 +43,7 @@ function rejectServerComputedFields(fields) {
|
|
|
43
43
|
const record = input;
|
|
44
44
|
for (const field of fields) {
|
|
45
45
|
if (!(field in record)) continue;
|
|
46
|
+
if (record[field] === null || record[field] === void 0) continue;
|
|
46
47
|
context.addIssue({
|
|
47
48
|
code: z.ZodIssueCode.custom,
|
|
48
49
|
path: [field],
|
|
@@ -234,7 +235,9 @@ const statementBaseSchema = z.object({
|
|
|
234
235
|
orderSnapshot: orderSnapshotSchema.optional().nullable(),
|
|
235
236
|
notes: z.string().max(5e3).optional().nullable()
|
|
236
237
|
});
|
|
237
|
-
const statementCreateSchema = rejectServerComputedFields(serverComputedStatementFields).pipe(
|
|
238
|
+
const statementCreateSchema = rejectServerComputedFields(serverComputedStatementFields).pipe(
|
|
239
|
+
statementBaseSchema.omit({ referenceIssuedAt: true })
|
|
240
|
+
);
|
|
238
241
|
const statementUpdateSchema = rejectServerComputedFields(serverComputedStatementFields).pipe(
|
|
239
242
|
z.object({
|
|
240
243
|
id: uuid()
|