@open-mercato/core 0.6.4-develop.4299.1.af24e08431 → 0.6.4-develop.4310.1.0be8773280

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/modules/attachments/lib/pdfProcessing.js +1 -1
  2. package/dist/modules/attachments/lib/pdfProcessing.js.map +2 -2
  3. package/dist/modules/attachments/lib/textExtraction.js +1 -1
  4. package/dist/modules/attachments/lib/textExtraction.js.map +1 -1
  5. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js +16 -3
  6. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +2 -2
  7. package/dist/modules/customers/api/companies/[id]/route.js +4 -0
  8. package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
  9. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +21 -5
  10. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  11. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +21 -5
  12. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  13. package/dist/modules/customers/commands/companies.js +48 -32
  14. package/dist/modules/customers/commands/companies.js.map +2 -2
  15. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +18 -3
  16. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
  17. package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.js +21 -3
  18. package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.js.map +2 -2
  19. package/dist/modules/integrations/backend/integrations/[id]/page.js +18 -2
  20. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  21. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +18 -3
  22. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
  23. package/jest.config.cjs +3 -0
  24. package/package.json +18 -18
  25. package/src/modules/attachments/lib/pdfProcessing.ts +1 -2
  26. package/src/modules/attachments/lib/textExtraction.ts +1 -1
  27. package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +20 -3
  28. package/src/modules/customers/api/companies/[id]/route.ts +4 -0
  29. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +25 -5
  30. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +25 -5
  31. package/src/modules/customers/commands/companies.ts +51 -34
  32. package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +21 -3
  33. package/src/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.tsx +36 -3
  34. package/src/modules/integrations/backend/integrations/[id]/page.tsx +21 -2
  35. package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +21 -3
@@ -87,7 +87,7 @@ async function preparePdfPagesForOcr(filePath) {
87
87
  pages
88
88
  };
89
89
  } finally {
90
- await pdfDocument.destroy();
90
+ await loadingTask.destroy();
91
91
  }
92
92
  }
