@open-mercato/core 0.10.1-develop.7826.1.5e82b7c668 → 0.10.1-develop.7833.1.d6cbf0e3ab
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/.turbo/turbo-build.log +1 -1
- package/dist/helpers/integration/appRuntime.js +17 -0
- package/dist/helpers/integration/appRuntime.js.map +7 -0
- package/dist/modules/query_index/lib/engine.js +14 -3
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/warranty_claims/search.js +7 -6
- package/dist/modules/warranty_claims/search.js.map +2 -2
- package/package.json +7 -7
- package/src/helpers/integration/appRuntime.ts +26 -0
- package/src/modules/query_index/lib/engine.ts +13 -2
- package/src/modules/warranty_claims/i18n/de.json +1 -0
- package/src/modules/warranty_claims/i18n/en.json +1 -0
- package/src/modules/warranty_claims/i18n/es.json +1 -0
- package/src/modules/warranty_claims/i18n/ko.json +1 -0
- package/src/modules/warranty_claims/i18n/pl.json +1 -0
- package/src/modules/warranty_claims/search.ts +8 -5
|
@@ -23,17 +23,18 @@ function appendLine(lines, label, value) {
|
|
|
23
23
|
function resolveClaimId(record) {
|
|
24
24
|
return readString(record, "id", "id");
|
|
25
25
|
}
|
|
26
|
-
function resolvePresenter(record) {
|
|
26
|
+
async function resolvePresenter(record) {
|
|
27
|
+
const { t } = await resolveTranslations();
|
|
27
28
|
const claimNumber = readString(record, "claim_number", "claimNumber") ?? "Warranty claim";
|
|
28
29
|
const customerName = readString(record, "customer_name", "customerName");
|
|
29
30
|
const claimType = readString(record, "claim_type", "claimType");
|
|
30
31
|
const status = readString(record, "status", "status");
|
|
31
|
-
const
|
|
32
|
+
const statusLabel = status ? t(`warranty_claims.status.${status}`, status) : null;
|
|
33
|
+
const subtitle = [customerName, claimType, statusLabel].filter((value) => Boolean(value)).join(" \u2014 ");
|
|
32
34
|
return {
|
|
33
35
|
title: claimNumber,
|
|
34
36
|
subtitle: subtitle || void 0,
|
|
35
|
-
icon: "shield-check"
|
|
36
|
-
badge: status ?? void 0
|
|
37
|
+
icon: "shield-check"
|
|
37
38
|
};
|
|
38
39
|
}
|
|
39
40
|
async function loadClaimLineRows(ctx, claimId) {
|
|
@@ -113,7 +114,7 @@ const searchConfig = {
|
|
|
113
114
|
const lineRows = claimId ? await loadClaimLineRows(ctx, claimId) : [];
|
|
114
115
|
appendLineRows(lines, lineRows);
|
|
115
116
|
if (!lines.length) return null;
|
|
116
|
-
const presenter = resolvePresenter(record);
|
|
117
|
+
const presenter = await resolvePresenter(record);
|
|
117
118
|
const url = buildClaimUrl(record);
|
|
118
119
|
const links = url ? [{ href: url, label: presenter.title, kind: "primary" }] : [];
|
|
119
120
|
return {
|
|
@@ -127,7 +128,7 @@ const searchConfig = {
|
|
|
127
128
|
}
|
|
128
129
|
};
|
|
129
130
|
},
|
|
130
|
-
formatResult: (ctx) => {
|
|
131
|
+
formatResult: async (ctx) => {
|
|
131
132
|
assertTenantContext(ctx);
|
|
132
133
|
return resolvePresenter(ctx.record);
|
|
133
134
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/warranty_claims/search.ts"],
|
|
4
|
-
"sourcesContent": ["import { SortDir, type QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type {\n SearchBuildContext,\n SearchIndexSource,\n SearchModuleConfig,\n SearchResultLink,\n SearchResultPresenter,\n} from '@open-mercato/shared/modules/search'\nimport { E } from '#generated/entities.ids.generated'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nconst logger = createLogger('warranty_claims')\n\ntype SearchContext = SearchBuildContext & {\n tenantId: string\n queryEngine?: QueryEngine\n}\n\nfunction assertTenantContext(ctx: SearchBuildContext): asserts ctx is SearchContext {\n if (typeof ctx.tenantId !== 'string' || ctx.tenantId.length === 0) {\n throw new Error('[internal] [search.warranty_claims] Missing tenantId in search build context')\n }\n}\n\nfunction readString(record: Record<string, unknown>, snakeKey: string, camelKey?: string): string | null {\n const value = record[snakeKey] ?? (camelKey ? record[camelKey] : undefined)\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n return trimmed.length ? trimmed : null\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown): void {\n if (typeof value !== 'string') return\n const trimmed = value.trim()\n if (!trimmed.length) return\n lines.push(`${label}: ${trimmed}`)\n}\n\nfunction resolveClaimId(record: Record<string, unknown>): string | null {\n return readString(record, 'id', 'id')\n}\n\
|
|
5
|
-
"mappings": "AAAA,SAAS,eAAiC;AAQ1C,SAAS,SAAS;AAClB,SAAS,oBAAoB;AAC7B,SAAS,2BAA2B;AAEpC,MAAM,SAAS,aAAa,iBAAiB;AAO7C,SAAS,oBAAoB,KAAuD;AAClF,MAAI,OAAO,IAAI,aAAa,YAAY,IAAI,SAAS,WAAW,GAAG;AACjE,UAAM,IAAI,MAAM,8EAA8E;AAAA,EAChG;AACF;AAEA,SAAS,WAAW,QAAiC,UAAkB,UAAkC;AACvG,QAAM,QAAQ,OAAO,QAAQ,MAAM,WAAW,OAAO,QAAQ,IAAI;AACjE,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,KAAK;AAC3B,SAAO,QAAQ,SAAS,UAAU;AACpC;AAEA,SAAS,WAAW,OAAiB,OAAe,OAAsB;AACxE,MAAI,OAAO,UAAU,SAAU;AAC/B,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,QAAQ,OAAQ;AACrB,QAAM,KAAK,GAAG,KAAK,KAAK,OAAO,EAAE;AACnC;AAEA,SAAS,eAAe,QAAgD;AACtE,SAAO,WAAW,QAAQ,MAAM,IAAI;AACtC;AAEA,
|
|
4
|
+
"sourcesContent": ["import { SortDir, type QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type {\n SearchBuildContext,\n SearchIndexSource,\n SearchModuleConfig,\n SearchResultLink,\n SearchResultPresenter,\n} from '@open-mercato/shared/modules/search'\nimport { E } from '#generated/entities.ids.generated'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nconst logger = createLogger('warranty_claims')\n\ntype SearchContext = SearchBuildContext & {\n tenantId: string\n queryEngine?: QueryEngine\n}\n\nfunction assertTenantContext(ctx: SearchBuildContext): asserts ctx is SearchContext {\n if (typeof ctx.tenantId !== 'string' || ctx.tenantId.length === 0) {\n throw new Error('[internal] [search.warranty_claims] Missing tenantId in search build context')\n }\n}\n\nfunction readString(record: Record<string, unknown>, snakeKey: string, camelKey?: string): string | null {\n const value = record[snakeKey] ?? (camelKey ? record[camelKey] : undefined)\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n return trimmed.length ? trimmed : null\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown): void {\n if (typeof value !== 'string') return\n const trimmed = value.trim()\n if (!trimmed.length) return\n lines.push(`${label}: ${trimmed}`)\n}\n\nfunction resolveClaimId(record: Record<string, unknown>): string | null {\n return readString(record, 'id', 'id')\n}\n\nasync function resolvePresenter(record: Record<string, unknown>): Promise<SearchResultPresenter> {\n const { t } = await resolveTranslations()\n const claimNumber = readString(record, 'claim_number', 'claimNumber') ?? 'Warranty claim'\n const customerName = readString(record, 'customer_name', 'customerName')\n const claimType = readString(record, 'claim_type', 'claimType')\n const status = readString(record, 'status', 'status')\n const statusLabel = status ? t(`warranty_claims.status.${status}`, status) : null\n const subtitle = [customerName, claimType, statusLabel]\n .filter((value): value is string => Boolean(value))\n .join(' \u2014 ')\n return {\n title: claimNumber,\n subtitle: subtitle || undefined,\n icon: 'shield-check',\n }\n}\n\nasync function loadClaimLineRows(ctx: SearchContext, claimId: string): Promise<Array<Record<string, unknown>>> {\n if (!ctx.queryEngine) return []\n try {\n const rows: Array<Record<string, unknown>> = []\n const pageSize = 100\n for (let page = 1; ; page += 1) {\n const result = await ctx.queryEngine.query<Record<string, unknown>>(E.warranty_claims.warranty_claim_line, {\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId ?? undefined,\n filters: { claim_id: { $eq: claimId } },\n fields: [\n 'id',\n 'line_no',\n 'sku',\n 'product_name',\n 'serial_number',\n 'lot_number',\n 'fault_code',\n 'warranty_status',\n 'disposition',\n 'line_status',\n ],\n page: { page, pageSize },\n sort: [\n { field: 'line_no', dir: SortDir.Asc },\n { field: 'id', dir: SortDir.Asc },\n ],\n })\n rows.push(...result.items)\n if (result.items.length < pageSize || rows.length >= result.total) break\n }\n return rows\n } catch (err) {\n logger.warn('[search.warranty_claims] Failed to load claim lines', {\n claimId,\n error: err instanceof Error ? err.message : err,\n })\n return []\n }\n}\n\nfunction appendLineRows(lines: string[], lineRows: Array<Record<string, unknown>>): void {\n for (const row of lineRows) {\n appendLine(lines, 'Line SKU', readString(row, 'sku', 'sku') ?? '')\n appendLine(lines, 'Line product', readString(row, 'product_name', 'productName') ?? '')\n appendLine(lines, 'Serial number', readString(row, 'serial_number', 'serialNumber') ?? '')\n appendLine(lines, 'Lot number', readString(row, 'lot_number', 'lotNumber') ?? '')\n appendLine(lines, 'Fault code', readString(row, 'fault_code', 'faultCode') ?? '')\n appendLine(lines, 'Warranty status', readString(row, 'warranty_status', 'warrantyStatus') ?? '')\n appendLine(lines, 'Disposition', readString(row, 'disposition', 'disposition') ?? '')\n appendLine(lines, 'Line status', readString(row, 'line_status', 'lineStatus') ?? '')\n }\n}\n\nfunction buildClaimUrl(record: Record<string, unknown>): string | null {\n const claimId = resolveClaimId(record)\n return claimId ? `/backend/warranty_claims/${claimId}` : null\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: E.warranty_claims.warranty_claim,\n enabled: true,\n priority: 20,\n\n buildSource: async (ctx: SearchBuildContext): Promise<SearchIndexSource | null> => {\n assertTenantContext(ctx)\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Claim number', readString(record, 'claim_number', 'claimNumber') ?? '')\n appendLine(lines, 'Customer', readString(record, 'customer_name', 'customerName') ?? '')\n appendLine(lines, 'Order number', readString(record, 'order_number', 'orderNumber') ?? '')\n appendLine(lines, 'Claim type', readString(record, 'claim_type', 'claimType') ?? '')\n appendLine(lines, 'Status', readString(record, 'status', 'status') ?? '')\n appendLine(lines, 'Vendor', readString(record, 'vendor_name', 'vendorName') ?? '')\n appendLine(lines, 'Vendor reference', readString(record, 'vendor_ref', 'vendorRef') ?? '')\n\n const claimId = resolveClaimId(record)\n const lineRows = claimId ? await loadClaimLineRows(ctx, claimId) : []\n appendLineRows(lines, lineRows)\n if (!lines.length) return null\n\n const presenter = await resolvePresenter(record)\n const url = buildClaimUrl(record)\n const links: SearchResultLink[] = url ? [{ href: url, label: presenter.title, kind: 'primary' }] : []\n return {\n text: lines,\n presenter,\n links,\n checksumSource: {\n record,\n customFields: ctx.customFields,\n lineRows,\n },\n }\n },\n\n formatResult: async (ctx: SearchBuildContext): Promise<SearchResultPresenter | null> => {\n assertTenantContext(ctx)\n return resolvePresenter(ctx.record)\n },\n\n resolveUrl: (ctx: SearchBuildContext): string | null => buildClaimUrl(ctx.record),\n\n resolveLinks: async (ctx: SearchBuildContext): Promise<SearchResultLink[] | null> => {\n const url = buildClaimUrl(ctx.record)\n if (!url) return null\n const { t } = await resolveTranslations()\n return [{ href: url, label: t('warranty_claims.search.openClaim', 'Open claim'), kind: 'secondary' }]\n },\n\n fieldPolicy: {\n searchable: [\n 'claim_number',\n 'claim_type',\n 'status',\n 'priority',\n 'customer_name',\n 'vendor_name',\n 'vendor_ref',\n ],\n hashOnly: ['customer_id', 'order_id', 'sales_return_id', 'replacement_order_id', 'source_claim_id'],\n excluded: [\n 'tenant_id',\n 'organization_id',\n 'assignee_user_id',\n 'deleted_at',\n 'notes',\n 'resolution_summary',\n 'contact_email',\n 'fault_description',\n 'inspection_notes',\n 'rejection_reason_code',\n ],\n },\n aclFeatures: ['warranty_claims.claim.view'],\n },\n ],\n}\n\nexport default searchConfig\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.10.1-develop.
|
|
3
|
+
"version": "0.10.1-develop.7833.1.d6cbf0e3ab",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -266,16 +266,16 @@
|
|
|
266
266
|
"zod": "^4.6.6"
|
|
267
267
|
},
|
|
268
268
|
"peerDependencies": {
|
|
269
|
-
"@open-mercato/ai-assistant": "0.10.1-develop.
|
|
270
|
-
"@open-mercato/shared": "0.10.1-develop.
|
|
271
|
-
"@open-mercato/ui": "0.10.1-develop.
|
|
269
|
+
"@open-mercato/ai-assistant": "0.10.1-develop.7833.1.d6cbf0e3ab",
|
|
270
|
+
"@open-mercato/shared": "0.10.1-develop.7833.1.d6cbf0e3ab",
|
|
271
|
+
"@open-mercato/ui": "0.10.1-develop.7833.1.d6cbf0e3ab",
|
|
272
272
|
"react": "^19.0.0",
|
|
273
273
|
"react-dom": "^19.0.0"
|
|
274
274
|
},
|
|
275
275
|
"devDependencies": {
|
|
276
|
-
"@open-mercato/ai-assistant": "0.10.1-develop.
|
|
277
|
-
"@open-mercato/shared": "0.10.1-develop.
|
|
278
|
-
"@open-mercato/ui": "0.10.1-develop.
|
|
276
|
+
"@open-mercato/ai-assistant": "0.10.1-develop.7833.1.d6cbf0e3ab",
|
|
277
|
+
"@open-mercato/shared": "0.10.1-develop.7833.1.d6cbf0e3ab",
|
|
278
|
+
"@open-mercato/ui": "0.10.1-develop.7833.1.d6cbf0e3ab",
|
|
279
279
|
"@testing-library/dom": "^10.4.1",
|
|
280
280
|
"@testing-library/jest-dom": "^7.0.1",
|
|
281
281
|
"@testing-library/react": "^16.3.3",
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createRequire } from 'node:module'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { pathToFileURL } from 'node:url'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Imports a package module from the same copy the app under test runs on.
|
|
7
|
+
*
|
|
8
|
+
* A spec that bootstraps the app in-process (`bootstrapFromAppRoot`) and then calls into its
|
|
9
|
+
* runtime — the command bus, `withAtomicFlush`, transaction lifetime — must load every one of those
|
|
10
|
+
* modules from a single copy. Against a standalone app (`OM_TEST_APP_ROOT`) the app's generated
|
|
11
|
+
* registries import `node_modules/@open-mercato/*` inside the app, while the spec's own static
|
|
12
|
+
* imports resolve to the monorepo's packages, so module-local state such as the command registry
|
|
13
|
+
* splits in two: handlers register in one copy and the bus resolves them in the other.
|
|
14
|
+
*
|
|
15
|
+
* Without `OM_TEST_APP_ROOT` this is a plain dynamic import, so the monorepo lane is unchanged.
|
|
16
|
+
*/
|
|
17
|
+
export async function importFromAppRuntime<TModule>(specifier: string): Promise<TModule> {
|
|
18
|
+
const resolvedPath = resolveAppRuntimeModulePath(specifier)
|
|
19
|
+
return (await import(resolvedPath ? pathToFileURL(resolvedPath).href : specifier)) as TModule
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function resolveAppRuntimeModulePath(specifier: string, appRoot = process.env.OM_TEST_APP_ROOT): string | null {
|
|
23
|
+
const standaloneRoot = appRoot?.trim()
|
|
24
|
+
if (!standaloneRoot) return null
|
|
25
|
+
return createRequire(path.join(path.resolve(standaloneRoot), 'package.json')).resolve(specifier)
|
|
26
|
+
}
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
import { tokenizeText } from '@open-mercato/shared/lib/search/tokenize'
|
|
59
59
|
import { buildContainmentPatterns } from '@open-mercato/shared/lib/search/containment'
|
|
60
60
|
import { runBeforeQueryPipeline, runAfterQueryPipeline, type QueryExtensionContext } from '@open-mercato/shared/lib/query/query-extension-runner'
|
|
61
|
-
import { warnOnCiphertextLikeFallback } from '@open-mercato/shared/lib/query/ciphertext-search-warning'
|
|
61
|
+
import { warnOnCiphertextLikeFallback, type CiphertextSearchWarning } from '@open-mercato/shared/lib/query/ciphertext-search-warning'
|
|
62
62
|
import {
|
|
63
63
|
matchEncryptedSortFields,
|
|
64
64
|
resolveEncryptedFieldNames,
|
|
@@ -452,12 +452,17 @@ export class HybridQueryEngine implements QueryEngine {
|
|
|
452
452
|
const applyAfterExtensions = async <R>(queryResult: QueryResult<R>): Promise<QueryResult<R>> => {
|
|
453
453
|
if (!ext || !hybridExtCtx) return queryResult
|
|
454
454
|
const diCtx = ext.resolve ? { resolve: ext.resolve } : noopDi
|
|
455
|
-
|
|
455
|
+
const ciphertextSearchWarnings = queryResult.meta?.ciphertextSearchWarnings
|
|
456
|
+
const result = await runAfterQueryPipeline(
|
|
456
457
|
queryResult as QueryResult<Record<string, unknown>>,
|
|
457
458
|
opts,
|
|
458
459
|
hybridExtCtx,
|
|
459
460
|
diCtx,
|
|
460
461
|
) as QueryResult<R>
|
|
462
|
+
if (ciphertextSearchWarnings?.length) {
|
|
463
|
+
result.meta = { ...result.meta, ciphertextSearchWarnings }
|
|
464
|
+
}
|
|
465
|
+
return result
|
|
461
466
|
}
|
|
462
467
|
|
|
463
468
|
try {
|
|
@@ -727,6 +732,7 @@ export class HybridQueryEngine implements QueryEngine {
|
|
|
727
732
|
searchRuntime.encryptedFields = null
|
|
728
733
|
}
|
|
729
734
|
}
|
|
735
|
+
const ciphertextSearchWarnings: CiphertextSearchWarning[] = []
|
|
730
736
|
if (searchFilters.length) {
|
|
731
737
|
this.logSearchDebug('search:init', {
|
|
732
738
|
entity,
|
|
@@ -768,6 +774,7 @@ export class HybridQueryEngine implements QueryEngine {
|
|
|
768
774
|
? 'no-indexable-tokens'
|
|
769
775
|
: searchConfig.enabled ? 'no-search-tokens' : 'search-disabled',
|
|
770
776
|
service: this.getEncryptionService(),
|
|
777
|
+
onDiagnostic: (warning) => ciphertextSearchWarnings.push(warning),
|
|
771
778
|
})
|
|
772
779
|
}
|
|
773
780
|
}
|
|
@@ -791,6 +798,7 @@ export class HybridQueryEngine implements QueryEngine {
|
|
|
791
798
|
? 'no-indexable-tokens'
|
|
792
799
|
: searchConfig.enabled ? 'no-search-tokens' : 'search-disabled',
|
|
793
800
|
service: this.getEncryptionService(),
|
|
801
|
+
onDiagnostic: (warning) => ciphertextSearchWarnings.push(warning),
|
|
794
802
|
})
|
|
795
803
|
}
|
|
796
804
|
const hasNonBaseSearchSource = searchSources.some(
|
|
@@ -1597,6 +1605,9 @@ export class HybridQueryEngine implements QueryEngine {
|
|
|
1597
1605
|
}
|
|
1598
1606
|
|
|
1599
1607
|
result = await applyAfterExtensions(result)
|
|
1608
|
+
if (ciphertextSearchWarnings.length) {
|
|
1609
|
+
result.meta = { ...result.meta, ciphertextSearchWarnings }
|
|
1610
|
+
}
|
|
1600
1611
|
finishProfile({
|
|
1601
1612
|
result: 'ok', total, page, pageSize,
|
|
1602
1613
|
itemCount: Array.isArray(items) ? items.length : undefined,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"notifications.categories.warranty_claims": "Garantieclaims",
|
|
3
|
+
"search.entityType.warranty_claims.warranty_claim": "Garantieclaim",
|
|
3
4
|
"warranty_claims.ai.apply": "Anwenden",
|
|
4
5
|
"warranty_claims.ai.assess.attachment": "Anhang",
|
|
5
6
|
"warranty_claims.ai.assess.attachmentsError": "Positionsanhänge konnten nicht geladen werden.",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"notifications.categories.warranty_claims": "Warranty claims",
|
|
3
|
+
"search.entityType.warranty_claims.warranty_claim": "Warranty Claim",
|
|
3
4
|
"warranty_claims.ai.apply": "Apply",
|
|
4
5
|
"warranty_claims.ai.assess.attachment": "Attachment",
|
|
5
6
|
"warranty_claims.ai.assess.attachmentsError": "Failed to load line attachments.",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"notifications.categories.warranty_claims": "Reclamos de garantía",
|
|
3
|
+
"search.entityType.warranty_claims.warranty_claim": "Reclamo de garantía",
|
|
3
4
|
"warranty_claims.ai.apply": "Aplicar",
|
|
4
5
|
"warranty_claims.ai.assess.attachment": "Adjunto",
|
|
5
6
|
"warranty_claims.ai.assess.attachmentsError": "No se pudieron cargar los adjuntos de la línea.",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"notifications.categories.warranty_claims": "보증 클레임",
|
|
3
|
+
"search.entityType.warranty_claims.warranty_claim": "보증 클레임",
|
|
3
4
|
"warranty_claims.ai.apply": "적용",
|
|
4
5
|
"warranty_claims.ai.assess.attachment": "첨부파일",
|
|
5
6
|
"warranty_claims.ai.assess.attachmentsError": "라인 첨부파일을 불러오지 못했습니다.",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"notifications.categories.warranty_claims": "Reklamacje gwarancyjne",
|
|
3
|
+
"search.entityType.warranty_claims.warranty_claim": "Reklamacja gwarancyjna",
|
|
3
4
|
"warranty_claims.ai.apply": "Zastosuj",
|
|
4
5
|
"warranty_claims.ai.assess.attachment": "Załącznik",
|
|
5
6
|
"warranty_claims.ai.assess.attachmentsError": "Nie udało się załadować załączników pozycji.",
|
|
@@ -41,17 +41,20 @@ function resolveClaimId(record: Record<string, unknown>): string | null {
|
|
|
41
41
|
return readString(record, 'id', 'id')
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
function resolvePresenter(record: Record<string, unknown>): SearchResultPresenter {
|
|
44
|
+
async function resolvePresenter(record: Record<string, unknown>): Promise<SearchResultPresenter> {
|
|
45
|
+
const { t } = await resolveTranslations()
|
|
45
46
|
const claimNumber = readString(record, 'claim_number', 'claimNumber') ?? 'Warranty claim'
|
|
46
47
|
const customerName = readString(record, 'customer_name', 'customerName')
|
|
47
48
|
const claimType = readString(record, 'claim_type', 'claimType')
|
|
48
49
|
const status = readString(record, 'status', 'status')
|
|
49
|
-
const
|
|
50
|
+
const statusLabel = status ? t(`warranty_claims.status.${status}`, status) : null
|
|
51
|
+
const subtitle = [customerName, claimType, statusLabel]
|
|
52
|
+
.filter((value): value is string => Boolean(value))
|
|
53
|
+
.join(' — ')
|
|
50
54
|
return {
|
|
51
55
|
title: claimNumber,
|
|
52
56
|
subtitle: subtitle || undefined,
|
|
53
57
|
icon: 'shield-check',
|
|
54
|
-
badge: status ?? undefined,
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
60
|
|
|
@@ -138,7 +141,7 @@ export const searchConfig: SearchModuleConfig = {
|
|
|
138
141
|
appendLineRows(lines, lineRows)
|
|
139
142
|
if (!lines.length) return null
|
|
140
143
|
|
|
141
|
-
const presenter = resolvePresenter(record)
|
|
144
|
+
const presenter = await resolvePresenter(record)
|
|
142
145
|
const url = buildClaimUrl(record)
|
|
143
146
|
const links: SearchResultLink[] = url ? [{ href: url, label: presenter.title, kind: 'primary' }] : []
|
|
144
147
|
return {
|
|
@@ -153,7 +156,7 @@ export const searchConfig: SearchModuleConfig = {
|
|
|
153
156
|
}
|
|
154
157
|
},
|
|
155
158
|
|
|
156
|
-
formatResult: (ctx: SearchBuildContext): SearchResultPresenter | null => {
|
|
159
|
+
formatResult: async (ctx: SearchBuildContext): Promise<SearchResultPresenter | null> => {
|
|
157
160
|
assertTenantContext(ctx)
|
|
158
161
|
return resolvePresenter(ctx.record)
|
|
159
162
|
},
|