diff --git a/modules/customer-invoices/package.json b/modules/customer-invoices/package.json index 5dde8b1a..89d70693 100644 --- a/modules/customer-invoices/package.json +++ b/modules/customer-invoices/package.json @@ -39,6 +39,7 @@ "@erp/core": "workspace:*", "@erp/customers": "workspace:*", "@hookform/resolvers": "^5.2.2", + "@lglab/react-qr-code": "^1.4.10", "@repo/i18next": "workspace:*", "@repo/rdx-criteria": "workspace:*", "@repo/rdx-ddd": "workspace:*", diff --git a/modules/customer-invoices/src/api/application/issued-invoices/services/proforma-to-issued-invoice-props-converter.ts b/modules/customer-invoices/src/api/application/issued-invoices/services/proforma-to-issued-invoice-props-converter.ts index df190866..e229e5d2 100644 --- a/modules/customer-invoices/src/api/application/issued-invoices/services/proforma-to-issued-invoice-props-converter.ts +++ b/modules/customer-invoices/src/api/application/issued-invoices/services/proforma-to-issued-invoice-props-converter.ts @@ -1,3 +1,4 @@ +import { UtcDate } from "@repo/rdx-ddd"; import { Maybe, Result } from "@repo/rdx-utils"; import { @@ -102,7 +103,7 @@ export class ProformaToIssuedInvoiceConverter implements IProformaToIssuedInvoic invoiceNumber: proforma.invoiceNumber, - invoiceDate: proforma.invoiceDate, + invoiceDate: UtcDate.today(), // La fecha de la factura es la fecha de emisión, no la de la proforma operationDate: proforma.operationDate, description: proforma.description, diff --git a/modules/customer-invoices/src/api/domain/proformas/value-objects/proforma-item-taxes.vo.ts b/modules/customer-invoices/src/api/domain/proformas/value-objects/proforma-item-taxes.vo.ts index a93c189a..6ca37a01 100644 --- a/modules/customer-invoices/src/api/domain/proformas/value-objects/proforma-item-taxes.vo.ts +++ b/modules/customer-invoices/src/api/domain/proformas/value-objects/proforma-item-taxes.vo.ts @@ -1,6 +1,6 @@ import type { Tax } from "@erp/core/api"; import { ValueObject } from "@repo/rdx-ddd"; -import { type Maybe, Result } from "@repo/rdx-utils"; +import { Maybe, Result } from "@repo/rdx-utils"; import { ItemAmount } from "../../common/value-objects"; @@ -32,6 +32,19 @@ export class ProformaItemTaxes return Result.ok(new ProformaItemTaxes(props)); } + /** + * Crea una instancia "vacía" (sin impuestos) + * - Evita duplicación de lógica de construcción + * - Centraliza el concepto de "sin impuestos" + */ + static empty(): ProformaItemTaxes { + return new ProformaItemTaxes({ + iva: Maybe.none(), + rec: Maybe.none(), + retention: Maybe.none(), + }); + } + toKey(): string { const ivaCode = this.props.iva.match( (iva) => iva.code, diff --git a/modules/customer-invoices/src/api/infrastructure/issued-invoices/persistence/sequelize/repositories/issued-invoice.repository.ts b/modules/customer-invoices/src/api/infrastructure/issued-invoices/persistence/sequelize/repositories/issued-invoice.repository.ts index f7d223bf..38e029d2 100644 --- a/modules/customer-invoices/src/api/infrastructure/issued-invoices/persistence/sequelize/repositories/issued-invoice.repository.ts +++ b/modules/customer-invoices/src/api/infrastructure/issued-invoices/persistence/sequelize/repositories/issued-invoice.repository.ts @@ -283,12 +283,6 @@ export class IssuedInvoiceRepository }, ]; - // Reemplazar findAndCountAll por findAll + count (más control y mejor rendimiento) - /*const { rows, count } = await CustomerInvoiceModel.findAndCountAll({ - ...query, - transaction, - });*/ - const [rows, count] = await Promise.all([ CustomerInvoiceModel.findAll({ ...query, diff --git a/modules/customer-invoices/src/api/infrastructure/proformas/express/proformas.routes.ts b/modules/customer-invoices/src/api/infrastructure/proformas/express/proformas.routes.ts index 8a3fab22..935b278b 100644 --- a/modules/customer-invoices/src/api/infrastructure/proformas/express/proformas.routes.ts +++ b/modules/customer-invoices/src/api/infrastructure/proformas/express/proformas.routes.ts @@ -13,7 +13,7 @@ import { import { CreateProformaRequestSchema, GetProformaByIdRequestSchema, - IssueProformaByIdResponseSchema, + IssueProformaByIdParamsRequestSchema, ListProformasRequestSchema, ReportProformaByIdParamsRequestSchema, ReportProformaByIdQueryRequestSchema, @@ -150,7 +150,7 @@ export const proformasRouter = (params: StartParams) => { "/:proforma_id/issue", //checkTabContext, - validateRequest(IssueProformaByIdResponseSchema, "params"), + validateRequest(IssueProformaByIdParamsRequestSchema, "params"), (req: Request, res: Response, next: NextFunction) => { const useCase = deps.useCases.issueProforma(publicServices); diff --git a/modules/customer-invoices/src/web/issued-invoices/list/controllers/use-issued-invoice-list.controller.ts b/modules/customer-invoices/src/web/issued-invoices/list/controllers/use-issued-invoice-list.controller.ts index 8bf3cb38..e864f6f9 100644 --- a/modules/customer-invoices/src/web/issued-invoices/list/controllers/use-issued-invoice-list.controller.ts +++ b/modules/customer-invoices/src/web/issued-invoices/list/controllers/use-issued-invoice-list.controller.ts @@ -3,12 +3,12 @@ import { useMemo, useState } from "react"; import type { IssuedInvoiceList, - IssuedInvoiceStatus, ListIssuedInvoicesByCriteriaParams, + VerifactuRecordStatus, } from "../../shared"; import { useIssuedInvoiceListQuery } from "../../shared/"; -type IssuedInvoiceListStatusFilter = "all" | IssuedInvoiceStatus; +type VerifactuRecordListStatusFilter = "all" | VerifactuRecordStatus; const EMPTY_ISSUED_INVOICES_LIST: IssuedInvoiceList = { items: [], @@ -22,7 +22,8 @@ export const useIssuedInvoiceListController = () => { const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(5); const [search, setSearch] = useState(""); - const [statusFilter, setStatusFilter] = useState("all"); + const [verifactuStatusFilter, setVerifactuStatusFilter] = + useState("all"); const debouncedSearch = useDebounce(search, 300); @@ -33,17 +34,20 @@ export const useIssuedInvoiceListController = () => { pageSize, order: "desc", orderBy: "invoice_date", - filters: status === "all" ? [] : [{ field: "status", operator: "eq", value: status }], + filters: + verifactuStatusFilter === "all" + ? [] + : [{ field: "verifactu.status", operator: "eq", value: verifactuStatusFilter }], }), - [debouncedSearch, pageIndex, pageSize, status] + [debouncedSearch, pageIndex, pageSize, verifactuStatusFilter] ); const query = useIssuedInvoiceListQuery({ criteria }); const setStatusFilterValue = (value: string) => { - const nextValue = (value || "all") as IssuedInvoiceListStatusFilter; + const nextValue = (value || "all") as VerifactuRecordListStatusFilter; - setStatusFilter((prev) => { + setVerifactuStatusFilter((prev) => { if (prev === nextValue) return prev; // Sólo si la búsqueda realmente cambia, @@ -95,7 +99,7 @@ export const useIssuedInvoiceListController = () => { search, setSearchValue, - statusFilter, + statusFilter: verifactuStatusFilter, setStatusFilter: setStatusFilterValue, }; }; diff --git a/modules/customer-invoices/src/web/issued-invoices/list/ui/blocks/issued-invoices-grid/use-issued-invoices-grid-columns.tsx b/modules/customer-invoices/src/web/issued-invoices/list/ui/blocks/issued-invoices-grid/use-issued-invoices-grid-columns.tsx index cc59f306..cf1ebd32 100644 --- a/modules/customer-invoices/src/web/issued-invoices/list/ui/blocks/issued-invoices-grid/use-issued-invoices-grid-columns.tsx +++ b/modules/customer-invoices/src/web/issued-invoices/list/ui/blocks/issued-invoices-grid/use-issued-invoices-grid-columns.tsx @@ -1,4 +1,5 @@ import { formatDate } from "@erp/core/client"; +import { ReactQRCode } from "@lglab/react-qr-code"; import { DataTableColumnHeader } from "@repo/rdx-ui/components"; import { Button, @@ -16,7 +17,6 @@ import { import type { ColumnDef } from "@tanstack/react-table"; import { DownloadIcon, FileDownIcon, MailIcon, MoreVerticalIcon, QrCodeIcon } from "lucide-react"; import * as React from "react"; -import QrCode from "react-qr-code"; import { useTranslation } from "../../../../../i18n"; import type { IssuedInvoiceListRow } from "../../../../shared"; @@ -115,7 +115,17 @@ export function useIssuedInvoicesGridColumns( } /> - +
+ +
)} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 11c9a9c0..9c622242 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -489,6 +489,9 @@ importers: '@hookform/resolvers': specifier: ^5.2.2 version: 5.2.2(react-hook-form@7.72.1(react@19.2.5)) + '@lglab/react-qr-code': + specifier: ^1.4.10 + version: 1.4.10(react@19.2.5) '@repo/i18next': specifier: workspace:* version: link:../../packages/i18n @@ -2226,6 +2229,11 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@lglab/react-qr-code@1.4.10': + resolution: {integrity: sha512-B+VOFfvnx+NqVaJqDbh1glHEU/rJR/3XtINcvM3qC9DW292GbaLNoa2OvRlXHYUQdsWcdzNzOcPzT39P1O8uJg==} + peerDependencies: + react: ^18 || ^19 + '@modelcontextprotocol/sdk@1.29.0': resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} engines: {node: '>=18'} @@ -8015,6 +8023,10 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@lglab/react-qr-code@1.4.10(react@19.2.5)': + dependencies: + react: 19.2.5 + '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': dependencies: '@hono/node-server': 1.19.13(hono@4.12.12)