feat: implementar soporte para carga de etiquetas de informe multilingüe y eliminar etiquetas obsoletas
This commit is contained in:
parent
ac117c1b18
commit
d6387f6e3e
@ -25,8 +25,7 @@ RUN cd ./server && yarn install
|
||||
RUN cd ./server && yarn run build || { echo 'Error during build'; exit 1; }
|
||||
|
||||
# Copiar plantillas
|
||||
RUN mkdir -p /api/dist/server/src/contexts/sales/infrastructure/express/controllers/quotes/reportQuote/reporter/templates/quote/
|
||||
COPY server/src/contexts/sales/infrastructure/express/controllers/quotes/reportQuote/reporter/templates/quote/* /api/dist/server/src/contexts/sales/infrastructure/express/controllers/quotes/reportQuote/reporter/templates/quote
|
||||
COPY server/src/contexts/sales/infrastructure/express/controllers/quotes/reportQuote/reporter/templates/quote/ /api/dist/server/src/contexts/sales/infrastructure/express/controllers/quotes/reportQuote/reporter/templates/quote/
|
||||
|
||||
# Copiar logo por defecto
|
||||
RUN mkdir -p /api/dist/uploads/images/
|
||||
@ -75,4 +74,3 @@ EXPOSE 3001
|
||||
|
||||
# Comando para correr la aplicación
|
||||
CMD node -r ts-node/register/transpile-only -r tsconfig-paths/register ./server/src/index.js
|
||||
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
import { readFileSync } from "fs";
|
||||
import path from "path";
|
||||
|
||||
export const REPORT_LANGUAGES = ["es", "en", "fr"] as const;
|
||||
export type ReportLanguage = (typeof REPORT_LANGUAGES)[number];
|
||||
|
||||
export interface ReportLabels {
|
||||
official_distributor: string;
|
||||
dealer_logo: string;
|
||||
document_title: string;
|
||||
browser_title: string;
|
||||
quote_number: string;
|
||||
date: string;
|
||||
validity: string;
|
||||
salesperson: string;
|
||||
customer_reference: string;
|
||||
page: string;
|
||||
of: string;
|
||||
quantity: string;
|
||||
description: string;
|
||||
unit_price: string;
|
||||
subtotal: string;
|
||||
discount: string;
|
||||
total_amount: string;
|
||||
payment_method: string;
|
||||
notes: string;
|
||||
net_amount: string;
|
||||
discounts: string;
|
||||
percentage_discount: string;
|
||||
taxable_amount: string;
|
||||
}
|
||||
|
||||
export const resolveReportLanguage = (language: string): ReportLanguage =>
|
||||
REPORT_LANGUAGES.includes(language as ReportLanguage) ? (language as ReportLanguage) : "es";
|
||||
|
||||
const requiredKeys = [
|
||||
"official_distributor", "dealer_logo", "document_title", "browser_title", "quote_number",
|
||||
"date", "validity", "salesperson", "customer_reference", "page", "of", "quantity",
|
||||
"description", "unit_price", "subtotal", "discount", "total_amount", "payment_method",
|
||||
"notes", "net_amount", "discounts", "percentage_discount", "taxable_amount",
|
||||
] satisfies (keyof ReportLabels)[];
|
||||
|
||||
export const loadReportLabels = (language: ReportLanguage): ReportLabels => {
|
||||
const filepath = path.join(__dirname, "./templates/quote/locales", `${language}.json`);
|
||||
const labels = JSON.parse(readFileSync(filepath, "utf8")) as Partial<ReportLabels>;
|
||||
const missingKeys = requiredKeys.filter((key) => !(key in labels));
|
||||
|
||||
if (missingKeys.length) {
|
||||
throw new Error(`Missing report labels for ${language}: ${missingKeys.join(", ")}`);
|
||||
}
|
||||
|
||||
return labels as ReportLabels;
|
||||
};
|
||||
@ -1,82 +0,0 @@
|
||||
export const reportLabels = {
|
||||
es: {
|
||||
official_distributor: "DISTRIBUIDOR OFICIAL",
|
||||
dealer_logo: "Logo distribuidor",
|
||||
document_title: "PRESUPUESTO",
|
||||
browser_title: "Presupuesto",
|
||||
quote_number: "Presupuesto nº:",
|
||||
date: "Fecha:",
|
||||
validity: "Validez:",
|
||||
salesperson: "Vendedor:",
|
||||
customer_reference: "Referencia cliente:",
|
||||
page: "Página",
|
||||
of: "de",
|
||||
quantity: "Cant.",
|
||||
description: "Descripción",
|
||||
unit_price: "Prec. Unitario",
|
||||
subtotal: "Subtotal",
|
||||
discount: "Dto (%)",
|
||||
total_amount: "Importe total",
|
||||
payment_method: "Forma de pago:",
|
||||
notes: "Notas:",
|
||||
net_amount: "Importe neto",
|
||||
discounts: "Descuentos",
|
||||
percentage_discount: "% Descuento",
|
||||
taxable_amount: "Base imponible",
|
||||
},
|
||||
en: {
|
||||
official_distributor: "OFFICIAL DISTRIBUTOR",
|
||||
dealer_logo: "Dealer logo",
|
||||
document_title: "QUOTE",
|
||||
browser_title: "Quote",
|
||||
quote_number: "Quote no.:",
|
||||
date: "Date:",
|
||||
validity: "Validity:",
|
||||
salesperson: "Salesperson:",
|
||||
customer_reference: "Customer reference:",
|
||||
page: "Page",
|
||||
of: "of",
|
||||
quantity: "Qty.",
|
||||
description: "Description",
|
||||
unit_price: "Unit price",
|
||||
subtotal: "Subtotal",
|
||||
discount: "Discount (%)",
|
||||
total_amount: "Total amount",
|
||||
payment_method: "Payment method:",
|
||||
notes: "Notes:",
|
||||
net_amount: "Net amount",
|
||||
discounts: "Discounts",
|
||||
percentage_discount: "% Discount",
|
||||
taxable_amount: "Taxable amount",
|
||||
},
|
||||
fr: {
|
||||
official_distributor: "DISTRIBUTEUR OFFICIEL",
|
||||
dealer_logo: "Logo du distributeur",
|
||||
document_title: "DEVIS",
|
||||
browser_title: "Devis",
|
||||
quote_number: "Devis n° :",
|
||||
date: "Date :",
|
||||
validity: "Validité :",
|
||||
salesperson: "Commercial :",
|
||||
customer_reference: "Référence client :",
|
||||
page: "Page",
|
||||
of: "sur",
|
||||
quantity: "Qté",
|
||||
description: "Description",
|
||||
unit_price: "Prix unitaire",
|
||||
subtotal: "Sous-total",
|
||||
discount: "Remise (%)",
|
||||
total_amount: "Montant total",
|
||||
payment_method: "Mode de paiement :",
|
||||
notes: "Notes :",
|
||||
net_amount: "Montant net",
|
||||
discounts: "Remises",
|
||||
percentage_discount: "% de remise",
|
||||
taxable_amount: "Base imposable",
|
||||
},
|
||||
} as const;
|
||||
|
||||
export type ReportLanguage = keyof typeof reportLabels;
|
||||
|
||||
export const resolveReportLanguage = (language: string): ReportLanguage =>
|
||||
language === "en" || language === "fr" ? language : "es";
|
||||
@ -1,6 +1,6 @@
|
||||
import { ISalesContext } from "@/contexts/sales/infrastructure/Sales.context";
|
||||
import { createQuoteMapper } from "@/contexts/sales/infrastructure/mappers/quote.mapper";
|
||||
import { resolveReportLanguage } from "./ReportQuote.labels";
|
||||
import { loadReportLabels, resolveReportLanguage } from "./ReportQuote.i18n";
|
||||
import { ReportQuotePresenter } from "./ReportQuote.reporter";
|
||||
|
||||
const source = (
|
||||
@ -82,4 +82,8 @@ describe("ReportQuotePresenter", () => {
|
||||
it("falls back to Spanish labels and language for unsupported quote languages", async () => {
|
||||
expect(resolveReportLanguage("zz")).toBe("es");
|
||||
});
|
||||
|
||||
it("loads the French labels from the template locale", () => {
|
||||
expect(loadReportLabels("fr").document_title).toBe("DEVIS");
|
||||
});
|
||||
});
|
||||
|
||||
@ -7,7 +7,7 @@ import * as handlebars from "handlebars";
|
||||
import path from "path";
|
||||
import puppeteer from "puppeteer";
|
||||
import report from "puppeteer-report";
|
||||
import { reportLabels, resolveReportLanguage } from "./ReportQuote.labels";
|
||||
import { loadReportLabels, resolveReportLanguage } from "./ReportQuote.i18n";
|
||||
import { Language } from "@shared/contexts";
|
||||
import { resolveLocalizedQuoteDescriptions } from "@/contexts/sales/application/services";
|
||||
|
||||
@ -82,7 +82,7 @@ const map = async (quote: Quote, context: ISalesContext) => {
|
||||
customer_reference: quote.customerReference.toString(),
|
||||
customer_information: quote.customer.toString(),
|
||||
lang_code: langCode,
|
||||
labels: reportLabels[langCode],
|
||||
labels: loadReportLabels(langCode),
|
||||
currency_code: quote.currency.toString(),
|
||||
|
||||
payment_method: quote.paymentMethod.toString(),
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"official_distributor": "OFFICIAL DISTRIBUTOR", "dealer_logo": "Dealer logo", "document_title": "QUOTE", "browser_title": "Quote", "quote_number": "Quote no.:", "date": "Date:", "validity": "Validity:", "salesperson": "Salesperson:", "customer_reference": "Customer reference:", "page": "Page", "of": "of", "quantity": "Qty.", "description": "Description", "unit_price": "Unit price", "subtotal": "Subtotal", "discount": "Discount (%)", "total_amount": "Total amount", "payment_method": "Payment method:", "notes": "Notes:", "net_amount": "Net amount", "discounts": "Discounts", "percentage_discount": "% Discount", "taxable_amount": "Taxable amount"
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"official_distributor": "DISTRIBUIDOR OFICIAL", "dealer_logo": "Logo distribuidor", "document_title": "PRESUPUESTO", "browser_title": "Presupuesto", "quote_number": "Presupuesto nº:", "date": "Fecha:", "validity": "Validez:", "salesperson": "Vendedor:", "customer_reference": "Referencia cliente:", "page": "Página", "of": "de", "quantity": "Cant.", "description": "Descripción", "unit_price": "Prec. Unitario", "subtotal": "Subtotal", "discount": "Dto (%)", "total_amount": "Importe total", "payment_method": "Forma de pago:", "notes": "Notas:", "net_amount": "Importe neto", "discounts": "Descuentos", "percentage_discount": "% Descuento", "taxable_amount": "Base imponible"
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"official_distributor": "DISTRIBUTEUR OFFICIEL", "dealer_logo": "Logo du distributeur", "document_title": "DEVIS", "browser_title": "Devis", "quote_number": "Devis n° :", "date": "Date :", "validity": "Validité :", "salesperson": "Commercial :", "customer_reference": "Référence client :", "page": "Page", "of": "sur", "quantity": "Qté", "description": "Description", "unit_price": "Prix unitaire", "subtotal": "Sous-total", "discount": "Remise (%)", "total_amount": "Montant total", "payment_method": "Mode de paiement :", "notes": "Notes :", "net_amount": "Montant net", "discounts": "Remises", "percentage_discount": "% de remise", "taxable_amount": "Base imposable"
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user