93
93
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/attachments/lib/pdfProcessing.ts"],
4
- "sourcesContent": ["import fs from 'fs/promises'\nimport path from 'path'\nimport { createRequire } from 'module'\n\nconst moduleRequire = createRequire(path.join(process.cwd(), 'package.json'))\nconst pdfJsPackageRoot = path.dirname(moduleRequire.resolve('pdfjs-dist/package.json'))\nconst cMapUrl = `${path.join(pdfJsPackageRoot, 'cmaps')}${path.sep}`\nconst standardFontDataUrl = `${path.join(pdfJsPackageRoot, 'standard_fonts')}${path.sep}`\n\nconst MIN_RENDER_SCALE = 2\nconst MAX_RENDER_SCALE = 4\nconst MAX_RENDER_DIMENSION = 2200\nconst MAX_RENDER_PIXELS = 8_000_000\n\ntype PdfPageProxyLike = {\n cleanup: () => void\n getTextContent: () => Promise<{ items?: Array<{ str?: string }> }>\n getViewport: (args: { scale: number }) => { width: number; height: number }\n render: (args: { canvasContext: unknown; viewport: { width: number; height: number } }) => { promise: Promise<void> }\n}\n\ntype PdfCanvasFactoryLike = {\n create: (width: number, height: number) => {\n canvas: { toBuffer: (mimeType: string) => Buffer | Uint8Array }\n context: unknown\n }\n destroy: (canvasAndContext: {\n canvas: { toBuffer: (mimeType: string) => Buffer | Uint8Array } | null\n context: unknown\n }) => void\n}\n\ntype PdfDocumentProxyLike = {\n numPages: number\n canvasFactory: PdfCanvasFactoryLike\n getPage: (pageNumber: number) => Promise<PdfPageProxyLike>\n destroy: () => Promise<void>\n}\n\nexport type PdfPageOcrInput = {\n pageNumber: number\n extractedText: string | null\n imageBuffer: Buffer | null\n}\n\nexport type PdfOcrPreparationResult = {\n pageCount: number\n pages: PdfPageOcrInput[]\n}\n\nfunction normalizePdfText(rawText: string): string | null {\n const normalized = rawText.replace(/\\s+/g, ' ').trim()\n return normalized.length > 0 ? normalized : null\n}\n\nfunction extractPdfTextContent(items: Array<{ str?: string }> | undefined): string | null {\n if (!Array.isArray(items) || items.length === 0) return null\n const collected = items\n .map((item) => (typeof item?.str === 'string' ? item.str : ''))\n .filter((value) => value.length > 0)\n .join(' ')\n return normalizePdfText(collected)\n}\n\nfunction resolvePdfRenderScale(page: PdfPageProxyLike): number {\n const baseViewport = page.getViewport({ scale: 1 })\n const baseLargestDimension = Math.max(baseViewport.width, baseViewport.height)\n let scale = Math.min(\n MAX_RENDER_SCALE,\n Math.max(MIN_RENDER_SCALE, MAX_RENDER_DIMENSION / Math.max(baseLargestDimension, 1)),\n )\n\n let viewport = page.getViewport({ scale })\n const pixelCount = viewport.width * viewport.height\n if (pixelCount > MAX_RENDER_PIXELS) {\n scale *= Math.sqrt(MAX_RENDER_PIXELS / pixelCount)\n viewport = page.getViewport({ scale })\n }\n\n return Math.max(1, scale)\n}\n\nasync function renderPdfPageToImageBuffer(\n page: PdfPageProxyLike,\n canvasFactory: PdfCanvasFactoryLike,\n): Promise<Buffer> {\n const viewport = page.getViewport({ scale: resolvePdfRenderScale(page) })\n const canvasAndContext = canvasFactory.create(viewport.width, viewport.height)\n\n try {\n const renderTask = page.render({\n canvasContext: canvasAndContext.context,\n viewport,\n })\n await renderTask.promise\n const imageBuffer = canvasAndContext.canvas.toBuffer('image/png')\n return Buffer.isBuffer(imageBuffer) ? imageBuffer : Buffer.from(imageBuffer)\n } finally {\n canvasFactory.destroy(canvasAndContext)\n }\n}\n\nexport async function preparePdfPagesForOcr(filePath: string): Promise<PdfOcrPreparationResult> {\n const { getDocument } = await import('pdfjs-dist/legacy/build/pdf.mjs')\n const data = new Uint8Array(await fs.readFile(filePath))\n const loadingTask = getDocument({\n data,\n cMapUrl,\n cMapPacked: true,\n standardFontDataUrl,\n })\n\n const pdfDocument = (await loadingTask.promise) as unknown as PdfDocumentProxyLike\n\n try {\n const pages: PdfPageOcrInput[] = []\n\n for (let pageNumber = 1; pageNumber <= pdfDocument.numPages; pageNumber += 1) {\n const page = await pdfDocument.getPage(pageNumber)\n\n try {\n const textContent = await page.getTextContent()\n const extractedText = extractPdfTextContent(textContent.items)\n\n if (extractedText) {\n pages.push({\n pageNumber,\n extractedText,\n imageBuffer: null,\n })\n continue\n }\n\n pages.push({\n pageNumber,\n extractedText: null,\n imageBuffer: await renderPdfPageToImageBuffer(page, pdfDocument.canvasFactory),\n })\n } finally {\n page.cleanup()\n }\n }\n\n return {\n pageCount: pdfDocument.numPages,\n pages,\n }\n } finally {\n await pdfDocument.destroy()\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import fs from 'fs/promises'\nimport path from 'path'\nimport { createRequire } from 'module'\n\nconst moduleRequire = createRequire(path.join(process.cwd(), 'package.json'))\nconst pdfJsPackageRoot = path.dirname(moduleRequire.resolve('pdfjs-dist/package.json'))\nconst cMapUrl = `${path.join(pdfJsPackageRoot, 'cmaps')}${path.sep}`\nconst standardFontDataUrl = `${path.join(pdfJsPackageRoot, 'standard_fonts')}${path.sep}`\n\nconst MIN_RENDER_SCALE = 2\nconst MAX_RENDER_SCALE = 4\nconst MAX_RENDER_DIMENSION = 2200\nconst MAX_RENDER_PIXELS = 8_000_000\n\ntype PdfPageProxyLike = {\n cleanup: () => void\n getTextContent: () => Promise<{ items?: Array<{ str?: string }> }>\n getViewport: (args: { scale: number }) => { width: number; height: number }\n render: (args: { canvasContext: unknown; viewport: { width: number; height: number } }) => { promise: Promise<void> }\n}\n\ntype PdfCanvasFactoryLike = {\n create: (width: number, height: number) => {\n canvas: { toBuffer: (mimeType: string) => Buffer | Uint8Array }\n context: unknown\n }\n destroy: (canvasAndContext: {\n canvas: { toBuffer: (mimeType: string) => Buffer | Uint8Array } | null\n context: unknown\n }) => void\n}\n\ntype PdfDocumentProxyLike = {\n numPages: number\n canvasFactory: PdfCanvasFactoryLike\n getPage: (pageNumber: number) => Promise<PdfPageProxyLike>\n}\n\nexport type PdfPageOcrInput = {\n pageNumber: number\n extractedText: string | null\n imageBuffer: Buffer | null\n}\n\nexport type PdfOcrPreparationResult = {\n pageCount: number\n pages: PdfPageOcrInput[]\n}\n\nfunction normalizePdfText(rawText: string): string | null {\n const normalized = rawText.replace(/\\s+/g, ' ').trim()\n return normalized.length > 0 ? normalized : null\n}\n\nfunction extractPdfTextContent(items: Array<{ str?: string }> | undefined): string | null {\n if (!Array.isArray(items) || items.length === 0) return null\n const collected = items\n .map((item) => (typeof item?.str === 'string' ? item.str : ''))\n .filter((value) => value.length > 0)\n .join(' ')\n return normalizePdfText(collected)\n}\n\nfunction resolvePdfRenderScale(page: PdfPageProxyLike): number {\n const baseViewport = page.getViewport({ scale: 1 })\n const baseLargestDimension = Math.max(baseViewport.width, baseViewport.height)\n let scale = Math.min(\n MAX_RENDER_SCALE,\n Math.max(MIN_RENDER_SCALE, MAX_RENDER_DIMENSION / Math.max(baseLargestDimension, 1)),\n )\n\n let viewport = page.getViewport({ scale })\n const pixelCount = viewport.width * viewport.height\n if (pixelCount > MAX_RENDER_PIXELS) {\n scale *= Math.sqrt(MAX_RENDER_PIXELS / pixelCount)\n viewport = page.getViewport({ scale })\n }\n\n return Math.max(1, scale)\n}\n\nasync function renderPdfPageToImageBuffer(\n page: PdfPageProxyLike,\n canvasFactory: PdfCanvasFactoryLike,\n): Promise<Buffer> {\n const viewport = page.getViewport({ scale: resolvePdfRenderScale(page) })\n const canvasAndContext = canvasFactory.create(viewport.width, viewport.height)\n\n try {\n const renderTask = page.render({\n canvasContext: canvasAndContext.context,\n viewport,\n })\n await renderTask.promise\n const imageBuffer = canvasAndContext.canvas.toBuffer('image/png')\n return Buffer.isBuffer(imageBuffer) ? imageBuffer : Buffer.from(imageBuffer)\n } finally {\n canvasFactory.destroy(canvasAndContext)\n }\n}\n\nexport async function preparePdfPagesForOcr(filePath: string): Promise<PdfOcrPreparationResult> {\n const { getDocument } = await import('pdfjs-dist/legacy/build/pdf.mjs')\n const data = new Uint8Array(await fs.readFile(filePath))\n const loadingTask = getDocument({\n data,\n cMapUrl,\n cMapPacked: true,\n standardFontDataUrl,\n })\n\n const pdfDocument = (await loadingTask.promise) as unknown as PdfDocumentProxyLike\n\n try {\n const pages: PdfPageOcrInput[] = []\n\n for (let pageNumber = 1; pageNumber <= pdfDocument.numPages; pageNumber += 1) {\n const page = await pdfDocument.getPage(pageNumber)\n\n try {\n const textContent = await page.getTextContent()\n const extractedText = extractPdfTextContent(textContent.items)\n\n if (extractedText) {\n pages.push({\n pageNumber,\n extractedText,\n imageBuffer: null,\n })\n continue\n }\n\n pages.push({\n pageNumber,\n extractedText: null,\n imageBuffer: await renderPdfPageToImageBuffer(page, pdfDocument.canvasFactory),\n })\n } finally {\n page.cleanup()\n }\n }\n\n return {\n pageCount: pdfDocument.numPages,\n pages,\n }\n } finally {\n await loadingTask.destroy()\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -59,7 +59,7 @@ async function extractPdfText(filePath) {
59
59
  }
