diff --git a/Dockerfile b/Dockerfile index 41c100c..34b1813 100644 --- a/Dockerfile +++ b/Dockerfile @@ -46,6 +46,9 @@ COPY --from=build /app/server ./server # Quote PDF branding asset loaded at runtime by pdf generation COPY logo.png ./logo.png +# Sales tax lookup data loaded by expectedSalesTax at runtime +COPY --from=build /app/src/modules/sales-utils/salesTaxRates.json ./salesTaxRates.json + # Copy Prisma artifacts needed at runtime COPY --from=build /app/generated/ ./generated/ COPY --from=build /app/prisma/ ./prisma/ diff --git a/src/modules/sales-utils/expectedSalesTax.ts b/src/modules/sales-utils/expectedSalesTax.ts index b3da9c9..1b079e2 100644 --- a/src/modules/sales-utils/expectedSalesTax.ts +++ b/src/modules/sales-utils/expectedSalesTax.ts @@ -1,4 +1,5 @@ import { readFileSync } from "fs"; +import { join } from "path"; export interface SalesTaxAddressInput { line1?: string | null; @@ -25,18 +26,26 @@ interface StateTaxRecord { local_jurisdictions?: LocalJurisdiction[]; } -const taxDataPath = new URL("./salesTaxRates.json", import.meta.url); +const TAX_DATA_FALLBACK_URL = new URL("./salesTaxRates.json", import.meta.url); + +const TAX_DATA_CANDIDATE_PATHS: Array = [ + process.env.SALES_TAX_RATES_PATH ?? "", + join(process.cwd(), "salesTaxRates.json"), + TAX_DATA_FALLBACK_URL, +].filter(Boolean); const parseTaxData = (): StateTaxRecord[] => { - try { - const raw = readFileSync(taxDataPath, "utf-8"); - const parsed = JSON.parse(raw) as StateTaxRecord[]; - - if (!Array.isArray(parsed)) return []; - return parsed; - } catch { - return []; + for (const source of TAX_DATA_CANDIDATE_PATHS) { + try { + const raw = readFileSync(source, "utf-8"); + const parsed = JSON.parse(raw) as StateTaxRecord[]; + if (Array.isArray(parsed)) return parsed; + } catch { + continue; + } } + + return []; }; const SALES_TAX_DATA = parseTaxData();