.
This commit is contained in:
parent
1beaa05fa4
commit
c91455ffc2
1
.vscode/launch.json
vendored
1
.vscode/launch.json
vendored
@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"version": "0.6.2",
|
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "WEB: Vite (Chrome)",
|
"name": "WEB: Vite (Chrome)",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/factuges-server",
|
"name": "@erp/factuges-server",
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsup src/index.ts --config tsup.config.ts",
|
"build": "tsup src/index.ts --config tsup.config.ts",
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/factuges-web",
|
"name": "@erp/factuges-web",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host --clearScreen false",
|
"dev": "vite --host --clearScreen false",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/auth",
|
"name": "@erp/auth",
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/core",
|
"name": "@erp/core",
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/customer-invoices",
|
"name": "@erp/customer-invoices",
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { DateHelper, MoneyDTOHelper, PercentageDTOHelper } from "@erp/core";
|
import { MoneyDTOHelper, PercentageDTOHelper } from "@erp/core";
|
||||||
import type { ISnapshotBuilder, ISnapshotBuilderParams } from "@erp/core/api";
|
import type { ISnapshotBuilder, ISnapshotBuilderParams } from "@erp/core/api";
|
||||||
|
import { DateHelper } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import type { IIssuedInvoiceFullSnapshot } from "../full";
|
import type { IIssuedInvoiceFullSnapshot } from "../full";
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { NumberHelper } from "@erp/core";
|
|
||||||
import { DiscountPercentage } from "@erp/core/api";
|
import { DiscountPercentage } from "@erp/core/api";
|
||||||
import {
|
import {
|
||||||
CurrencyCode,
|
CurrencyCode,
|
||||||
@ -12,7 +11,7 @@ import {
|
|||||||
extractOrPushError,
|
extractOrPushError,
|
||||||
maybeFromNullableResult,
|
maybeFromNullableResult,
|
||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Maybe, NumberHelper, Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import type { CreateProformaRequestDTO } from "../../../../common";
|
import type { CreateProformaRequestDTO } from "../../../../common";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { NumberHelper } from "@erp/core";
|
|
||||||
import { DiscountPercentage } from "@erp/core/api";
|
import { DiscountPercentage } from "@erp/core/api";
|
||||||
import {
|
import {
|
||||||
CurrencyCode,
|
CurrencyCode,
|
||||||
@ -12,7 +11,7 @@ import {
|
|||||||
extractOrPushError,
|
extractOrPushError,
|
||||||
maybeFromNullableResult,
|
maybeFromNullableResult,
|
||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import { Result, isNullishOrEmpty, toPatchField } from "@repo/rdx-utils";
|
import { NumberHelper, Result, isNullishOrEmpty, toPatchField } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import type { UpdateProformaByIdRequestDTO } from "../../../../common/dto";
|
import type { UpdateProformaByIdRequestDTO } from "../../../../common/dto";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import type { UniqueID } from "@repo/rdx-ddd";
|
|||||||
import type { Result } from "@repo/rdx-utils";
|
import type { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import type { Proforma } from "../../../domain/proformas";
|
import type { Proforma } from "../../../domain/proformas";
|
||||||
import type { IProformaFullSnapshot } from "../snapshot-builders";
|
import type { ProformaFullSnapshot } from "../snapshot-builders";
|
||||||
|
|
||||||
import type { IProformaCreatorParams } from "./proforma-creator";
|
import type { IProformaCreatorParams } from "./proforma-creator";
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ export interface IProformaPublicServices {
|
|||||||
getProformaSnapshotById: (
|
getProformaSnapshotById: (
|
||||||
id: UniqueID,
|
id: UniqueID,
|
||||||
context: IProformaServicesContext
|
context: IProformaServicesContext
|
||||||
) => Promise<Result<IProformaFullSnapshot, Error>>;
|
) => Promise<Result<ProformaFullSnapshot, Error>>;
|
||||||
|
|
||||||
generateProformaReport: (id: unknown, options: unknown, context: unknown) => null;
|
generateProformaReport: (id: unknown, options: unknown, context: unknown) => null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,8 +8,10 @@ import type { IProformaItemsFullSnapshotBuilder } from "./proforma-items-full-sn
|
|||||||
import type { IProformaRecipientFullSnapshotBuilder } from "./proforma-recipient-full-snapshot-builder";
|
import type { IProformaRecipientFullSnapshotBuilder } from "./proforma-recipient-full-snapshot-builder";
|
||||||
import type { IProformaTaxesFullSnapshotBuilder } from "./proforma-taxes-full-snapshot-builder";
|
import type { IProformaTaxesFullSnapshotBuilder } from "./proforma-taxes-full-snapshot-builder";
|
||||||
|
|
||||||
|
export type ProformaFullSnapshot = GetProformaByIdResponseDTO;
|
||||||
|
|
||||||
export interface IProformaFullSnapshotBuilder
|
export interface IProformaFullSnapshotBuilder
|
||||||
extends ISnapshotBuilder<Proforma, GetProformaByIdResponseDTO> {}
|
extends ISnapshotBuilder<Proforma, ProformaFullSnapshot> {}
|
||||||
|
|
||||||
export class ProformaFullSnapshotBuilder implements IProformaFullSnapshotBuilder {
|
export class ProformaFullSnapshotBuilder implements IProformaFullSnapshotBuilder {
|
||||||
constructor(
|
constructor(
|
||||||
@ -19,7 +21,7 @@ export class ProformaFullSnapshotBuilder implements IProformaFullSnapshotBuilder
|
|||||||
//private readonly paymentMethodBuilder: IProformaPaymentMethodFullSnapshotBuilder
|
//private readonly paymentMethodBuilder: IProformaPaymentMethodFullSnapshotBuilder
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
toOutput(proforma: Proforma): GetProformaByIdResponseDTO {
|
toOutput(proforma: Proforma): ProformaFullSnapshot {
|
||||||
const items = this.itemsBuilder.toOutput(proforma.items);
|
const items = this.itemsBuilder.toOutput(proforma.items);
|
||||||
const recipient = this.recipientBuilder.toOutput(proforma);
|
const recipient = this.recipientBuilder.toOutput(proforma);
|
||||||
const taxes = this.taxesBuilder.toOutput(proforma.taxes());
|
const taxes = this.taxesBuilder.toOutput(proforma.taxes());
|
||||||
@ -37,7 +39,7 @@ export class ProformaFullSnapshotBuilder implements IProformaFullSnapshotBuilder
|
|||||||
company_id: proforma.companyId.toString(),
|
company_id: proforma.companyId.toString(),
|
||||||
|
|
||||||
invoice_number: proforma.invoiceNumber.toString(),
|
invoice_number: proforma.invoiceNumber.toString(),
|
||||||
status: proforma.status.toPrimitive() as GetProformaByIdResponseDTO["status"],
|
status: proforma.status.toPrimitive() as ProformaFullSnapshot["status"],
|
||||||
series: maybeToNullable(proforma.series, (value) => value.toString()),
|
series: maybeToNullable(proforma.series, (value) => value.toString()),
|
||||||
|
|
||||||
invoice_date: proforma.invoiceDate.toDateString(),
|
invoice_date: proforma.invoiceDate.toDateString(),
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
import { MoneyDTOHelper, PercentageDTOHelper, QuantityDTOHelper } from "@erp/core";
|
import { MoneyDTOHelper, PercentageDTOHelper, QuantityDTOHelper } from "@erp/core";
|
||||||
import type { ISnapshotBuilder, ISnapshotBuilderParams } from "@erp/core/api";
|
import type { ISnapshotBuilder, ISnapshotBuilderParams } from "@erp/core/api";
|
||||||
|
|
||||||
import type { IProformaFullSnapshot } from "../full";
|
import type { ProformaFullSnapshot } from "../full";
|
||||||
|
|
||||||
import type { ProformaReportItemSnapshot } from "./proforma-report-item-snapshot.interface";
|
import type { ProformaReportItemSnapshot } from "./proforma-report-item-snapshot.interface";
|
||||||
|
|
||||||
export interface IProformaItemReportSnapshotBuilder
|
export interface IProformaItemReportSnapshotBuilder
|
||||||
extends ISnapshotBuilder<IProformaFullSnapshot["items"], ProformaReportItemSnapshot[]> {}
|
extends ISnapshotBuilder<ProformaFullSnapshot["items"], ProformaReportItemSnapshot[]> {}
|
||||||
|
|
||||||
export class ProformaItemReportSnapshotBuilder implements IProformaItemReportSnapshotBuilder {
|
export class ProformaItemReportSnapshotBuilder implements IProformaItemReportSnapshotBuilder {
|
||||||
toOutput(
|
toOutput(
|
||||||
items: IProformaFullSnapshot["items"],
|
items: ProformaFullSnapshot["items"],
|
||||||
params?: ISnapshotBuilderParams
|
params?: ISnapshotBuilderParams
|
||||||
): ProformaReportItemSnapshot[] {
|
): ProformaReportItemSnapshot[] {
|
||||||
const locale = params?.locale as string;
|
const locale = params?.locale as string;
|
||||||
|
|||||||
@ -1,29 +1,30 @@
|
|||||||
import { DateHelper, MoneyDTOHelper, PercentageDTOHelper } from "@erp/core";
|
import { MoneyDTOHelper, PercentageDTOHelper } from "@erp/core";
|
||||||
import type { ISnapshotBuilder, ISnapshotBuilderParams } from "@erp/core/api";
|
import type { ISnapshotBuilder, ISnapshotBuilderParams } from "@erp/core/api";
|
||||||
|
import { DateHelper } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import type { IProformaFullSnapshot } from "../full";
|
import type { ProformaFullSnapshot } from "../full";
|
||||||
|
|
||||||
import type { ProformaReportItemSnapshot } from "./proforma-report-item-snapshot.interface";
|
import type { ProformaReportItemSnapshot } from "./proforma-report-item-snapshot.interface";
|
||||||
import type { ProformaReportSnapshot } from "./proforma-report-snapshot.interface";
|
import type { ProformaReportSnapshot } from "./proforma-report-snapshot.interface";
|
||||||
import type { ProformaReportTaxSnapshot } from "./proforma-report-tax-snapshot.interface";
|
import type { ProformaReportTaxSnapshot } from "./proforma-report-tax-snapshot.interface";
|
||||||
|
|
||||||
export interface IProformaReportSnapshotBuilder
|
export interface IProformaReportSnapshotBuilder
|
||||||
extends ISnapshotBuilder<IProformaFullSnapshot, ProformaReportSnapshot> {}
|
extends ISnapshotBuilder<ProformaFullSnapshot, ProformaReportSnapshot> {}
|
||||||
|
|
||||||
export class ProformaReportSnapshotBuilder implements IProformaReportSnapshotBuilder {
|
export class ProformaReportSnapshotBuilder implements IProformaReportSnapshotBuilder {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly itemsBuilder: ISnapshotBuilder<
|
private readonly itemsBuilder: ISnapshotBuilder<
|
||||||
IProformaFullSnapshot["items"],
|
ProformaFullSnapshot["items"],
|
||||||
ProformaReportItemSnapshot[]
|
ProformaReportItemSnapshot[]
|
||||||
>,
|
>,
|
||||||
private readonly taxesBuilder: ISnapshotBuilder<
|
private readonly taxesBuilder: ISnapshotBuilder<
|
||||||
IProformaFullSnapshot["taxes"],
|
ProformaFullSnapshot["taxes"],
|
||||||
ProformaReportTaxSnapshot[]
|
ProformaReportTaxSnapshot[]
|
||||||
>
|
>
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
toOutput(
|
toOutput(
|
||||||
snapshot: IProformaFullSnapshot,
|
snapshot: ProformaFullSnapshot,
|
||||||
params?: ISnapshotBuilderParams
|
params?: ISnapshotBuilderParams
|
||||||
): ProformaReportSnapshot {
|
): ProformaReportSnapshot {
|
||||||
const locale = params?.locale as string;
|
const locale = params?.locale as string;
|
||||||
@ -90,7 +91,7 @@ export class ProformaReportSnapshotBuilder implements IProformaReportSnapshotBui
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private formatAddress(recipient: IProformaFullSnapshot["recipient"]): string {
|
private formatAddress(recipient: ProformaFullSnapshot["recipient"]): string {
|
||||||
const lines: string[] = [];
|
const lines: string[] = [];
|
||||||
|
|
||||||
if (recipient.street) lines.push(recipient.street);
|
if (recipient.street) lines.push(recipient.street);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { DateHelper, MoneyDTOHelper, PercentageDTOHelper } from "@erp/core";
|
import { MoneyDTOHelper, PercentageDTOHelper } from "@erp/core";
|
||||||
import { Presenter } from "@erp/core/api";
|
import { Presenter } from "@erp/core/api";
|
||||||
|
import { DateHelper } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import type { GetIssuedInvoiceByIdResponseDTO } from "../../../../../common/dto";
|
import type { GetIssuedInvoiceByIdResponseDTO } from "../../../../../common/dto";
|
||||||
|
|
||||||
|
|||||||
@ -47,28 +47,26 @@ export class ProformaItemsTotalsCalculator {
|
|||||||
const amounts = item.totals();
|
const amounts = item.totals();
|
||||||
|
|
||||||
// Subtotales
|
// Subtotales
|
||||||
subtotalAmount = subtotalAmount.add(amounts.subtotalAmount.roundUsingScale(2));
|
subtotalAmount = subtotalAmount.add(amounts.subtotalAmount);
|
||||||
|
|
||||||
// Descuentos
|
// Descuentos
|
||||||
itemDiscountAmount = itemDiscountAmount.add(amounts.itemDiscountAmount.roundUsingScale(2));
|
itemDiscountAmount = itemDiscountAmount.add(amounts.itemDiscountAmount);
|
||||||
globalDiscountAmount = globalDiscountAmount.add(
|
globalDiscountAmount = globalDiscountAmount.add(amounts.globalDiscountAmount);
|
||||||
amounts.globalDiscountAmount.roundUsingScale(2)
|
totalDiscountAmount = totalDiscountAmount.add(amounts.totalDiscountAmount);
|
||||||
);
|
|
||||||
totalDiscountAmount = totalDiscountAmount.add(amounts.totalDiscountAmount.roundUsingScale(2));
|
|
||||||
|
|
||||||
// Base imponible
|
// Base imponible
|
||||||
taxableAmount = taxableAmount.add(amounts.taxableAmount.roundUsingScale(2));
|
taxableAmount = taxableAmount.add(amounts.taxableAmount);
|
||||||
|
|
||||||
// Impuestos individuales
|
// Impuestos individuales
|
||||||
ivaAmount = ivaAmount.add(amounts.ivaAmount.roundUsingScale(2));
|
ivaAmount = ivaAmount.add(amounts.ivaAmount);
|
||||||
recAmount = recAmount.add(amounts.recAmount.roundUsingScale(2));
|
recAmount = recAmount.add(amounts.recAmount);
|
||||||
retentionAmount = retentionAmount.add(amounts.retentionAmount.roundUsingScale(2));
|
retentionAmount = retentionAmount.add(amounts.retentionAmount);
|
||||||
|
|
||||||
// Total impuestos del ítem
|
// Total impuestos del ítem
|
||||||
taxesAmount = taxesAmount.add(amounts.taxesAmount.roundUsingScale(2));
|
taxesAmount = taxesAmount.add(amounts.taxesAmount);
|
||||||
|
|
||||||
// Total final del ítem
|
// Total final del ítem
|
||||||
totalAmount = totalAmount.add(amounts.totalAmount.roundUsingScale(2));
|
totalAmount = totalAmount.add(amounts.totalAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -37,6 +37,7 @@ export class ProformaTaxesCalculator {
|
|||||||
const ivaAmount = this.toInvoiceAmount(g.ivaAmount);
|
const ivaAmount = this.toInvoiceAmount(g.ivaAmount);
|
||||||
const recAmount = this.toInvoiceAmount(g.recAmount);
|
const recAmount = this.toInvoiceAmount(g.recAmount);
|
||||||
const retentionAmount = this.toInvoiceAmount(g.retentionAmount);
|
const retentionAmount = this.toInvoiceAmount(g.retentionAmount);
|
||||||
|
//const taxesAmount = this.toInvoiceAmount(g.taxesAmount);
|
||||||
|
|
||||||
const taxesAmount = ivaAmount.add(recAmount).subtract(retentionAmount);
|
const taxesAmount = ivaAmount.add(recAmount).subtract(retentionAmount);
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import type { Transaction } from "sequelize";
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
type IProformaCreatorParams,
|
type IProformaCreatorParams,
|
||||||
type IProformaFullSnapshot,
|
type ProformaFullSnapshot,
|
||||||
buildProformaCreator,
|
buildProformaCreator,
|
||||||
buildProformaFinder,
|
buildProformaFinder,
|
||||||
buildProformaSnapshotBuilders,
|
buildProformaSnapshotBuilders,
|
||||||
@ -36,7 +36,7 @@ export type ProformaPublicServices = {
|
|||||||
getProformaSnapshotById: (
|
getProformaSnapshotById: (
|
||||||
id: UniqueID,
|
id: UniqueID,
|
||||||
context: ProformaServicesContext
|
context: ProformaServicesContext
|
||||||
) => Promise<Result<IProformaFullSnapshot, Error>>;
|
) => Promise<Result<ProformaFullSnapshot, Error>>;
|
||||||
|
|
||||||
createProforma: (
|
createProforma: (
|
||||||
id: UniqueID,
|
id: UniqueID,
|
||||||
|
|||||||
@ -0,0 +1,193 @@
|
|||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
Checkbox,
|
||||||
|
Field,
|
||||||
|
FieldContent,
|
||||||
|
FieldDescription,
|
||||||
|
FieldGroup,
|
||||||
|
FieldLabel,
|
||||||
|
FieldSet,
|
||||||
|
Input,
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@repo/shadcn-ui/components";
|
||||||
|
import { FileText } from "lucide-react";
|
||||||
|
|
||||||
|
export const ProformaTaxesCard = () => {
|
||||||
|
return (
|
||||||
|
<Card className="shadow">
|
||||||
|
<CardHeader className="px-6 pb-7 pt-3">
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<div className="flex size-12 shrink-0 items-center justify-center rounded-lg bg-primary-50 text-primary-600">
|
||||||
|
<FileText aria-hidden="true" className="size-5" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-1">
|
||||||
|
<CardTitle className="text-base font-semibold">Impuestos</CardTitle>
|
||||||
|
<p className="text-sm text-muted-foreground">Configuración fiscal de la proforma</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
|
||||||
|
<CardContent>
|
||||||
|
<FieldSet>
|
||||||
|
<FieldGroup className="gap-5">
|
||||||
|
<SectionIntro
|
||||||
|
description="Selecciona el régimen fiscal que aplica a esta proforma."
|
||||||
|
title="1. Régimen fiscal"
|
||||||
|
variant="primary"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel htmlFor="tax-regime">Régimen fiscal</FieldLabel>
|
||||||
|
|
||||||
|
<Select defaultValue="general">
|
||||||
|
<SelectTrigger className="h-9 bg-muted/40 font-medium" id="tax-regime">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="general">01: Operación de régimen general.</SelectItem>
|
||||||
|
<SelectItem value="exempt">Operación exenta de IVA.</SelectItem>
|
||||||
|
<SelectItem value="reverse-charge">Inversión del sujeto pasivo.</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</FieldSet>
|
||||||
|
</CardContent>
|
||||||
|
|
||||||
|
<section className="border-y bg-primary-50 px-6 py-4">
|
||||||
|
<FieldSet>
|
||||||
|
<FieldGroup className="gap-5">
|
||||||
|
<SectionIntro
|
||||||
|
description="Puedes usar un tipo único para todas las líneas de detalle o permitir que cada línea tenga su propio IVA."
|
||||||
|
title="Configuración de IVA"
|
||||||
|
variant="primary"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Field className="items-center gap-3" orientation="horizontal">
|
||||||
|
<Checkbox defaultChecked id="same-vat" />
|
||||||
|
|
||||||
|
<FieldLabel
|
||||||
|
className="cursor-pointer font-medium text-primary-700"
|
||||||
|
htmlFor="same-vat"
|
||||||
|
>
|
||||||
|
Aplicar el mismo IVA a todas las líneas de la proforma
|
||||||
|
</FieldLabel>
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field className="w-32">
|
||||||
|
<FieldLabel className="text-primary-700" htmlFor="default-vat">
|
||||||
|
IVA por defecto
|
||||||
|
</FieldLabel>
|
||||||
|
|
||||||
|
<Select defaultValue="21">
|
||||||
|
<SelectTrigger
|
||||||
|
className="h-9 bg-background/75 font-medium text-primary-700"
|
||||||
|
id="default-vat"
|
||||||
|
>
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="21">21%</SelectItem>
|
||||||
|
<SelectItem value="10">10%</SelectItem>
|
||||||
|
<SelectItem value="4">4%</SelectItem>
|
||||||
|
<SelectItem value="0">0%</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</FieldSet>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<CardContent className="px-6 py-6">
|
||||||
|
<FieldSet>
|
||||||
|
<FieldGroup className="gap-5">
|
||||||
|
<SectionIntro
|
||||||
|
description="Activa opciones fiscales adicionales como recargo de equivalencia o retenciones (IRPF), según el tipo de cliente y normativa aplicable."
|
||||||
|
title="Impuestos adicionales"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
<CheckboxField id="equivalence-surcharge" label="Recargo de equivalencia" />
|
||||||
|
|
||||||
|
<CheckboxField id="withholding" label="Incluir retención/IRPF" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Field className="w-36">
|
||||||
|
<FieldLabel htmlFor="withholding-rate">Retención</FieldLabel>
|
||||||
|
|
||||||
|
<div className="relative">
|
||||||
|
<Input
|
||||||
|
className="h-9 bg-muted/40 pr-8 text-right font-medium tabular-nums"
|
||||||
|
defaultValue="0"
|
||||||
|
id="withholding-rate"
|
||||||
|
inputMode="decimal"
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-sm text-foreground"
|
||||||
|
>
|
||||||
|
%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</FieldSet>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface SectionIntroProps {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
variant?: "default" | "primary";
|
||||||
|
}
|
||||||
|
|
||||||
|
const SectionIntro = ({ title, description, variant = "default" }: SectionIntroProps) => {
|
||||||
|
return (
|
||||||
|
<Field>
|
||||||
|
<FieldContent className="space-y-2">
|
||||||
|
<h3
|
||||||
|
className={
|
||||||
|
variant === "primary"
|
||||||
|
? "text-base font-semibold text-primary-700"
|
||||||
|
: "text-base font-semibold text-foreground"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<FieldDescription className="max-w-md text-sm leading-6">{description}</FieldDescription>
|
||||||
|
</FieldContent>
|
||||||
|
</Field>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface CheckboxFieldProps {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CheckboxField = ({ id, label }: CheckboxFieldProps) => {
|
||||||
|
return (
|
||||||
|
<Field className="items-center gap-3" orientation="horizontal">
|
||||||
|
<Checkbox id={id} />
|
||||||
|
|
||||||
|
<FieldLabel className="cursor-pointer font-medium" htmlFor={id}>
|
||||||
|
{label}
|
||||||
|
</FieldLabel>
|
||||||
|
</Field>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -14,6 +14,7 @@ import type {
|
|||||||
} from "../../controllers";
|
} from "../../controllers";
|
||||||
import { ProformaTotalsSummary } from "../blocks";
|
import { ProformaTotalsSummary } from "../blocks";
|
||||||
|
|
||||||
|
import { ProformaTaxesCard } from "./proforma-taxes-card";
|
||||||
import { ProformaUpdateHeaderEditor } from "./proforma-update-header-editor";
|
import { ProformaUpdateHeaderEditor } from "./proforma-update-header-editor";
|
||||||
import { ProformaUpdateItemsEditor } from "./proforma-update-items-editor";
|
import { ProformaUpdateItemsEditor } from "./proforma-update-items-editor";
|
||||||
import { ProformaUpdateTaxEditor } from "./proforma-update-tax-editor";
|
import { ProformaUpdateTaxEditor } from "./proforma-update-tax-editor";
|
||||||
@ -74,6 +75,10 @@ export const ProformaUpdateEditorForm = ({
|
|||||||
|
|
||||||
<ProformaUpdateItemsEditor disabled={isSubmitting} itemsCtrl={itemsCtrl} taxCtrl={taxCtrl} />
|
<ProformaUpdateItemsEditor disabled={isSubmitting} itemsCtrl={itemsCtrl} taxCtrl={taxCtrl} />
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1">
|
||||||
|
<ProformaTaxesCard />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-12">
|
<div className="grid grid-cols-1 gap-4 md:grid-cols-12">
|
||||||
<ProformaUpdateTaxEditor className="md:col-span-6" taxCtrl={taxCtrl} />
|
<ProformaUpdateTaxEditor className="md:col-span-6" taxCtrl={taxCtrl} />
|
||||||
<ProformaTotalsSummary
|
<ProformaTotalsSummary
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/customers",
|
"name": "@erp/customers",
|
||||||
"description": "Customers",
|
"description": "Customers",
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/factuges",
|
"name": "@erp/factuges",
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/supplier-invoices",
|
"name": "@erp/supplier-invoices",
|
||||||
"description": "Supplier invoices",
|
"description": "Supplier invoices",
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/suppliers",
|
"name": "@erp/suppliers",
|
||||||
"description": "Suppliers",
|
"description": "Suppliers",
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "uecko-erp-2025",
|
"name": "uecko-erp-2025",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"apps/*",
|
"apps/*",
|
||||||
"modules/*",
|
"modules/*",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/rdx-criteria",
|
"name": "@repo/rdx-criteria",
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/rdx-ddd",
|
"name": "@repo/rdx-ddd",
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/rdx-logger",
|
"name": "@repo/rdx-logger",
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/rdx-ui",
|
"name": "@repo/rdx-ui",
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
|
CardDescription,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
FieldDescription,
|
CardTitle,
|
||||||
FieldLegend,
|
|
||||||
FieldSet,
|
|
||||||
} from "@repo/shadcn-ui/components";
|
} from "@repo/shadcn-ui/components";
|
||||||
import { cn } from "@repo/shadcn-ui/lib/utils";
|
import { cn } from "@repo/shadcn-ui/lib/utils";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
@ -34,32 +33,30 @@ export const FormSectionCard = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={className}>
|
<Card className={className}>
|
||||||
<FieldSet disabled={disabled}>
|
<CardHeader className={headerClassName}>
|
||||||
<CardHeader className={headerClassName}>
|
<div className="flex items-start gap-3">
|
||||||
<div className="flex items-start gap-3">
|
{icon ? (
|
||||||
{icon ? (
|
<div
|
||||||
<div
|
className={cn(
|
||||||
className={cn(
|
"flex size-12 shrink-0 items-center justify-center rounded-md",
|
||||||
"flex size-12 shrink-0 items-center justify-center rounded-md",
|
disabled ? "bg-muted text-muted-foreground" : "bg-primary/10 text-primary"
|
||||||
disabled ? "bg-muted text-muted-foreground" : "bg-primary/10 text-primary"
|
)}
|
||||||
)}
|
>
|
||||||
>
|
{" "}
|
||||||
{" "}
|
{icon}{" "}
|
||||||
{icon}{" "}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<div className="space-y-1">
|
|
||||||
{title ? <FieldLegend className="font-semibold">{title}</FieldLegend> : null}
|
|
||||||
{description ? (
|
|
||||||
<FieldDescription className="font-medium">{description}</FieldDescription>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
) : null}
|
||||||
</CardHeader>
|
|
||||||
|
|
||||||
<CardContent className={contentClassName}>{children}</CardContent>
|
<div className="space-y-1">
|
||||||
</FieldSet>
|
{title ? <CardTitle className="font-semibold">{title}</CardTitle> : null}
|
||||||
|
{description ? (
|
||||||
|
<CardDescription className="font-medium">{description}</CardDescription>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
|
||||||
|
<CardContent className={contentClassName}>{children}</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/rdx-utils",
|
"name": "@repo/rdx-utils",
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -13,14 +13,27 @@
|
|||||||
@source "../**/*.{ts,tsx}";
|
@source "../**/*.{ts,tsx}";
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
--primary: #0b7ad0;
|
||||||
|
--primary-foreground: #ffffff;
|
||||||
|
|
||||||
|
--primary-50: #eef8ff;
|
||||||
|
--primary-100: #d9efff;
|
||||||
|
--primary-200: #bce4ff;
|
||||||
|
--primary-300: #8ed3ff;
|
||||||
|
--primary-400: #58b8f4;
|
||||||
|
--primary-500: #2e9be4;
|
||||||
|
--primary-600: #0b7ad0;
|
||||||
|
--primary-700: #0862a8;
|
||||||
|
--primary-800: #0a528a;
|
||||||
|
--primary-900: #0d456f;
|
||||||
|
--primary-950: #092b49;
|
||||||
|
|
||||||
--background: #ffffff;
|
--background: #ffffff;
|
||||||
--foreground: #0a0a0a;
|
--foreground: #0a0a0a;
|
||||||
--card: #ffffff;
|
--card: #ffffff;
|
||||||
--card-foreground: #0a0a0a;
|
--card-foreground: #0a0a0a;
|
||||||
--popover: #ffffff;
|
--popover: #ffffff;
|
||||||
--popover-foreground: #0a0a0a;
|
--popover-foreground: #0a0a0a;
|
||||||
--primary: #0b7ad0;
|
|
||||||
--primary-foreground: #ffffff;
|
|
||||||
--secondary: #e4e8ef;
|
--secondary: #e4e8ef;
|
||||||
--secondary-foreground: #6a8aa3;
|
--secondary-foreground: #6a8aa3;
|
||||||
--muted: #f5f5f5;
|
--muted: #f5f5f5;
|
||||||
@ -64,14 +77,27 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
|
--primary: #125cff;
|
||||||
|
--primary-foreground: #eff6ff;
|
||||||
|
|
||||||
|
--primary-50: #eff6ff;
|
||||||
|
--primary-100: #dbeafe;
|
||||||
|
--primary-200: #bfdbfe;
|
||||||
|
--primary-300: #93c5fd;
|
||||||
|
--primary-400: #60a5fa;
|
||||||
|
--primary-500: #3b82f6;
|
||||||
|
--primary-600: #125cff;
|
||||||
|
--primary-700: #1d4ed8;
|
||||||
|
--primary-800: #1e40af;
|
||||||
|
--primary-900: #1e3a8a;
|
||||||
|
--primary-950: #172554;
|
||||||
|
|
||||||
--background: #0a0a0a;
|
--background: #0a0a0a;
|
||||||
--foreground: #fafafa;
|
--foreground: #fafafa;
|
||||||
--card: #171717;
|
--card: #171717;
|
||||||
--card-foreground: #fafafa;
|
--card-foreground: #fafafa;
|
||||||
--popover: #171717;
|
--popover: #171717;
|
||||||
--popover-foreground: #fafafa;
|
--popover-foreground: #fafafa;
|
||||||
--primary: #125cff;
|
|
||||||
--primary-foreground: #eff6ff;
|
|
||||||
--secondary: #26262b;
|
--secondary: #26262b;
|
||||||
--secondary-foreground: #fafafa;
|
--secondary-foreground: #fafafa;
|
||||||
--muted: #262626;
|
--muted: #262626;
|
||||||
@ -107,6 +133,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
|
--color-primary-50: var(--primary-50);
|
||||||
|
--color-primary-100: var(--primary-100);
|
||||||
|
--color-primary-200: var(--primary-200);
|
||||||
|
--color-primary-300: var(--primary-300);
|
||||||
|
--color-primary-400: var(--primary-400);
|
||||||
|
--color-primary-500: var(--primary-500);
|
||||||
|
--color-primary-600: var(--primary-600);
|
||||||
|
--color-primary-700: var(--primary-700);
|
||||||
|
--color-primary-800: var(--primary-800);
|
||||||
|
--color-primary-900: var(--primary-900);
|
||||||
|
--color-primary-950: var(--primary-950);
|
||||||
|
|
||||||
--color-background: var(--background);
|
--color-background: var(--background);
|
||||||
--color-foreground: var(--foreground);
|
--color-foreground: var(--foreground);
|
||||||
--color-card: var(--card);
|
--color-card: var(--card);
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user