60
60
  }
61
61
  } finally {
62
- await pdfDocument.destroy();
62
+ await loadingTask.destroy();
63
63
  }
64
64
  const result = textParts.join("\n").trim();
65
65
  return result.length > 0 ? result : null;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/attachments/lib/textExtraction.ts"],
4
- "sourcesContent": ["import fs from 'fs/promises'\nimport path from 'path'\nimport { createRequire } from 'module'\n\n// NOTE: child_process is intentionally NOT imported here.\n// This module MUST NOT shell out to any external binary for content extraction.\n// All extraction must use pure-JS libraries. See HUNT-PARSER-01.\n\nconst moduleRequire = createRequire(path.join(process.cwd(), 'package.json'))\nconst pdfJsPackageRoot = path.dirname(moduleRequire.resolve('pdfjs-dist/package.json'))\nconst PDF_CMAP_URL = `${path.join(pdfJsPackageRoot, 'cmaps')}${path.sep}`\nconst PDF_STANDARD_FONT_DATA_URL = `${path.join(pdfJsPackageRoot, 'standard_fonts')}${path.sep}`\n\ntype ExtractParams = {\n filePath: string\n mimeType?: string | null\n}\n\nfunction isImage(mimeType?: string | null, filePath?: string | null): boolean {\n const normalized = (mimeType || '').toLowerCase()\n if (normalized.startsWith('image/')) return true\n if (filePath) {\n const ext = path.extname(filePath).toLowerCase()\n return ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp', '.tiff'].includes(ext)\n }\n return false\n}\n\nfunction isPlainText(mimeType: string, ext: string): boolean {\n return mimeType.startsWith('text/')\n || ext === '.txt'\n || ext === '.md'\n || ext === '.csv'\n || ext === '.log'\n}\n\nfunction isPdf(mimeType: string, ext: string): boolean {\n return mimeType === 'application/pdf' || ext === '.pdf'\n}\n\nfunction isDocx(mimeType: string, ext: string): boolean {\n // mammoth supports only Open XML .docx, not legacy binary .doc files.\n return (\n mimeType === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'\n || ext === '.docx'\n )\n}\n\nasync function extractPlainText(filePath: string): Promise<string | null> {\n try {\n const text = await fs.readFile(filePath, 'utf8')\n const trimmed = text.trim()\n return trimmed.length > 0 ? trimmed : null\n } catch {\n return null\n }\n}\n\nasync function extractPdfText(filePath: string): Promise<string | null> {\n try {\n const { getDocument } = await import('pdfjs-dist/legacy/build/pdf.mjs')\n const data = new Uint8Array(await fs.readFile(filePath))\n const loadingTask = getDocument({\n data,\n cMapUrl: PDF_CMAP_URL,\n cMapPacked: true,\n standardFontDataUrl: PDF_STANDARD_FONT_DATA_URL,\n })\n const pdfDocument = await loadingTask.promise\n const textParts: string[] = []\n try {\n for (let pageNumber = 1; pageNumber <= pdfDocument.numPages; pageNumber += 1) {\n const page = await pdfDocument.getPage(pageNumber)\n try {\n const textContent = await page.getTextContent()\n const items = (textContent as any).items as Array<{ str?: string }> | undefined\n if (Array.isArray(items)) {\n const pageText = items\n .map((item) => (typeof item?.str === 'string' ? item.str : ''))\n .filter((s) => s.length > 0)\n .join(' ')\n if (pageText.trim()) textParts.push(pageText.trim())\n }\n } finally {\n page.cleanup()\n }\n }\n } finally {\n await pdfDocument.destroy()\n }\n const result = textParts.join('\\n').trim()\n return result.length > 0 ? result : null\n } catch {\n return null\n }\n}\n\nasync function extractDocxText(filePath: string): Promise<string | null> {\n try {\n const mammoth = await import('mammoth')\n const result = await mammoth.extractRawText({ path: filePath })\n const trimmed = result.value.trim()\n return trimmed.length > 0 ? trimmed : null\n } catch {\n return null\n }\n}\n\nexport async function extractAttachmentContent(params: ExtractParams): Promise<string | null> {\n const { filePath, mimeType } = params\n if (!filePath) return null\n if (isImage(mimeType, filePath)) return null\n\n const normalized = (mimeType || '').toLowerCase()\n const ext = path.extname(filePath).toLowerCase()\n\n if (isPlainText(normalized, ext)) {\n return extractPlainText(filePath)\n }\n\n if (isPdf(normalized, ext)) {\n return extractPdfText(filePath)\n }\n\n if (isDocx(normalized, ext)) {\n return extractDocxText(filePath)\n }\n\n // XLSX, PPTX, MSG and other Office formats: no safe pure-JS extractor available yet.\n // Return null rather than shelling out to an external binary.\n return null\n}\n"],
4
+ "sourcesContent": ["import fs from 'fs/promises'\nimport path from 'path'\nimport { createRequire } from 'module'\n\n// NOTE: child_process is intentionally NOT imported here.\n// This module MUST NOT shell out to any external binary for content extraction.\n// All extraction must use pure-JS libraries. See HUNT-PARSER-01.\n\nconst moduleRequire = createRequire(path.join(process.cwd(), 'package.json'))\nconst pdfJsPackageRoot = path.dirname(moduleRequire.resolve('pdfjs-dist/package.json'))\nconst PDF_CMAP_URL = `${path.join(pdfJsPackageRoot, 'cmaps')}${path.sep}`\nconst PDF_STANDARD_FONT_DATA_URL = `${path.join(pdfJsPackageRoot, 'standard_fonts')}${path.sep}`\n\ntype ExtractParams = {\n filePath: string\n mimeType?: string | null\n}\n\nfunction isImage(mimeType?: string | null, filePath?: string | null): boolean {\n const normalized = (mimeType || '').toLowerCase()\n if (normalized.startsWith('image/')) return true\n if (filePath) {\n const ext = path.extname(filePath).toLowerCase()\n return ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp', '.tiff'].includes(ext)\n }\n return false\n}\n\nfunction isPlainText(mimeType: string, ext: string): boolean {\n return mimeType.startsWith('text/')\n || ext === '.txt'\n || ext === '.md'\n || ext === '.csv'\n || ext === '.log'\n}\n\nfunction isPdf(mimeType: string, ext: string): boolean {\n return mimeType === 'application/pdf' || ext === '.pdf'\n}\n\nfunction isDocx(mimeType: string, ext: string): boolean {\n // mammoth supports only Open XML .docx, not legacy binary .doc files.\n return (\n mimeType === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'\n || ext === '.docx'\n )\n}\n\nasync function extractPlainText(filePath: string): Promise<string | null> {\n try {\n const text = await fs.readFile(filePath, 'utf8')\n const trimmed = text.trim()\n return trimmed.length > 0 ? trimmed : null\n } catch {\n return null\n }\n}\n\nasync function extractPdfText(filePath: string): Promise<string | null> {\n try {\n const { getDocument } = await import('pdfjs-dist/legacy/build/pdf.mjs')\n const data = new Uint8Array(await fs.readFile(filePath))\n const loadingTask = getDocument({\n data,\n cMapUrl: PDF_CMAP_URL,\n cMapPacked: true,\n standardFontDataUrl: PDF_STANDARD_FONT_DATA_URL,\n })\n const pdfDocument = await loadingTask.promise\n const textParts: string[] = []\n try {\n for (let pageNumber = 1; pageNumber <= pdfDocument.numPages; pageNumber += 1) {\n const page = await pdfDocument.getPage(pageNumber)\n try {\n const textContent = await page.getTextContent()\n const items = (textContent as any).items as Array<{ str?: string }> | undefined\n if (Array.isArray(items)) {\n const pageText = items\n .map((item) => (typeof item?.str === 'string' ? item.str : ''))\n .filter((s) => s.length > 0)\n .join(' ')\n if (pageText.trim()) textParts.push(pageText.trim())\n }\n } finally {\n page.cleanup()\n }\n }\n } finally {\n await loadingTask.destroy()\n }\n const result = textParts.join('\\n').trim()\n return result.length > 0 ? result : null\n } catch {\n return null\n }\n}\n\nasync function extractDocxText(filePath: string): Promise<string | null> {\n try {\n const mammoth = await import('mammoth')\n const result = await mammoth.extractRawText({ path: filePath })\n const trimmed = result.value.trim()\n return trimmed.length > 0 ? trimmed : null\n } catch {\n return null\n }\n}\n\nexport async function extractAttachmentContent(params: ExtractParams): Promise<string | null> {\n const { filePath, mimeType } = params\n if (!filePath) return null\n if (isImage(mimeType, filePath)) return null\n\n const normalized = (mimeType || '').toLowerCase()\n const ext = path.extname(filePath).toLowerCase()\n\n if (isPlainText(normalized, ext)) {\n return extractPlainText(filePath)\n }\n\n if (isPdf(normalized, ext)) {\n return extractPdfText(filePath)\n }\n\n if (isDocx(normalized, ext)) {\n return extractDocxText(filePath)\n }\n\n // XLSX, PPTX, MSG and other Office formats: no safe pure-JS extractor available yet.\n // Return null rather than shelling out to an external binary.\n return null\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -3,7 +3,7 @@ import { jsx } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { useRouter } from "next/navigation";
5
5
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
6
- import { LoadingMessage, ErrorMessage } from "@open-mercato/ui/backend/detail";
6
+ import { LoadingMessage, ErrorMessage, RecordNotFoundState } from "@open-mercato/ui/backend/detail";
7
7
  import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
8
8
  import { updateCrud } from "@open-mercato/ui/backend/utils/crud";
9
9
  import { flash } from "@open-mercato/ui/backend/FlashMessages";
@@ -29,6 +29,7 @@ function EditExchangeRatePage({ params }) {
29
29
  const [exchangeRate, setExchangeRate] = React.useState(null);
30
30
  const [loading, setLoading] = React.useState(true);
31
31
  const [error, setError] = React.useState(null);
32
+ const [isNotFound, setIsNotFound] = React.useState(false);
32
33
  const loadOptions = React.useCallback(
33
34
  (query) => loadCurrencyOptions(apiCall, query),
34
35
  []
@@ -39,8 +40,10 @@ function EditExchangeRatePage({ params }) {
39
40
  const response = await apiCall(`/api/currencies/exchange-rates?id=${params?.id}`);
40
41
  if (response.ok && response.result && response.result.items.length > 0) {
41
42
  setExchangeRate(response.result.items[0]);
43
+ } else if (response.ok) {
44
+ setIsNotFound(true);
42
45
  } else {
43
- setError(t("exchangeRates.form.errors.notFound"));
46
+ setError(t("exchangeRates.form.errors.load"));
44
47
  }
45
48
  } catch (err) {
46
49
  setError(t("exchangeRates.form.errors.load"));
@@ -57,8 +60,18 @@ function EditExchangeRatePage({ params }) {
57
60
  if (loading) {
58
61
  return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(LoadingMessage, { label: t("exchangeRates.form.loading") }) }) });
59
62
  }
63
+ if (isNotFound) {
64
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
65
+ RecordNotFoundState,
66
+ {
67
+ label: t("exchangeRates.form.errors.notFound"),
68
+ backHref: "/backend/exchange-rates",
69
+ backLabel: t("exchangeRates.form.actions.backToList", "Back to exchange rates")
70
+ }
71
+ ) }) });
72
+ }
60
73
  if (error || !exchangeRate) {
61
- return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(ErrorMessage, { label: error || t("exchangeRates.form.errors.notFound") }) }) });
74
+ return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(ErrorMessage, { label: error ?? t("exchangeRates.form.errors.load") }) }) });
62
75
  }
