Clientes y facturas de cliente

This commit is contained in:
David Arranz 2025-09-16 19:41:27 +02:00
parent c285c2d897
commit f72273b069
7 changed files with 93 additions and 61 deletions

View File

@ -3,13 +3,13 @@ import { CustomerInvoiceListDTO } from "@erp/customer-invoices/api/infrastructur
import { Criteria } from "@repo/rdx-criteria/server";
import { toEmptyString } from "@repo/rdx-ddd";
import { ArrayElement, Collection } from "@repo/rdx-utils";
import { CustomerInvoiceListResponseDTO } from "../../../../common/dto";
import { ListCustomerInvoicesResponseDTO } from "../../../../common/dto";
export class ListCustomerInvoicesPresenter extends Presenter {
protected _mapInvoice(invoice: CustomerInvoiceListDTO) {
const recipientDTO = invoice.recipient.toObjectString();
const invoiceDTO: ArrayElement<CustomerInvoiceListResponseDTO["items"]> = {
const invoiceDTO: ArrayElement<ListCustomerInvoicesResponseDTO["items"]> = {
id: invoice.id.toString(),
company_id: invoice.companyId.toString(),
customer_id: invoice.customerId.toString(),
@ -48,7 +48,7 @@ export class ListCustomerInvoicesPresenter extends Presenter {
toOutput(params: {
customerInvoices: Collection<CustomerInvoiceListDTO>;
criteria: Criteria;
}): CustomerInvoiceListResponseDTO {
}): ListCustomerInvoicesResponseDTO {
const { customerInvoices, criteria } = params;
const invoices = customerInvoices.map((invoice) => this._mapInvoice(invoice));

View File

@ -3,7 +3,7 @@ import { Criteria } from "@repo/rdx-criteria/server";
import { UniqueID } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils";
import { Transaction } from "sequelize";
import { CustomerInvoiceListResponseDTO } from "../../../common/dto";
import { ListCustomerInvoicesResponseDTO } from "../../../common/dto";
import { CustomerInvoiceService } from "../../domain";
import { ListCustomerInvoicesPresenter } from "../presenters";
@ -21,7 +21,7 @@ export class ListCustomerInvoicesUseCase {
public execute(
params: ListCustomerInvoicesUseCaseInput
): Promise<Result<CustomerInvoiceListResponseDTO, Error>> {
): Promise<Result<ListCustomerInvoicesResponseDTO, Error>> {
const { criteria, companyId } = params;
const presenter = this.presenterRegistry.getPresenter({
resource: "customer-invoice",

View File

@ -101,17 +101,17 @@
<aside class="flex items-start mb-4 w-full">
<!-- Bloque IZQUIERDO: imagen arriba + texto abajo, alineado a la izquierda -->
<div class="flex flex-col items-start text-left">
<div class="w-[70%] flex flex-col items-start text-left">
<img src="https://rodax-software.com/images/logo1.jpg" alt="Logo Rodax" class="block h-14 w-auto mb-1" />
<div class="flex w-full gap-30">
<div class="w-[30%] bg-amber-400 p-3 text-sm leading-tight">
<p><span class="font-semibold">Factura nº:</span> {{reference}}</p>
<p><span class="font-semibold">Fecha:</span> {{date}}</p>
<div class="flex w-full gap-9">
<div class="p-1 ">
<p><span>Factura nº:</span>xxxxxxxx</p>
<p><span>Fecha:</span>12/12/2024</p>
</div>
<div class="w-[70%] bg-amber-700 p-3 text-sm leading-tight text-white">
<div class="p-1">
<h2 class="font-semibold uppercase mb-1">{{customer.name}}</h2>
<p>AAAA</p>
<p>BBBBBB</p>
<p>BBBBBBsdfsfsdf sfsdf sf sdfs fsdfsd fsdf sdfsd fds </p>
<p>CCCCC</p>
<p>DDDDD</p>
</div>

View File

@ -1,7 +1,7 @@
import { MetadataSchema, MoneySchema, createListViewResponseSchema } from "@erp/core";
import * as z from "zod/v4";
export const ListCustomerInvoiceResponseSchema = createListViewResponseSchema(
export const ListCustomerInvoicesResponseSchema = createListViewResponseSchema(
z.object({
id: z.uuid(),
company_id: z.uuid(),
@ -40,4 +40,4 @@ export const ListCustomerInvoiceResponseSchema = createListViewResponseSchema(
})
);
export type CustomerInvoiceListResponseDTO = z.infer<typeof ListCustomerInvoiceResponseSchema>;
export type ListCustomerInvoicesResponseDTO = z.infer<typeof ListCustomerInvoicesResponseSchema>;

View File

@ -1,25 +1,37 @@
import { useState } from "react";
import { AG_GRID_LOCALE_ES } from "@ag-grid-community/locale";
// Grid
import type { ColDef, GridOptions, ValueFormatterParams } from "ag-grid-community";
import { AllCommunityModule, ModuleRegistry } from "ag-grid-community";
ModuleRegistry.registerModules([AllCommunityModule]);
import type {
SizeColumnsToContentStrategy,
SizeColumnsToFitGridStrategy,
SizeColumnsToFitProvidedWidthStrategy,
ValueFormatterParams,
} from "ag-grid-community";
import { AllCommunityModule, ColDef, GridOptions, ModuleRegistry } from "ag-grid-community";
import { useMemo, useState } from "react";
import { MoneyDTO } from "@erp/core";
import { formatDate, formatMoney } from "@erp/core/client";
// Core CSS
import { Button } from "@repo/shadcn-ui/components";
import { AgGridReact } from "ag-grid-react";
import { Link } from "react-router-dom";
import { ChevronRightIcon } from "lucide-react";
import { useNavigate } from "react-router-dom";
import { useCustomerInvoicesQuery } from "../hooks";
import { useTranslation } from "../i18n";
import { CustomerInvoiceStatusBadge } from "./customer-invoice-status-badge";
ModuleRegistry.registerModules([AllCommunityModule]);
// Create new GridExample component
export const CustomerInvoicesListGrid = () => {
const { t } = useTranslation();
const { data, isLoading, isPending, isError, error } = useCustomerInvoicesQuery({
const navigate = useNavigate();
const {
data: customersData,
isLoading: isLoadingCustomerInvoices,
isError: isLoadError,
error: loadError,
} = useCustomerInvoicesQuery({
pagination: {
pageSize: 999,
},
@ -78,31 +90,56 @@ export const CustomerInvoicesListGrid = () => {
},
},
{
field: "id",
headerName: t("pages.list.grid_columns.total_amount"),
colId: "actions",
headerName: t("pages.list.grid_columns.actions", "Actions"),
cellRenderer: (params: ValueFormatterParams) => {
return <Link to={params.value}>Hola</Link>;
const { data } = params;
return (
<Button
variant='secondary'
size='icon'
className='size-8'
onClick={() => {
navigate(`${data.id}/edit`);
}}
>
<ChevronRightIcon />
</Button>
);
},
},
]);
const gridOptions: GridOptions = {
rowModelType: "clientSide",
columnDefs: colDefs,
defaultColDef: {
editable: false,
flex: 1,
minWidth: 100,
filter: true,
sortable: true,
resizable: true,
},
pagination: true,
paginationPageSize: 15,
paginationPageSizeSelector: [10, 15, 20, 30, 50],
localeText: AG_GRID_LOCALE_ES,
rowSelection: { mode: "multiRow" },
};
const autoSizeStrategy = useMemo<
| SizeColumnsToFitGridStrategy
| SizeColumnsToFitProvidedWidthStrategy
| SizeColumnsToContentStrategy
>(() => {
return {
type: "fitGridWidth",
defaultMinWidth: 100,
columnLimits: [{ colId: "actions", minWidth: 75, maxWidth: 75 }],
};
}, []);
const gridOptions: GridOptions = useMemo(
() => ({
columnDefs: colDefs,
autoSizeStrategy: autoSizeStrategy,
defaultColDef: {
editable: false,
flex: 1,
filter: false,
sortable: false,
resizable: true,
},
pagination: true,
paginationPageSize: 10,
paginationPageSizeSelector: [10, 20, 30, 50],
localeText: AG_GRID_LOCALE_ES,
}),
[autoSizeStrategy, colDefs]
);
// Container: Defines the grid's theme & dimensions.
return (
@ -113,7 +150,11 @@ export const CustomerInvoicesListGrid = () => {
width: "100%",
}}
>
<AgGridReact rowData={data?.items ?? []} loading={isLoading || isPending} {...gridOptions} />
<AgGridReact
rowData={customersData?.items ?? []}
loading={isLoadingCustomerInvoices}
{...gridOptions}
/>
</div>
);
};

View File

@ -1,22 +1,22 @@
import { useDataSource, useQueryKey } from "@erp/core/hooks";
import { useQuery } from "@tanstack/react-query";
import { CustomerInvoiceListResponseDTO } from "../../common/dto";
import { ListCustomerInvoicesResponseDTO } from "../../common/dto";
// Obtener todas las facturas
export const useCustomerInvoicesQuery = (params: any) => {
export const useCustomerInvoicesQuery = (params?: any) => {
const dataSource = useDataSource();
const keys = useQueryKey();
return useQuery<CustomerInvoiceListResponseDTO>({
return useQuery<ListCustomerInvoicesResponseDTO>({
queryKey: keys().data().resource("customer-invoices").action("list").params(params).get(),
queryFn: (context) => {
console.log(dataSource.getBaseUrl());
console.log(params);
queryFn: async (context) => {
const { signal } = context;
return dataSource.getList<CustomerInvoiceListResponseDTO>("customer-invoices", {
const invoices = await dataSource.getList("customer-invoices", {
signal,
...params,
});
return invoices as ListCustomerInvoicesResponseDTO;
},
});
};

View File

@ -110,15 +110,6 @@ export const CustomerEditForm = ({ formId, data, onSubmit, isPending }: Customer
)}
/>
<TextField
control={form.control}
name='tin'
required
label={t("form_fields.tin.label")}
placeholder={t("form_fields.tin.placeholder")}
description={t("form_fields.tin.description")}
/>
<TextField
control={form.control}
name='name'