Informes de facturas de cliente
This commit is contained in:
parent
156dc9db0f
commit
747d11a956
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
// other vscode settings
|
// other vscode settings
|
||||||
"[handlebars]": {
|
"[handlebars]": {
|
||||||
"editor.defaultFormatter": "vscode.html-language-features"
|
"editor.defaultFormatter": "mfeckies.handlebars-formatter"
|
||||||
},
|
},
|
||||||
"[sql]": {
|
"[sql]": {
|
||||||
"editor.defaultFormatter": "cweijan.vscode-mysql-client2"
|
"editor.defaultFormatter": "cweijan.vscode-mysql-client2"
|
||||||
|
|||||||
@ -292,6 +292,14 @@
|
|||||||
"enabled": true
|
"enabled": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"html": {
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true,
|
||||||
|
"indentStyle": "space",
|
||||||
|
"indentWidth": 2,
|
||||||
|
"lineWidth": 100
|
||||||
|
}
|
||||||
|
},
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"includes": ["**/*.test.{js,ts,tsx}", "**/*.spec.{js,ts,tsx}", "**/__tests__/**"],
|
"includes": ["**/*.test.{js,ts,tsx}", "**/*.spec.{js,ts,tsx}", "**/__tests__/**"],
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { IPresenter } from "./presenter.interface";
|
import type { IPresenter } from "./presenter.interface";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 🔑 Claves de proyección comunes para seleccionar presenters
|
* 🔑 Claves de proyección comunes para seleccionar presenters
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { Criteria, CriteriaFromUrlConverter } from "@repo/rdx-criteria/server";
|
import { type Criteria, CriteriaFromUrlConverter } from "@repo/rdx-criteria/server";
|
||||||
import { UniqueID } from "@repo/rdx-ddd";
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { NextFunction, Request, Response } from "express";
|
import type { NextFunction, Request, Response } from "express";
|
||||||
import httpStatus from "http-status";
|
import httpStatus from "http-status";
|
||||||
import { ApiErrorContext, ApiErrorMapper, toProblemJson } from "./api-error-mapper";
|
|
||||||
|
import { type ApiErrorContext, ApiErrorMapper, toProblemJson } from "./api-error-mapper";
|
||||||
import {
|
import {
|
||||||
ApiError,
|
type ApiError,
|
||||||
ConflictApiError,
|
ConflictApiError,
|
||||||
ForbiddenApiError,
|
ForbiddenApiError,
|
||||||
InternalApiError,
|
InternalApiError,
|
||||||
@ -13,7 +14,7 @@ import {
|
|||||||
UnavailableApiError,
|
UnavailableApiError,
|
||||||
ValidationApiError,
|
ValidationApiError,
|
||||||
} from "./errors";
|
} from "./errors";
|
||||||
import { GuardFn } from "./express-guards";
|
import type { GuardFn } from "./express-guards";
|
||||||
|
|
||||||
export abstract class ExpressController {
|
export abstract class ExpressController {
|
||||||
protected req!: Request;
|
protected req!: Request;
|
||||||
@ -125,6 +126,15 @@ export abstract class ExpressController {
|
|||||||
return this.res.send(pdfBuffer);
|
return this.res.send(pdfBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public downloadHTML(htmlString: string) {
|
||||||
|
this.res.set({
|
||||||
|
"Content-Type": "text/html; charset=utf-8",
|
||||||
|
"Content-Length": Buffer.byteLength(htmlString, "utf-8"),
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.res.send(htmlString);
|
||||||
|
}
|
||||||
|
|
||||||
protected clientError(message: string, errors?: any[] | any) {
|
protected clientError(message: string, errors?: any[] | any) {
|
||||||
return this.handleApiError(
|
return this.handleApiError(
|
||||||
new ValidationApiError(message, Array.isArray(errors) ? errors : [errors])
|
new ValidationApiError(message, Array.isArray(errors) ? errors : [errors])
|
||||||
|
|||||||
@ -5,11 +5,6 @@ import { lookup } from "mime-types";
|
|||||||
|
|
||||||
import { TemplateResolver } from "./template-resolver";
|
import { TemplateResolver } from "./template-resolver";
|
||||||
|
|
||||||
interface AssetHelperOptions {
|
|
||||||
baseDir: string;
|
|
||||||
mode: "local_file" | "base64";
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HandlebarsTemplateResolver extends TemplateResolver {
|
export class HandlebarsTemplateResolver extends TemplateResolver {
|
||||||
protected readonly hbs = Handlebars.create();
|
protected readonly hbs = Handlebars.create();
|
||||||
protected registered = false;
|
protected registered = false;
|
||||||
@ -18,18 +13,16 @@ export class HandlebarsTemplateResolver extends TemplateResolver {
|
|||||||
/**
|
/**
|
||||||
* Registra el helper "asset".
|
* Registra el helper "asset".
|
||||||
*
|
*
|
||||||
* - Si `mode === "local_file"` → devuelve file://...
|
|
||||||
* - Si `mode === "base64"`:
|
|
||||||
* - Si el fichero termina en .b64 → se asume que el contenido ya es base64
|
* - Si el fichero termina en .b64 → se asume que el contenido ya es base64
|
||||||
* - Si no → se lee binario y se convierte a base64
|
* - Si no → se lee binario y se convierte a base64
|
||||||
*/
|
*/
|
||||||
protected registerAssetHelper(templateDir: string, mode: "local_file" | "base64") {
|
protected registerAssetHelper(templateDir: string) {
|
||||||
// Si ya está registrado, no hacer nada
|
// Si ya está registrado, no hacer nada
|
||||||
if (this.registered) return;
|
if (this.registered) return;
|
||||||
|
|
||||||
this.hbs.registerHelper("asset", (resource: string) => {
|
this.hbs.registerHelper("asset", (resource: string) => {
|
||||||
const assetPath = this.resolveAssetPath(templateDir, resource);
|
const assetPath = this.resolveAssetPath(templateDir, resource);
|
||||||
const cacheKey = `${mode}:${assetPath}`;
|
const cacheKey = `${assetPath}`;
|
||||||
|
|
||||||
// 1) Caché en memoria
|
// 1) Caché en memoria
|
||||||
const cached = this.assetCache.get(cacheKey);
|
const cached = this.assetCache.get(cacheKey);
|
||||||
@ -41,18 +34,12 @@ export class HandlebarsTemplateResolver extends TemplateResolver {
|
|||||||
throw new Error(`Asset not found: ${assetPath}`);
|
throw new Error(`Asset not found: ${assetPath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Modo "local_file": solo devolver la ruta de fichero
|
|
||||||
if (mode === "local_file") {
|
|
||||||
const value = `file://${assetPath.replace(/\\/g, "/")}`;
|
|
||||||
this.assetCache.set(cacheKey, value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3) Modo "base64"
|
// 3) Modo "base64"
|
||||||
const isPreencoded = assetPath.endsWith(".b64");
|
const isPreencoded = assetPath.endsWith(".b64");
|
||||||
|
|
||||||
let base64: string;
|
let base64: string;
|
||||||
let mimeType: string;
|
let mimeType: string;
|
||||||
|
let value: string;
|
||||||
|
|
||||||
if (isPreencoded) {
|
if (isPreencoded) {
|
||||||
// Fichero ya contiene el base64 en texto plano
|
// Fichero ya contiene el base64 en texto plano
|
||||||
@ -61,14 +48,24 @@ export class HandlebarsTemplateResolver extends TemplateResolver {
|
|||||||
// Para el MIME usamos el nombre "original" sin .b64
|
// Para el MIME usamos el nombre "original" sin .b64
|
||||||
const mimeLookupPath = assetPath.replace(/\.b64$/, "");
|
const mimeLookupPath = assetPath.replace(/\.b64$/, "");
|
||||||
mimeType = (lookup(mimeLookupPath) || "application/octet-stream") as string;
|
mimeType = (lookup(mimeLookupPath) || "application/octet-stream") as string;
|
||||||
|
value = `data:${mimeType};base64,${base64}`;
|
||||||
} else {
|
} else {
|
||||||
// Fichero binario normal → convertimos a base64
|
// Fichero normal
|
||||||
const buffer = readFileSync(assetPath);
|
|
||||||
mimeType = (lookup(assetPath) || "application/octet-stream") as string;
|
// Si es un CSS no se convierte y se incrusta
|
||||||
base64 = buffer.toString("base64");
|
const isCSS = assetPath.endsWith(".css");
|
||||||
|
if (isCSS) {
|
||||||
|
const buffer = readFileSync(assetPath);
|
||||||
|
value = buffer.toString();
|
||||||
|
} else {
|
||||||
|
// En otro caso, se transforma a Base64
|
||||||
|
const buffer = readFileSync(assetPath);
|
||||||
|
mimeType = (lookup(assetPath) || "application/octet-stream") as string;
|
||||||
|
base64 = buffer.toString("base64");
|
||||||
|
value = `data:${mimeType};base64,${base64}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = `data:${mimeType};base64,${base64}`;
|
|
||||||
this.assetCache.set(cacheKey, value);
|
this.assetCache.set(cacheKey, value);
|
||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
@ -87,14 +84,12 @@ export class HandlebarsTemplateResolver extends TemplateResolver {
|
|||||||
companySlug: string,
|
companySlug: string,
|
||||||
templateName: string
|
templateName: string
|
||||||
): Handlebars.TemplateDelegate {
|
): Handlebars.TemplateDelegate {
|
||||||
const isDev = process.env.NODE_ENV === "development";
|
|
||||||
|
|
||||||
// 1) Directorio de plantillas
|
// 1) Directorio de plantillas
|
||||||
const templateDir = this.resolveTemplateDirectory(module, companySlug);
|
const templateDir = this.resolveTemplateDirectory(module, companySlug);
|
||||||
const templatePath = this.resolveTemplatePath(module, companySlug, templateName); // 2) Path completo del template
|
const templatePath = this.resolveTemplatePath(module, companySlug, templateName); // 2) Path completo del template
|
||||||
const source = this.readTemplateFile(templatePath); // Contenido
|
const source = this.readTemplateFile(templatePath); // Contenido
|
||||||
|
|
||||||
this.registerAssetHelper(templateDir, isDev ? "local_file" : "base64");
|
this.registerAssetHelper(templateDir);
|
||||||
|
|
||||||
// 5) Compilar
|
// 5) Compilar
|
||||||
return this.compile(source);
|
return this.compile(source);
|
||||||
|
|||||||
@ -55,8 +55,7 @@
|
|||||||
"libphonenumber-js": "^1.12.7",
|
"libphonenumber-js": "^1.12.7",
|
||||||
"lucide-react": "^0.503.0",
|
"lucide-react": "^0.503.0",
|
||||||
"pg-hstore": "^2.3.4",
|
"pg-hstore": "^2.3.4",
|
||||||
"puppeteer": "^24.20.0",
|
"puppeteer": "^24.30.0",
|
||||||
"puppeteer-report": "^3.2.0",
|
|
||||||
"react-hook-form": "^7.58.1",
|
"react-hook-form": "^7.58.1",
|
||||||
"react-i18next": "^15.5.1",
|
"react-i18next": "^15.5.1",
|
||||||
"react-router-dom": "^6.26.0",
|
"react-router-dom": "^6.26.0",
|
||||||
|
|||||||
@ -21,7 +21,7 @@ export class IssuedInvoiceVerifactuFullPresenter extends Presenter {
|
|||||||
}),
|
}),
|
||||||
() => ({
|
() => ({
|
||||||
id: "",
|
id: "",
|
||||||
status: "",
|
status: "Pendiente",
|
||||||
url: "",
|
url: "",
|
||||||
qr_code: "",
|
qr_code: "",
|
||||||
})
|
})
|
||||||
|
|||||||
@ -10,6 +10,7 @@ type ReportIssuedInvoiceUseCaseInput = {
|
|||||||
companyId: UniqueID;
|
companyId: UniqueID;
|
||||||
companySlug: string;
|
companySlug: string;
|
||||||
invoice_id: string;
|
invoice_id: string;
|
||||||
|
format: "pdf" | "html";
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ReportIssuedInvoiceUseCase {
|
export class ReportIssuedInvoiceUseCase {
|
||||||
@ -20,7 +21,7 @@ export class ReportIssuedInvoiceUseCase {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
public async execute(params: ReportIssuedInvoiceUseCaseInput) {
|
public async execute(params: ReportIssuedInvoiceUseCaseInput) {
|
||||||
const { invoice_id, companyId, companySlug } = params;
|
const { invoice_id, companyId, companySlug, format } = params;
|
||||||
|
|
||||||
const idOrError = UniqueID.create(invoice_id);
|
const idOrError = UniqueID.create(invoice_id);
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ export class ReportIssuedInvoiceUseCase {
|
|||||||
const pdfPresenter = this.presenterRegistry.getPresenter({
|
const pdfPresenter = this.presenterRegistry.getPresenter({
|
||||||
resource: "issued-invoice",
|
resource: "issued-invoice",
|
||||||
projection: "REPORT",
|
projection: "REPORT",
|
||||||
format: "PDF",
|
format,
|
||||||
}) as IssuedInvoiceReportPDFPresenter;
|
}) as IssuedInvoiceReportPDFPresenter;
|
||||||
|
|
||||||
return this.transactionManager.complete(async (transaction) => {
|
return this.transactionManager.complete(async (transaction) => {
|
||||||
@ -48,10 +49,18 @@ export class ReportIssuedInvoiceUseCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const invoice = invoiceOrError.data;
|
const invoice = invoiceOrError.data;
|
||||||
const pdfData = await pdfPresenter.toOutput(invoice, { companySlug });
|
const reportData = await pdfPresenter.toOutput(invoice, { companySlug });
|
||||||
|
|
||||||
|
if (format === "html") {
|
||||||
|
return Result.ok({
|
||||||
|
data: String(reportData),
|
||||||
|
filename: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return Result.ok({
|
return Result.ok({
|
||||||
data: pdfData,
|
data: reportData as Buffer<ArrayBuffer>,
|
||||||
filename: `invoice-${invoice.invoiceNumber}.pdf`,
|
filename: `proforma-${invoice.invoiceNumber}.pdf`,
|
||||||
});
|
});
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
return Result.fail(error as Error);
|
return Result.fail(error as Error);
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { Presenter } from "@erp/core/api";
|
import { Presenter } from "@erp/core/api";
|
||||||
import puppeteer from "puppeteer";
|
import puppeteer from "puppeteer";
|
||||||
import report from "puppeteer-report";
|
|
||||||
|
|
||||||
import type { CustomerInvoice } from "../../../../../domain";
|
import type { CustomerInvoice } from "../../../../../domain";
|
||||||
|
|
||||||
import type { IssuedInvoiceReportHTMLPresenter } from "./issued-invoice.report.html";
|
import type { IssuedInvoiceReportHTMLPresenter } from "./issued-invoice.report.html";
|
||||||
|
|
||||||
// https://plnkr.co/edit/lWk6Yd?preview
|
// https://plnkr.co/edit/lWk6Yd?preview
|
||||||
|
// https://latenode.com/es/blog/web-automation-scraping/puppeteer-fundamentals-setup/complete-guide-to-pdf-generation-with-puppeteer-from-simple-documents-to-complex-reports
|
||||||
|
|
||||||
export class IssuedInvoiceReportPDFPresenter extends Presenter<
|
export class IssuedInvoiceReportPDFPresenter extends Presenter<
|
||||||
CustomerInvoice,
|
CustomerInvoice,
|
||||||
@ -27,35 +27,35 @@ export class IssuedInvoiceReportPDFPresenter extends Presenter<
|
|||||||
|
|
||||||
// Generar el PDF con Puppeteer
|
// Generar el PDF con Puppeteer
|
||||||
const browser = await puppeteer.launch({
|
const browser = await puppeteer.launch({
|
||||||
headless: "new",
|
//headless: "new",
|
||||||
executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
|
executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
|
||||||
args: ["--font-render-hinting=medium"],
|
args: ["--font-render-hinting=medium"],
|
||||||
});
|
});
|
||||||
|
|
||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
page.setDefaultNavigationTimeout(60000);
|
//page.setDefaultNavigationTimeout(60000);
|
||||||
page.setDefaultTimeout(60000);
|
//page.setDefaultTimeout(60000);
|
||||||
|
|
||||||
await page.setContent(htmlData, {
|
await page.setContent(htmlData, {
|
||||||
waitUntil: "networkidle0",
|
waitUntil: "networkidle2",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Espera extra opcional si hay imágenes base64 muy grandes
|
// Espera extra opcional si hay imágenes base64 muy grandes
|
||||||
await page.waitForNetworkIdle({ idleTime: 200, timeout: 5000 });
|
await page.waitForNetworkIdle({ idleTime: 200, timeout: 5000 });
|
||||||
|
|
||||||
const reportPDF = await report.pdfPage(page, {
|
const reportPDF = await page.pdf({
|
||||||
format: "A4",
|
format: "A4",
|
||||||
margin: {
|
margin: {
|
||||||
bottom: "10mm",
|
top: 0,
|
||||||
left: "10mm",
|
left: 0,
|
||||||
right: "10mm",
|
right: 0,
|
||||||
top: "10mm",
|
bottom: 0,
|
||||||
},
|
},
|
||||||
landscape: false,
|
landscape: false,
|
||||||
preferCSSPageSize: true,
|
preferCSSPageSize: true,
|
||||||
omitBackground: false,
|
omitBackground: false,
|
||||||
printBackground: true,
|
printBackground: true,
|
||||||
displayHeaderFooter: false,
|
displayHeaderFooter: true,
|
||||||
headerTemplate: "<div />",
|
headerTemplate: "<div />",
|
||||||
footerTemplate:
|
footerTemplate:
|
||||||
'<div style="text-align: center;width: 297mm;font-size: 10px;">Página <span style="margin-right: 1cm"><span class="pageNumber"></span> de <span class="totalPages"></span></span></span></div>',
|
'<div style="text-align: center;width: 297mm;font-size: 10px;">Página <span style="margin-right: 1cm"><span class="pageNumber"></span> de <span class="totalPages"></span></span></span></div>',
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import {
|
|||||||
IssueCustomerInvoiceDomainService,
|
IssueCustomerInvoiceDomainService,
|
||||||
ProformaCustomerInvoiceDomainService,
|
ProformaCustomerInvoiceDomainService,
|
||||||
} from "../../../domain";
|
} from "../../../domain";
|
||||||
import type { ProformaFullPresenter } from "../../presenters";
|
|
||||||
import type { CustomerInvoiceApplicationService } from "../../services";
|
import type { CustomerInvoiceApplicationService } from "../../services";
|
||||||
|
|
||||||
type IssueProformaUseCaseInput = {
|
type IssueProformaUseCaseInput = {
|
||||||
@ -42,10 +41,6 @@ export class IssueProformaUseCase {
|
|||||||
if (idOrError.isFailure) return Result.fail(idOrError.error);
|
if (idOrError.isFailure) return Result.fail(idOrError.error);
|
||||||
|
|
||||||
const proformaId = idOrError.data;
|
const proformaId = idOrError.data;
|
||||||
const presenter = this.presenterRegistry.getPresenter({
|
|
||||||
resource: "issued-invoice",
|
|
||||||
projection: "FULL",
|
|
||||||
}) as ProformaFullPresenter;
|
|
||||||
|
|
||||||
return this.transactionManager.complete(async (transaction) => {
|
return this.transactionManager.complete(async (transaction) => {
|
||||||
try {
|
try {
|
||||||
@ -97,7 +92,12 @@ export class IssueProformaUseCase {
|
|||||||
transaction
|
transaction
|
||||||
);
|
);
|
||||||
|
|
||||||
const dto = presenter.toOutput(saveInvoiceResult.data);
|
const invoice = saveInvoiceResult.data;
|
||||||
|
const dto = {
|
||||||
|
proforma_id: proforma.id.toString(),
|
||||||
|
invoice_id: invoice.id.toString(),
|
||||||
|
customer_id: invoice.customerId.toString(),
|
||||||
|
};
|
||||||
return Result.ok(dto);
|
return Result.ok(dto);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
return Result.fail(error as Error);
|
return Result.fail(error as Error);
|
||||||
|
|||||||
@ -4,12 +4,11 @@ import { Result } from "@repo/rdx-utils";
|
|||||||
|
|
||||||
import type { CustomerInvoiceApplicationService } from "../../../services/customer-invoice-application.service";
|
import type { CustomerInvoiceApplicationService } from "../../../services/customer-invoice-application.service";
|
||||||
|
|
||||||
import type { ProformaReportPDFPresenter } from "./reporter";
|
|
||||||
|
|
||||||
type ReportProformaUseCaseInput = {
|
type ReportProformaUseCaseInput = {
|
||||||
companyId: UniqueID;
|
companyId: UniqueID;
|
||||||
companySlug: string;
|
companySlug: string;
|
||||||
proforma_id: string;
|
proforma_id: string;
|
||||||
|
format: "pdf" | "html";
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ReportProformaUseCase {
|
export class ReportProformaUseCase {
|
||||||
@ -20,7 +19,7 @@ export class ReportProformaUseCase {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
public async execute(params: ReportProformaUseCaseInput) {
|
public async execute(params: ReportProformaUseCaseInput) {
|
||||||
const { proforma_id, companySlug, companyId } = params;
|
const { proforma_id, companySlug, companyId, format } = params;
|
||||||
|
|
||||||
const idOrError = UniqueID.create(proforma_id);
|
const idOrError = UniqueID.create(proforma_id);
|
||||||
|
|
||||||
@ -29,11 +28,11 @@ export class ReportProformaUseCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const proformaId = idOrError.data;
|
const proformaId = idOrError.data;
|
||||||
const pdfPresenter = this.presenterRegistry.getPresenter({
|
const reportPresenter = this.presenterRegistry.getPresenter({
|
||||||
resource: "proforma",
|
resource: "proforma",
|
||||||
projection: "REPORT",
|
projection: "REPORT",
|
||||||
format: "PDF",
|
format,
|
||||||
}) as ProformaReportPDFPresenter;
|
});
|
||||||
|
|
||||||
return this.transactionManager.complete(async (transaction) => {
|
return this.transactionManager.complete(async (transaction) => {
|
||||||
try {
|
try {
|
||||||
@ -47,9 +46,17 @@ export class ReportProformaUseCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const proforma = proformaOrError.data;
|
const proforma = proformaOrError.data;
|
||||||
const pdfData = await pdfPresenter.toOutput(proforma, { companySlug });
|
const reportData = await reportPresenter.toOutput(proforma, { companySlug });
|
||||||
|
|
||||||
|
if (format === "html") {
|
||||||
|
return Result.ok({
|
||||||
|
data: String(reportData),
|
||||||
|
filename: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return Result.ok({
|
return Result.ok({
|
||||||
data: pdfData,
|
data: reportData as Buffer<ArrayBuffer>,
|
||||||
filename: `proforma-${proforma.invoiceNumber}.pdf`,
|
filename: `proforma-${proforma.invoiceNumber}.pdf`,
|
||||||
});
|
});
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { Presenter } from "@erp/core/api";
|
import { Presenter } from "@erp/core/api";
|
||||||
import puppeteer from "puppeteer";
|
import puppeteer from "puppeteer";
|
||||||
import report from "puppeteer-report";
|
|
||||||
|
|
||||||
import type { CustomerInvoice } from "../../../../../domain";
|
import type { CustomerInvoice } from "../../../../../domain";
|
||||||
|
|
||||||
import type { ProformaReportHTMLPresenter } from "./proforma.report.html";
|
import type { ProformaReportHTMLPresenter } from "./proforma.report.html";
|
||||||
|
|
||||||
// https://plnkr.co/edit/lWk6Yd?preview
|
// https://plnkr.co/edit/lWk6Yd?preview
|
||||||
|
// https://latenode.com/es/blog/web-automation-scraping/puppeteer-fundamentals-setup/complete-guide-to-pdf-generation-with-puppeteer-from-simple-documents-to-complex-reports
|
||||||
|
|
||||||
export class ProformaReportPDFPresenter extends Presenter<
|
export class ProformaReportPDFPresenter extends Presenter<
|
||||||
CustomerInvoice,
|
CustomerInvoice,
|
||||||
@ -25,38 +25,37 @@ export class ProformaReportPDFPresenter extends Presenter<
|
|||||||
|
|
||||||
const htmlData = htmlPresenter.toOutput(proforma, params);
|
const htmlData = htmlPresenter.toOutput(proforma, params);
|
||||||
|
|
||||||
// Generar el PDF con Puppeteer
|
|
||||||
// Generar el PDF con Puppeteer
|
// Generar el PDF con Puppeteer
|
||||||
const browser = await puppeteer.launch({
|
const browser = await puppeteer.launch({
|
||||||
headless: "new",
|
//headless: "new",
|
||||||
executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
|
executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
|
||||||
args: ["--font-render-hinting=medium"],
|
args: ["--font-render-hinting=medium"],
|
||||||
});
|
});
|
||||||
|
|
||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
page.setDefaultNavigationTimeout(60000);
|
//page.setDefaultNavigationTimeout(60000);
|
||||||
page.setDefaultTimeout(60000);
|
//page.setDefaultTimeout(60000);
|
||||||
|
|
||||||
await page.setContent(htmlData, {
|
await page.setContent(htmlData, {
|
||||||
waitUntil: "networkidle0",
|
waitUntil: "networkidle2",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Espera extra opcional si hay imágenes base64 muy grandes
|
// Espera extra opcional si hay imágenes base64 muy grandes
|
||||||
await page.waitForNetworkIdle({ idleTime: 200, timeout: 5000 });
|
await page.waitForNetworkIdle({ idleTime: 200, timeout: 5000 });
|
||||||
|
|
||||||
const reportPDF = await report.pdfPage(page, {
|
const reportPDF = await page.pdf({
|
||||||
format: "A4",
|
format: "A4",
|
||||||
margin: {
|
margin: {
|
||||||
bottom: "10mm",
|
bottom: 0,
|
||||||
left: "10mm",
|
left: 0,
|
||||||
right: "10mm",
|
right: 0,
|
||||||
top: "10mm",
|
top: 0,
|
||||||
},
|
},
|
||||||
landscape: false,
|
landscape: false,
|
||||||
preferCSSPageSize: true,
|
preferCSSPageSize: true,
|
||||||
omitBackground: false,
|
omitBackground: false,
|
||||||
printBackground: true,
|
printBackground: true,
|
||||||
displayHeaderFooter: false,
|
displayHeaderFooter: true,
|
||||||
headerTemplate: "<div />",
|
headerTemplate: "<div />",
|
||||||
footerTemplate:
|
footerTemplate:
|
||||||
'<div style="text-align: center;width: 297mm;font-size: 10px;">Página <span style="margin-right: 1cm"><span class="pageNumber"></span> de <span class="totalPages"></span></span></span></div>',
|
'<div style="text-align: center;width: 297mm;font-size: 10px;">Página <span style="margin-right: 1cm"><span class="pageNumber"></span> de <span class="totalPages"></span></span></span></div>',
|
||||||
|
|||||||
@ -20,11 +20,13 @@ export class ReportIssuedInvoiceController extends ExpressController {
|
|||||||
|
|
||||||
const { companySlug } = this.getUser();
|
const { companySlug } = this.getUser();
|
||||||
const { invoice_id } = this.req.params;
|
const { invoice_id } = this.req.params;
|
||||||
|
const { format } = this.req.query as { format: "pdf" | "html" };
|
||||||
|
|
||||||
const result = await this.useCase.execute({ invoice_id, companyId, companySlug });
|
const result = await this.useCase.execute({ invoice_id, companyId, companySlug, format });
|
||||||
|
|
||||||
return result.match(
|
return result.match(
|
||||||
({ data, filename }) => this.downloadPDF(data, filename),
|
({ data, filename }) =>
|
||||||
|
filename ? this.downloadPDF(data, filename) : this.downloadHTML(data as string),
|
||||||
(err) => this.handleError(err)
|
(err) => this.handleError(err)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,11 +20,13 @@ export class ReportProformaController extends ExpressController {
|
|||||||
|
|
||||||
const { companySlug } = this.getUser();
|
const { companySlug } = this.getUser();
|
||||||
const { proforma_id } = this.req.params;
|
const { proforma_id } = this.req.params;
|
||||||
|
const { format } = this.req.query as { format: "pdf" | "html" };
|
||||||
|
|
||||||
const result = await this.useCase.execute({ proforma_id, companyId, companySlug });
|
const result = await this.useCase.execute({ proforma_id, companyId, companySlug, format });
|
||||||
|
|
||||||
return result.match(
|
return result.match(
|
||||||
({ data, filename }) => this.downloadPDF(data, filename),
|
({ data, filename }) =>
|
||||||
|
filename ? this.downloadPDF(data, filename) : this.downloadHTML(data as string),
|
||||||
(err) => this.handleError(err)
|
(err) => this.handleError(err)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,8 @@ import type { Sequelize } from "sequelize";
|
|||||||
import {
|
import {
|
||||||
GetIssueInvoiceByIdRequestSchema,
|
GetIssueInvoiceByIdRequestSchema,
|
||||||
ListIssuedInvoicesRequestSchema,
|
ListIssuedInvoicesRequestSchema,
|
||||||
ReportIssueInvoiceByIdRequestSchema,
|
ReportIssueInvoiceByIdParamsRequestSchema,
|
||||||
|
ReportIssueInvoiceByIdQueryRequestSchema,
|
||||||
} from "../../../common/dto";
|
} from "../../../common/dto";
|
||||||
import { buildIssuedInvoicesDependencies } from "../issued-invoices-dependencies";
|
import { buildIssuedInvoicesDependencies } from "../issued-invoices-dependencies";
|
||||||
|
|
||||||
@ -71,7 +72,8 @@ export const issuedInvoicesRouter = (params: ModuleParams) => {
|
|||||||
router.get(
|
router.get(
|
||||||
"/:invoice_id/report",
|
"/:invoice_id/report",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
validateRequest(ReportIssueInvoiceByIdRequestSchema, "params"),
|
validateRequest(ReportIssueInvoiceByIdParamsRequestSchema, "params"),
|
||||||
|
validateRequest(ReportIssueInvoiceByIdQueryRequestSchema, "query"),
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
const useCase = deps.useCases.report_issued_invoice();
|
const useCase = deps.useCases.report_issued_invoice();
|
||||||
const controller = new ReportIssuedInvoiceController(useCase);
|
const controller = new ReportIssuedInvoiceController(useCase);
|
||||||
|
|||||||
@ -12,7 +12,8 @@ import {
|
|||||||
GetProformaByIdRequestSchema,
|
GetProformaByIdRequestSchema,
|
||||||
IssueProformaByIdParamsRequestSchema,
|
IssueProformaByIdParamsRequestSchema,
|
||||||
ListProformasRequestSchema,
|
ListProformasRequestSchema,
|
||||||
ReportProformaByIdRequestSchema,
|
ReportProformaByIdParamsRequestSchema,
|
||||||
|
ReportProformaByIdQueryRequestSchema,
|
||||||
UpdateProformaByIdParamsRequestSchema,
|
UpdateProformaByIdParamsRequestSchema,
|
||||||
UpdateProformaByIdRequestSchema,
|
UpdateProformaByIdRequestSchema,
|
||||||
} from "../../../common";
|
} from "../../../common";
|
||||||
@ -121,7 +122,8 @@ export const proformasRouter = (params: ModuleParams) => {
|
|||||||
router.get(
|
router.get(
|
||||||
"/:proforma_id/report",
|
"/:proforma_id/report",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
validateRequest(ReportProformaByIdRequestSchema, "params"),
|
validateRequest(ReportProformaByIdParamsRequestSchema, "params"),
|
||||||
|
validateRequest(ReportProformaByIdQueryRequestSchema, "query"),
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
const useCase = deps.useCases.report_proforma();
|
const useCase = deps.useCases.report_proforma();
|
||||||
const controller = new ReportProformaController(useCase);
|
const controller = new ReportProformaController(useCase);
|
||||||
|
|||||||
@ -78,8 +78,6 @@ export class CustomerInvoiceRepository
|
|||||||
});
|
});
|
||||||
const dtoResult = mapper.mapToPersistence(invoice);
|
const dtoResult = mapper.mapToPersistence(invoice);
|
||||||
|
|
||||||
console.log("DTO to persist:", dtoResult);
|
|
||||||
|
|
||||||
if (dtoResult.isFailure) {
|
if (dtoResult.isFailure) {
|
||||||
return Result.fail(dtoResult.error);
|
return Result.fail(dtoResult.error);
|
||||||
}
|
}
|
||||||
@ -358,6 +356,12 @@ export class CustomerInvoiceRepository
|
|||||||
],
|
],
|
||||||
include: [
|
include: [
|
||||||
...normalizedInclude,
|
...normalizedInclude,
|
||||||
|
{
|
||||||
|
model: VerifactuRecordModel,
|
||||||
|
as: "verifactu",
|
||||||
|
required: false,
|
||||||
|
attributes: ["id", "estado", "url", "uuid"],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
model: CustomerModel,
|
model: CustomerModel,
|
||||||
as: "current_customer",
|
as: "current_customer",
|
||||||
|
|||||||
@ -1,7 +1,17 @@
|
|||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const ReportIssueInvoiceByIdRequestSchema = z.object({
|
export const ReportIssueInvoiceByIdParamsRequestSchema = z.object({
|
||||||
invoice_id: z.string(),
|
invoice_id: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ReportIssueInvoiceByIdRequestDTO = z.infer<typeof ReportIssueInvoiceByIdRequestSchema>;
|
export type ReportIssueInvoiceByIdParamsRequestDTO = z.infer<
|
||||||
|
typeof ReportIssueInvoiceByIdParamsRequestSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const ReportIssueInvoiceByIdQueryRequestSchema = z.object({
|
||||||
|
format: z.enum(["pdf", "html"]).default("pdf"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type ReportIssueInvoiceByIdQueryRequestDTO = z.infer<
|
||||||
|
typeof ReportIssueInvoiceByIdQueryRequestSchema
|
||||||
|
>;
|
||||||
|
|||||||
@ -1,7 +1,16 @@
|
|||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const ReportProformaByIdRequestSchema = z.object({
|
export const ReportProformaByIdParamsRequestSchema = z.object({
|
||||||
proforma_id: z.string(),
|
proforma_id: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ReportProformaByIdRequestDTO = z.infer<typeof ReportProformaByIdRequestSchema>;
|
export type ReportProformaByIdParamsRequestDTO = z.infer<
|
||||||
|
typeof ReportProformaByIdParamsRequestSchema
|
||||||
|
>;
|
||||||
|
export const ReportProformaByIdQueryRequestSchema = z.object({
|
||||||
|
format: z.enum(["pdf", "html"]).default("pdf"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type ReportProformaByIdQueryRequestDTO = z.infer<
|
||||||
|
typeof ReportProformaByIdQueryRequestSchema
|
||||||
|
>;
|
||||||
|
|||||||
@ -3,13 +3,7 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<style type="text/css">
|
<style>{{ asset 'tailwind.css' }}</style>
|
||||||
{
|
|
||||||
{
|
|
||||||
asset 'tailwind.css.b64'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<title>Factura</title>
|
<title>Factura</title>
|
||||||
<style>
|
<style>
|
||||||
/* ---------------------------- */
|
/* ---------------------------- */
|
||||||
|
|||||||
@ -3,15 +3,9 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<style type="text/css">
|
<style>{{ asset 'tailwind.css' }}</style>
|
||||||
{
|
|
||||||
{
|
|
||||||
asset 'tailwind.css.b64'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<title>Factura proforma</title>
|
<title>Factura proforma</title>
|
||||||
<style>
|
<style type="text/css">
|
||||||
/* ---------------------------- */
|
/* ---------------------------- */
|
||||||
/* ESTRUCTURA CABECERA */
|
/* ESTRUCTURA CABECERA */
|
||||||
/* ---------------------------- */
|
/* ---------------------------- */
|
||||||
@ -43,7 +37,7 @@
|
|||||||
|
|
||||||
.company-text {
|
.company-text {
|
||||||
font-size: 7pt;
|
font-size: 7pt;
|
||||||
line-height: 1.2;
|
line-height: 1;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -511,11 +511,8 @@ importers:
|
|||||||
specifier: ^2.3.4
|
specifier: ^2.3.4
|
||||||
version: 2.3.4
|
version: 2.3.4
|
||||||
puppeteer:
|
puppeteer:
|
||||||
specifier: ^24.20.0
|
specifier: ^24.30.0
|
||||||
version: 24.28.0(typescript@5.9.3)
|
version: 24.30.0(typescript@5.9.3)
|
||||||
puppeteer-report:
|
|
||||||
specifier: ^3.2.0
|
|
||||||
version: 3.2.0
|
|
||||||
react-hook-form:
|
react-hook-form:
|
||||||
specifier: ^7.58.1
|
specifier: ^7.58.1
|
||||||
version: 7.66.0(react@19.2.0)
|
version: 7.66.0(react@19.2.0)
|
||||||
@ -1768,12 +1765,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
|
resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
|
|
||||||
'@pdf-lib/standard-fonts@1.0.0':
|
|
||||||
resolution: {integrity: sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==}
|
|
||||||
|
|
||||||
'@pdf-lib/upng@1.0.1':
|
|
||||||
resolution: {integrity: sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==}
|
|
||||||
|
|
||||||
'@pkgjs/parseargs@0.11.0':
|
'@pkgjs/parseargs@0.11.0':
|
||||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
@ -3167,8 +3158,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
|
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
chromium-bidi@10.5.1:
|
chromium-bidi@11.0.0:
|
||||||
resolution: {integrity: sha512-rlj6OyhKhVTnk4aENcUme3Jl9h+cq4oXu4AzBcvr8RMmT6BR4a3zSNT9dbIfXr9/BS6ibzRyDhowuw4n2GgzsQ==}
|
resolution: {integrity: sha512-cM3DI+OOb89T3wO8cpPSro80Q9eKYJ7hGVXoGS3GkDPxnYSqiv+6xwpIf6XERyJ9Tdsl09hmNmY94BkgZdVekw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
devtools-protocol: '*'
|
devtools-protocol: '*'
|
||||||
|
|
||||||
@ -4810,9 +4801,6 @@ packages:
|
|||||||
package-json-from-dist@1.0.1:
|
package-json-from-dist@1.0.1:
|
||||||
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
|
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
|
||||||
|
|
||||||
pako@1.0.11:
|
|
||||||
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
|
|
||||||
|
|
||||||
param-case@2.1.1:
|
param-case@2.1.1:
|
||||||
resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==}
|
resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==}
|
||||||
|
|
||||||
@ -4910,9 +4898,6 @@ packages:
|
|||||||
pause@0.0.1:
|
pause@0.0.1:
|
||||||
resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==}
|
resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==}
|
||||||
|
|
||||||
pdf-lib@1.17.1:
|
|
||||||
resolution: {integrity: sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==}
|
|
||||||
|
|
||||||
pend@1.2.0:
|
pend@1.2.0:
|
||||||
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
|
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
|
||||||
|
|
||||||
@ -5060,15 +5045,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
puppeteer-core@24.28.0:
|
puppeteer-core@24.30.0:
|
||||||
resolution: {integrity: sha512-QpAqaYgeZHF5/xAZ4jAOzsU+l0Ed4EJoWkRdfw8rNqmSN7itcdYeCJaSPQ0s5Pyn/eGNC4xNevxbgY+5bzNllw==}
|
resolution: {integrity: sha512-2S3Smy0t0W4wJnNvDe7W0bE7wDmZjfZ3ljfMgJd6hn2Hq/f0jgN+x9PULZo2U3fu5UUIJ+JP8cNUGllu8P91Pg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
puppeteer-report@3.2.0:
|
puppeteer@24.30.0:
|
||||||
resolution: {integrity: sha512-c2JNsAeLa4Ik4FVPdTRyWYfXO61uSI0ZJ9BNPuf84sImTmwBT4CY/Vn88iQ7q7LQstJStkPuNWAzJgNEmBONmQ==}
|
resolution: {integrity: sha512-A5OtCi9WpiXBQgJ2vQiZHSyrAzQmO/WDsvghqlN4kgw21PhxA5knHUaUQq/N3EMt8CcvSS0RM+kmYLJmedR3TQ==}
|
||||||
|
|
||||||
puppeteer@24.28.0:
|
|
||||||
resolution: {integrity: sha512-KLRGFNCGmXJpocEBbEIoHJB0vNRZLQNBjl5ExXEv0z7MIU+qqVEQcfWTyat+qxPDk/wZvSf+b30cQqAfWxX0zg==}
|
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
@ -6815,14 +6797,6 @@ snapshots:
|
|||||||
'@parcel/watcher-win32-ia32': 2.5.1
|
'@parcel/watcher-win32-ia32': 2.5.1
|
||||||
'@parcel/watcher-win32-x64': 2.5.1
|
'@parcel/watcher-win32-x64': 2.5.1
|
||||||
|
|
||||||
'@pdf-lib/standard-fonts@1.0.0':
|
|
||||||
dependencies:
|
|
||||||
pako: 1.0.11
|
|
||||||
|
|
||||||
'@pdf-lib/upng@1.0.1':
|
|
||||||
dependencies:
|
|
||||||
pako: 1.0.11
|
|
||||||
|
|
||||||
'@pkgjs/parseargs@0.11.0':
|
'@pkgjs/parseargs@0.11.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@ -8284,7 +8258,7 @@ snapshots:
|
|||||||
|
|
||||||
chownr@2.0.0: {}
|
chownr@2.0.0: {}
|
||||||
|
|
||||||
chromium-bidi@10.5.1(devtools-protocol@0.0.1521046):
|
chromium-bidi@11.0.0(devtools-protocol@0.0.1521046):
|
||||||
dependencies:
|
dependencies:
|
||||||
devtools-protocol: 0.0.1521046
|
devtools-protocol: 0.0.1521046
|
||||||
mitt: 3.0.1
|
mitt: 3.0.1
|
||||||
@ -9963,8 +9937,6 @@ snapshots:
|
|||||||
|
|
||||||
package-json-from-dist@1.0.1: {}
|
package-json-from-dist@1.0.1: {}
|
||||||
|
|
||||||
pako@1.0.11: {}
|
|
||||||
|
|
||||||
param-case@2.1.1:
|
param-case@2.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
no-case: 2.3.2
|
no-case: 2.3.2
|
||||||
@ -10060,13 +10032,6 @@ snapshots:
|
|||||||
|
|
||||||
pause@0.0.1: {}
|
pause@0.0.1: {}
|
||||||
|
|
||||||
pdf-lib@1.17.1:
|
|
||||||
dependencies:
|
|
||||||
'@pdf-lib/standard-fonts': 1.0.0
|
|
||||||
'@pdf-lib/upng': 1.0.1
|
|
||||||
pako: 1.0.11
|
|
||||||
tslib: 1.14.1
|
|
||||||
|
|
||||||
pend@1.2.0: {}
|
pend@1.2.0: {}
|
||||||
|
|
||||||
pg-connection-string@2.9.1: {}
|
pg-connection-string@2.9.1: {}
|
||||||
@ -10215,10 +10180,10 @@ snapshots:
|
|||||||
|
|
||||||
punycode@2.3.1: {}
|
punycode@2.3.1: {}
|
||||||
|
|
||||||
puppeteer-core@24.28.0:
|
puppeteer-core@24.30.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@puppeteer/browsers': 2.10.13
|
'@puppeteer/browsers': 2.10.13
|
||||||
chromium-bidi: 10.5.1(devtools-protocol@0.0.1521046)
|
chromium-bidi: 11.0.0(devtools-protocol@0.0.1521046)
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
devtools-protocol: 0.0.1521046
|
devtools-protocol: 0.0.1521046
|
||||||
typed-query-selector: 2.12.0
|
typed-query-selector: 2.12.0
|
||||||
@ -10232,17 +10197,13 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
|
||||||
puppeteer-report@3.2.0:
|
puppeteer@24.30.0(typescript@5.9.3):
|
||||||
dependencies:
|
|
||||||
pdf-lib: 1.17.1
|
|
||||||
|
|
||||||
puppeteer@24.28.0(typescript@5.9.3):
|
|
||||||
dependencies:
|
dependencies:
|
||||||
'@puppeteer/browsers': 2.10.13
|
'@puppeteer/browsers': 2.10.13
|
||||||
chromium-bidi: 10.5.1(devtools-protocol@0.0.1521046)
|
chromium-bidi: 11.0.0(devtools-protocol@0.0.1521046)
|
||||||
cosmiconfig: 9.0.0(typescript@5.9.3)
|
cosmiconfig: 9.0.0(typescript@5.9.3)
|
||||||
devtools-protocol: 0.0.1521046
|
devtools-protocol: 0.0.1521046
|
||||||
puppeteer-core: 24.28.0
|
puppeteer-core: 24.30.0
|
||||||
typed-query-selector: 2.12.0
|
typed-query-selector: 2.12.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bare-abort-controller
|
- bare-abort-controller
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user