63
76
  return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
64
77
  CrudForm,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/currencies/backend/exchange-rates/%5Bid%5D/page.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n loadCurrencyOptions,\n exchangeRateGroups,\n validateExchangeRateForm,\n buildExchangeRatePayload,\n} from '../../../lib/exchangeRateFormConfig'\n\n/**\n * Formats a Date object to YYYY-MM-DDTHH:MM format in local timezone\n * for use with datetime-local input\n */\nfunction formatDateTimeLocal(date: Date): string {\n const year = date.getFullYear()\n const month = String(date.getMonth() + 1).padStart(2, '0')\n const day = String(date.getDate()).padStart(2, '0')\n const hours = String(date.getHours()).padStart(2, '0')\n const minutes = String(date.getMinutes()).padStart(2, '0')\n return `${year}-${month}-${day}T${hours}:${minutes}`\n}\n\ntype ExchangeRateData = {\n id: string\n fromCurrencyCode: string\n toCurrencyCode: string\n rate: string\n date: string\n source: string | null\n type: string | null\n isActive: boolean\n organizationId: string\n tenantId: string\n}\n\nexport default function EditExchangeRatePage({ params }: { params?: { id?: string } }) {\n const t = useT()\n const router = useRouter()\n\n const [exchangeRate, setExchangeRate] = React.useState<ExchangeRateData | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n\n const loadOptions = React.useCallback(\n (query?: string) => loadCurrencyOptions(apiCall, query),\n []\n )\n\n // Load exchange rate data\n React.useEffect(() => {\n async function loadExchangeRate() {\n try {\n const response = await apiCall<{ items: ExchangeRateData[] }>(`/api/currencies/exchange-rates?id=${params?.id}`)\n if (response.ok && response.result && response.result.items.length > 0) {\n setExchangeRate(response.result.items[0])\n } else {\n setError(t('exchangeRates.form.errors.notFound'))\n }\n } catch (err) {\n setError(t('exchangeRates.form.errors.load'))\n } finally {\n setLoading(false)\n }\n }\n loadExchangeRate()\n }, [params, t])\n\n const groups = React.useMemo(\n () => exchangeRateGroups(t, loadOptions),\n [t, loadOptions]\n )\n\n if (loading) {\n return (\n <Page>\n <PageBody>\n <LoadingMessage label={t('exchangeRates.form.loading')} />\n </PageBody>\n </Page>\n )\n }\n\n if (error || !exchangeRate) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error || t('exchangeRates.form.errors.notFound')} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm\n title={t('exchangeRates.edit.title')}\n backHref=\"/backend/exchange-rates\"\n versionHistory={{ resourceKind: 'currencies.exchange_rate', resourceId: exchangeRate.id }}\n fields={[]}\n groups={groups}\n initialValues={{\n fromCurrencyCode: exchangeRate.fromCurrencyCode,\n toCurrencyCode: exchangeRate.toCurrencyCode,\n rate: parseFloat(exchangeRate.rate),\n date: formatDateTimeLocal(new Date(exchangeRate.date)),\n source: exchangeRate.source || '',\n type: exchangeRate.type || '',\n isActive: exchangeRate.isActive,\n }}\n submitLabel={t('exchangeRates.form.action.save')}\n cancelHref=\"/backend/exchange-rates\"\n onSubmit={async (values) => {\n const validated = validateExchangeRateForm(values, t)\n const payload = {\n id: exchangeRate.id,\n ...buildExchangeRatePayload(values, validated),\n }\n\n await updateCrud('currencies/exchange-rates', payload)\n\n flash(t('exchangeRates.flash.updated'), 'success')\n router.push('/backend/exchange-rates')\n }}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { LoadingMessage, ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n loadCurrencyOptions,\n exchangeRateGroups,\n validateExchangeRateForm,\n buildExchangeRatePayload,\n} from '../../../lib/exchangeRateFormConfig'\n\n/**\n * Formats a Date object to YYYY-MM-DDTHH:MM format in local timezone\n * for use with datetime-local input\n */\nfunction formatDateTimeLocal(date: Date): string {\n const year = date.getFullYear()\n const month = String(date.getMonth() + 1).padStart(2, '0')\n const day = String(date.getDate()).padStart(2, '0')\n const hours = String(date.getHours()).padStart(2, '0')\n const minutes = String(date.getMinutes()).padStart(2, '0')\n return `${year}-${month}-${day}T${hours}:${minutes}`\n}\n\ntype ExchangeRateData = {\n id: string\n fromCurrencyCode: string\n toCurrencyCode: string\n rate: string\n date: string\n source: string | null\n type: string | null\n isActive: boolean\n organizationId: string\n tenantId: string\n}\n\nexport default function EditExchangeRatePage({ params }: { params?: { id?: string } }) {\n const t = useT()\n const router = useRouter()\n\n const [exchangeRate, setExchangeRate] = React.useState<ExchangeRateData | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n\n const loadOptions = React.useCallback(\n (query?: string) => loadCurrencyOptions(apiCall, query),\n []\n )\n\n // Load exchange rate data\n React.useEffect(() => {\n async function loadExchangeRate() {\n try {\n const response = await apiCall<{ items: ExchangeRateData[] }>(`/api/currencies/exchange-rates?id=${params?.id}`)\n if (response.ok && response.result && response.result.items.length > 0) {\n setExchangeRate(response.result.items[0])\n } else if (response.ok) {\n setIsNotFound(true)\n } else {\n setError(t('exchangeRates.form.errors.load'))\n }\n } catch (err) {\n setError(t('exchangeRates.form.errors.load'))\n } finally {\n setLoading(false)\n }\n }\n loadExchangeRate()\n }, [params, t])\n\n const groups = React.useMemo(\n () => exchangeRateGroups(t, loadOptions),\n [t, loadOptions]\n )\n\n if (loading) {\n return (\n <Page>\n <PageBody>\n <LoadingMessage label={t('exchangeRates.form.loading')} />\n </PageBody>\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('exchangeRates.form.errors.notFound')}\n backHref=\"/backend/exchange-rates\"\n backLabel={t('exchangeRates.form.actions.backToList', 'Back to exchange rates')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error || !exchangeRate) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error ?? t('exchangeRates.form.errors.load')} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm\n title={t('exchangeRates.edit.title')}\n backHref=\"/backend/exchange-rates\"\n versionHistory={{ resourceKind: 'currencies.exchange_rate', resourceId: exchangeRate.id }}\n fields={[]}\n groups={groups}\n initialValues={{\n fromCurrencyCode: exchangeRate.fromCurrencyCode,\n toCurrencyCode: exchangeRate.toCurrencyCode,\n rate: parseFloat(exchangeRate.rate),\n date: formatDateTimeLocal(new Date(exchangeRate.date)),\n source: exchangeRate.source || '',\n type: exchangeRate.type || '',\n isActive: exchangeRate.isActive,\n }}\n submitLabel={t('exchangeRates.form.action.save')}\n cancelHref=\"/backend/exchange-rates\"\n onSubmit={async (values) => {\n const validated = validateExchangeRateForm(values, t)\n const payload = {\n id: exchangeRate.id,\n ...buildExchangeRatePayload(values, validated),\n }\n\n await updateCrud('currencies/exchange-rates', payload)\n\n flash(t('exchangeRates.flash.updated'), 'success')\n router.push('/backend/exchange-rates')\n }}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -768,6 +768,8 @@ async function GET(_req, ctx) {
768
768
  organizationId: company.organizationId,
769
769
  tenantId: company.tenantId,
770
770
  isActive: company.isActive,
771
+ temperature: company.temperature ?? null,
772
+ renewalQuarter: company.renewalQuarter ?? null,
771
773
  createdAt: company.createdAt.toISOString(),
772
774
  updatedAt: company.updatedAt.toISOString()
773
775
  },
@@ -944,6 +946,8 @@ const companyDetailResponseSchema = z.object({
944
946
  organizationId: z.string().uuid().nullable().optional(),
945
947
  tenantId: z.string().uuid().nullable().optional(),
946
948
  isActive: z.boolean().optional(),
949
+ temperature: z.string().nullable().optional(),
950
+ renewalQuarter: z.string().nullable().optional(),
947
951
  createdAt: z.string(),
948
952
  updatedAt: z.string()
949
953
  }),