v0.10.2
This commit is contained in:
parent
10a5c25fc1
commit
ddf68c32c1
3
.gitignore
vendored
3
.gitignore
vendored
@ -10,6 +10,3 @@ dist-ssr
|
|||||||
server/dist
|
server/dist
|
||||||
public/dist
|
public/dist
|
||||||
out
|
out
|
||||||
|
|
||||||
apps/**/false/*
|
|
||||||
false
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/factuges-server",
|
"name": "@erp/factuges-server",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"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.10.1",
|
"version": "0.10.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"typecheck": "tsc -p tsconfig.json --noEmit",
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/auth",
|
"name": "@erp/auth",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/catalogs",
|
"name": "@erp/catalogs",
|
||||||
"description": "Catalogs module",
|
"description": "Catalogs module",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/companies",
|
"name": "@erp/companies",
|
||||||
"description": "Companies module",
|
"description": "Companies module",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/core",
|
"name": "@erp/core",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { ArrowLeftIcon } from "lucide-react";
|
|||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
export interface PageFormHeaderProps {
|
export interface PageFormHeaderProps {
|
||||||
title: string;
|
title: string | ReactNode;
|
||||||
|
|
||||||
backLabel: string;
|
backLabel: string;
|
||||||
onBack?: () => void;
|
onBack?: () => void;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/customer-invoices",
|
"name": "@erp/customer-invoices",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import type { UniqueID } from "@repo/rdx-ddd";
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { type Maybe, Result } from "@repo/rdx-utils";
|
import type { Maybe, Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import type { InvoiceNumber, InvoiceSerie } from "../../../domain";
|
import type { InvoiceNumber, InvoiceSerie } from "../../../domain";
|
||||||
|
|
||||||
|
|||||||
@ -4,13 +4,13 @@ import type { DocumentSeriesPublicServicesType } from "@erp/document-series/api"
|
|||||||
import type { UniqueID } from "@repo/rdx-ddd";
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { IInvoiceSeriesNumberAssigner } from "../../../application/invoice-series";
|
||||||
import {
|
import {
|
||||||
type IIssuedInvoiceCreatorParams,
|
type IIssuedInvoiceCreatorParams,
|
||||||
type IIssuedInvoicePublicServices,
|
type IIssuedInvoicePublicServices,
|
||||||
type IIssuedInvoiceServicesContext,
|
type IIssuedInvoiceServicesContext,
|
||||||
buildIssuedInvoiceCreator,
|
buildIssuedInvoiceCreator,
|
||||||
} from "../../../application/issued-invoices";
|
} from "../../../application/issued-invoices";
|
||||||
import type { IInvoiceSeriesNumberAssigner } from "../../../application/invoice-series";
|
|
||||||
import { InvoiceNumber, InvoiceSerie } from "../../../domain";
|
import { InvoiceNumber, InvoiceSerie } from "../../../domain";
|
||||||
|
|
||||||
import { buildV2IssuedInvoicePersistence } from "./issued-invoice-persistence.di";
|
import { buildV2IssuedInvoicePersistence } from "./issued-invoice-persistence.di";
|
||||||
@ -29,11 +29,13 @@ export function buildIssuedInvoicePublicServices(
|
|||||||
// Fase 1C: la emision ya persiste en `issued_invoices` y relaciona Verifactu por `issued_invoice_id`.
|
// Fase 1C: la emision ya persiste en `issued_invoices` y relaciona Verifactu por `issued_invoice_id`.
|
||||||
const persistence = buildV2IssuedInvoicePersistence({ catalogs, database });
|
const persistence = buildV2IssuedInvoicePersistence({ catalogs, database });
|
||||||
const { repository } = persistence;
|
const { repository } = persistence;
|
||||||
|
|
||||||
const invoiceSeriesNumberAssigner: IInvoiceSeriesNumberAssigner = {
|
const invoiceSeriesNumberAssigner: IInvoiceSeriesNumberAssigner = {
|
||||||
assignNextNumber: async ({ companyId, invoiceSeriesCode, transaction }) => {
|
assignNextNumber: async ({ companyId, invoiceSeriesCode, transaction }) => {
|
||||||
const requestedSeriesCode = invoiceSeriesCode
|
const requestedSeriesCode = invoiceSeriesCode.match(
|
||||||
.map((series) => series.toPrimitive())
|
(serie) => serie.toString(),
|
||||||
.unwrapOr(null);
|
() => null
|
||||||
|
);
|
||||||
|
|
||||||
const assignResult = await documentSeriesServices.assignNextNumber({
|
const assignResult = await documentSeriesServices.assignNextNumber({
|
||||||
companyId: companyId.toString(),
|
companyId: companyId.toString(),
|
||||||
@ -56,12 +58,12 @@ export function buildIssuedInvoicePublicServices(
|
|||||||
return Result.fail(assignedSeriesResult.error);
|
return Result.fail(assignedSeriesResult.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.ok({
|
return Result.ok({
|
||||||
invoiceNumber: invoiceNumberResult.data,
|
invoiceNumber: invoiceNumberResult.data,
|
||||||
formattedNumber: assignResult.data.reference,
|
formattedNumber: assignResult.data.reference,
|
||||||
invoiceSeriesId: assignResult.data.series_id,
|
invoiceSeriesId: assignResult.data.series_id,
|
||||||
invoiceSeriesCode: assignedSeriesResult.data,
|
invoiceSeriesCode: assignedSeriesResult.data,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ export const ProformaDetailHeaderMeta = ({ proforma }: ProformaDetailHeaderMetaP
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap items-center gap-x-3 gap-y-2 text-sm text-muted-foreground">
|
<div className="flex flex-wrap items-center gap-x-3 gap-y-2 text-base text-foreground font-semibold">
|
||||||
{items.map((item, index) => (
|
{items.map((item, index) => (
|
||||||
<div className="flex items-center gap-3" key={`${item}-${index}`}>
|
<div className="flex items-center gap-3" key={`${item}-${index}`}>
|
||||||
{index > 0 ? <span className="hidden text-border sm:inline">|</span> : null}
|
{index > 0 ? <span className="hidden text-border sm:inline">|</span> : null}
|
||||||
|
|||||||
@ -68,7 +68,7 @@ export const ProformaDetailPage = () => {
|
|||||||
}
|
}
|
||||||
backLabel="Volver al listado"
|
backLabel="Volver al listado"
|
||||||
onBack={ctrl.navigateBack}
|
onBack={ctrl.navigateBack}
|
||||||
title={`Proforma ${ctrl.proforma.proformaReference}`}
|
title={<>{`Proforma ${ctrl.proforma.proformaReference}`}</>}
|
||||||
>
|
>
|
||||||
<div className="border-b bg-background px-4 py-4 sm:px-6">
|
<div className="border-b bg-background px-4 py-4 sm:px-6">
|
||||||
<div className="flex flex-wrap items-center gap-3">
|
<div className="flex flex-wrap items-center gap-3">
|
||||||
|
|||||||
@ -20,8 +20,8 @@ import {
|
|||||||
import type { ColumnDef } from "@tanstack/react-table";
|
import type { ColumnDef } from "@tanstack/react-table";
|
||||||
import {
|
import {
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
EyeIcon,
|
|
||||||
ExternalLinkIcon,
|
ExternalLinkIcon,
|
||||||
|
EyeIcon,
|
||||||
FileDownIcon,
|
FileDownIcon,
|
||||||
FileTextIcon,
|
FileTextIcon,
|
||||||
FolderArchiveIcon,
|
FolderArchiveIcon,
|
||||||
@ -80,9 +80,7 @@ const stopRowPropagation = (event: React.MouseEvent | React.KeyboardEvent) => {
|
|||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopRowPropagationAndPreventDefault = (
|
const stopRowPropagationAndPreventDefault = (event: React.MouseEvent | React.KeyboardEvent) => {
|
||||||
event: React.MouseEvent | React.KeyboardEvent
|
|
||||||
) => {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
};
|
};
|
||||||
@ -367,12 +365,12 @@ export function useProformasGridColumns(
|
|||||||
key: "edit",
|
key: "edit",
|
||||||
label: t("pages.proformas.list.actions.edit"),
|
label: t("pages.proformas.list.actions.edit"),
|
||||||
icon: PencilIcon,
|
icon: PencilIcon,
|
||||||
disabled: !actionHandlers.onEditClick || !isNormalScope || isIssued,
|
disabled: !(actionHandlers.onEditClick && isNormalScope) || isIssued,
|
||||||
disabledReason: !isNormalScope
|
disabledReason: isNormalScope
|
||||||
? getScopeReason()
|
? isIssued
|
||||||
: isIssued
|
|
||||||
? t("pages.proformas.list.actions.disabled_reasons.edit_issued")
|
? t("pages.proformas.list.actions.disabled_reasons.edit_issued")
|
||||||
: undefined,
|
: undefined
|
||||||
|
: getScopeReason(),
|
||||||
onClick: handleEdit,
|
onClick: handleEdit,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -382,11 +380,11 @@ export function useProformasGridColumns(
|
|||||||
key: "linked-invoice",
|
key: "linked-invoice",
|
||||||
label: t("pages.proformas.list.actions.view_linked_invoice"),
|
label: t("pages.proformas.list.actions.view_linked_invoice"),
|
||||||
icon: ExternalLinkIcon,
|
icon: ExternalLinkIcon,
|
||||||
disabled: !isIssued || !proforma.linkedInvoiceId,
|
disabled: !(isIssued && proforma.linkedInvoiceId),
|
||||||
disabledReason:
|
disabledReason:
|
||||||
!isIssued || !proforma.linkedInvoiceId
|
isIssued && proforma.linkedInvoiceId
|
||||||
? t("pages.proformas.list.actions.disabled_reasons.linked_invoice_unavailable")
|
? undefined
|
||||||
: undefined,
|
: t("pages.proformas.list.actions.disabled_reasons.linked_invoice_unavailable"),
|
||||||
href: proforma.linkedInvoiceId
|
href: proforma.linkedInvoiceId
|
||||||
? `/issed-invoices/${proforma.linkedInvoiceId}`
|
? `/issed-invoices/${proforma.linkedInvoiceId}`
|
||||||
: undefined,
|
: undefined,
|
||||||
@ -396,26 +394,27 @@ export function useProformasGridColumns(
|
|||||||
label: t("pages.proformas.list.actions.change_status"),
|
label: t("pages.proformas.list.actions.change_status"),
|
||||||
icon: RefreshCwIcon,
|
icon: RefreshCwIcon,
|
||||||
disabled:
|
disabled:
|
||||||
!actionHandlers.onChangeStatusClick || !isNormalScope || !nextTransition || isIssued,
|
!(actionHandlers.onChangeStatusClick && isNormalScope && nextTransition) ||
|
||||||
disabledReason: !isNormalScope
|
isIssued,
|
||||||
? getScopeReason()
|
disabledReason: isNormalScope
|
||||||
: isIssued
|
? isIssued
|
||||||
? t("pages.proformas.list.actions.disabled_reasons.status_issued")
|
? t("pages.proformas.list.actions.disabled_reasons.status_issued")
|
||||||
: !nextTransition
|
: nextTransition
|
||||||
? t("proformas.change_proforma_status_dialog.empty_available_statuses")
|
? undefined
|
||||||
: undefined,
|
: t("proformas.change_proforma_status_dialog.empty_available_statuses")
|
||||||
|
: getScopeReason(),
|
||||||
onClick: handleChangeStatus,
|
onClick: handleChangeStatus,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "issue",
|
key: "issue",
|
||||||
label: t("pages.proformas.list.actions.issue"),
|
label: t("pages.proformas.list.actions.issue"),
|
||||||
icon: FileTextIcon,
|
icon: FileTextIcon,
|
||||||
disabled: !actionHandlers.onIssueClick || !isNormalScope || !isApproved || isIssued,
|
disabled: !(actionHandlers.onIssueClick && isNormalScope && isApproved) || isIssued,
|
||||||
disabledReason: !isNormalScope
|
disabledReason: isNormalScope
|
||||||
? getScopeReason()
|
? isApproved
|
||||||
: !isApproved
|
? undefined
|
||||||
? t("proformas.issue_proforma_dialog.not_allowed_description")
|
: t("proformas.issue_proforma_dialog.not_allowed_description")
|
||||||
: undefined,
|
: getScopeReason(),
|
||||||
onClick: handleIssue,
|
onClick: handleIssue,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -432,31 +431,31 @@ export function useProformasGridColumns(
|
|||||||
key: "archive",
|
key: "archive",
|
||||||
label: t("pages.proformas.list.actions.archive"),
|
label: t("pages.proformas.list.actions.archive"),
|
||||||
icon: FolderArchiveIcon,
|
icon: FolderArchiveIcon,
|
||||||
disabled: !actionHandlers.onArchiveClick || !isArchivable,
|
disabled: !(actionHandlers.onArchiveClick && isArchivable),
|
||||||
disabledReason: !actionHandlers.onArchiveClick
|
disabledReason: actionHandlers.onArchiveClick
|
||||||
? undefined
|
? isNormalScope
|
||||||
: !isNormalScope
|
? t("proformas.archive.error_conflict_message")
|
||||||
? getScopeReason()
|
: getScopeReason()
|
||||||
: t("proformas.archive.error_conflict_message"),
|
: undefined,
|
||||||
onClick: handleArchive,
|
onClick: handleArchive,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "unarchive",
|
key: "unarchive",
|
||||||
label: t("pages.proformas.list.actions.unarchive"),
|
label: t("pages.proformas.list.actions.unarchive"),
|
||||||
icon: Undo2Icon,
|
icon: Undo2Icon,
|
||||||
disabled: !actionHandlers.onUnarchiveClick || !isUnarchivable,
|
disabled: !(actionHandlers.onUnarchiveClick && isUnarchivable),
|
||||||
disabledReason: !actionHandlers.onUnarchiveClick
|
disabledReason: actionHandlers.onUnarchiveClick
|
||||||
? undefined
|
? isArchivedScope
|
||||||
: !isArchivedScope
|
? t("proformas.unarchive.error_conflict_message")
|
||||||
? t("pages.proformas.list.actions.disabled_reasons.archived_only")
|
: t("pages.proformas.list.actions.disabled_reasons.archived_only")
|
||||||
: t("proformas.unarchive.error_conflict_message"),
|
: undefined,
|
||||||
onClick: handleUnarchive,
|
onClick: handleUnarchive,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "download-pdf",
|
key: "download-pdf",
|
||||||
label: t("pages.proformas.list.actions.download_pdf"),
|
label: t("pages.proformas.list.actions.download_pdf"),
|
||||||
icon: FileDownIcon,
|
icon: FileDownIcon,
|
||||||
disabled: !actionHandlers.onDownloadPdf || isDeletedScope || isPDFLoading,
|
disabled: Boolean(!actionHandlers.onDownloadPdf || isDeletedScope || isPDFLoading),
|
||||||
disabledReason: isDeletedScope
|
disabledReason: isDeletedScope
|
||||||
? t("pages.proformas.list.actions.disabled_reasons.deleted_scope")
|
? t("pages.proformas.list.actions.disabled_reasons.deleted_scope")
|
||||||
: isPDFLoading
|
: isPDFLoading
|
||||||
@ -473,9 +472,9 @@ export function useProformasGridColumns(
|
|||||||
disabled: !actionHandlers.onDeleteClick || isDeletedScope || !isDraft,
|
disabled: !actionHandlers.onDeleteClick || isDeletedScope || !isDraft,
|
||||||
disabledReason: isDeletedScope
|
disabledReason: isDeletedScope
|
||||||
? t("pages.proformas.list.actions.disabled_reasons.deleted_scope")
|
? t("pages.proformas.list.actions.disabled_reasons.deleted_scope")
|
||||||
: !isDraft
|
: isDraft
|
||||||
? t("proformas.delete_proforma_dialog.error_conflict_message")
|
? undefined
|
||||||
: undefined,
|
: t("proformas.delete_proforma_dialog.error_conflict_message"),
|
||||||
onClick: handleDelete,
|
onClick: handleDelete,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -543,7 +542,9 @@ export function useProformasGridColumns(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip key={action.key}>
|
<Tooltip key={action.key}>
|
||||||
<TooltipTrigger render={action.disabled ? <div className="w-full">{item}</div> : item} />
|
<TooltipTrigger
|
||||||
|
render={action.disabled ? <div className="w-full">{item}</div> : item}
|
||||||
|
/>
|
||||||
<TooltipContent side="left">{action.disabledReason ?? action.label}</TooltipContent>
|
<TooltipContent side="left">{action.disabledReason ?? action.label}</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
@ -574,11 +575,7 @@ export function useProformasGridColumns(
|
|||||||
/>
|
/>
|
||||||
<TooltipContent>{t("common.more_actions")}</TooltipContent>
|
<TooltipContent>{t("common.more_actions")}</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<DropdownMenuContent
|
<DropdownMenuContent align="end" className="w-56" onClick={stopRowPropagation}>
|
||||||
align="end"
|
|
||||||
className="w-56"
|
|
||||||
onClick={stopRowPropagation}
|
|
||||||
>
|
|
||||||
<DropdownMenuGroup>
|
<DropdownMenuGroup>
|
||||||
<DropdownMenuLabel>{t("common.actions")}</DropdownMenuLabel>
|
<DropdownMenuLabel>{t("common.actions")}</DropdownMenuLabel>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { cn } from "@repo/shadcn-ui/lib/utils";
|
|||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
export interface ProformaPageHeaderProps {
|
export interface ProformaPageHeaderProps {
|
||||||
title: string;
|
title: string | ReactNode;
|
||||||
backLabel?: string;
|
backLabel?: string;
|
||||||
onBack?: () => void;
|
onBack?: () => void;
|
||||||
statusLabel?: string;
|
statusLabel?: string;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/customers",
|
"name": "@erp/customers",
|
||||||
"description": "Customers",
|
"description": "Customers",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/document-series",
|
"name": "@erp/document-series",
|
||||||
"description": "Document series module",
|
"description": "Document series module",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/factuges",
|
"name": "@erp/factuges",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@erp/identity",
|
"name": "@erp/identity",
|
||||||
"description": "Identity module",
|
"description": "Identity module",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"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.10.1",
|
"version": "0.10.2",
|
||||||
"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.10.1",
|
"version": "0.10.2",
|
||||||
"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.10.1",
|
"version": "0.10.2",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"apps/*",
|
"apps/*",
|
||||||
"modules/*",
|
"modules/*",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/i18next",
|
"name": "@repo/i18next",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/rdx-criteria",
|
"name": "@repo/rdx-criteria",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,20 +0,0 @@
|
|||||||
import { describe, expect, test } from "vitest";
|
|
||||||
|
|
||||||
import { buildBooleanFullTextQuery } from "../build-boolean-full-text-query";
|
|
||||||
|
|
||||||
describe("buildBooleanFullTextQuery", () => {
|
|
||||||
test.each([
|
|
||||||
["pr", "+pr*"],
|
|
||||||
["pr-", "+pr*"],
|
|
||||||
["-pr", "+pr*"],
|
|
||||||
["cliente prueba", "+cliente* +prueba*"],
|
|
||||||
["cliente-prueba", "+cliente* +prueba*"],
|
|
||||||
["José Pérez", "+José* +Pérez*"],
|
|
||||||
["++ -- **", ""],
|
|
||||||
["", ""],
|
|
||||||
[" ", ""],
|
|
||||||
['+ - > < ( ) ~ * " @', ""],
|
|
||||||
])("normalizes %p into %p", (input, expected) => {
|
|
||||||
expect(buildBooleanFullTextQuery(input)).toBe(expected);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
import { describe, expect, test } from "vitest";
|
|
||||||
import { Op, type Sequelize } from "sequelize";
|
|
||||||
|
|
||||||
import { Criteria } from "../critera";
|
|
||||||
import { CriteriaToSequelizeConverter } from "../criteria-to-sequelize-converter";
|
|
||||||
|
|
||||||
const createDatabaseStub = () =>
|
|
||||||
({
|
|
||||||
escape: (value: string) => `'${value.replaceAll("'", "''")}'`,
|
|
||||||
}) as Sequelize;
|
|
||||||
|
|
||||||
describe("CriteriaToSequelizeConverter quick search", () => {
|
|
||||||
test("builds a full-text filter and score for free text search", () => {
|
|
||||||
const converter = new CriteriaToSequelizeConverter();
|
|
||||||
const criteria = Criteria.fromPrimitives([], "name", "asc", 10, 0, "pr-");
|
|
||||||
|
|
||||||
const options = converter.convert(criteria, {
|
|
||||||
searchableFields: ["name", "trade_name"],
|
|
||||||
sortableFields: ["name"],
|
|
||||||
enableFullText: true,
|
|
||||||
database: createDatabaseStub(),
|
|
||||||
strictMode: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(options.attributes).toEqual({
|
|
||||||
include: [[expect.objectContaining({ val: expect.stringContaining("'+pr*'") }), "score"]],
|
|
||||||
});
|
|
||||||
expect(options.order).toEqual([
|
|
||||||
[expect.objectContaining({ val: "score" }), "DESC"],
|
|
||||||
["name", "ASC"],
|
|
||||||
]);
|
|
||||||
expect(options.where).toEqual({
|
|
||||||
[Op.and]: expect.any(Array),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("omits MATCH, score and score ordering when the normalized search is empty", () => {
|
|
||||||
const converter = new CriteriaToSequelizeConverter();
|
|
||||||
const criteria = Criteria.fromPrimitives([], "name", "asc", 10, 0, "++ -- **");
|
|
||||||
|
|
||||||
const options = converter.convert(criteria, {
|
|
||||||
searchableFields: ["name", "trade_name"],
|
|
||||||
sortableFields: ["name"],
|
|
||||||
enableFullText: true,
|
|
||||||
database: createDatabaseStub(),
|
|
||||||
strictMode: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(options.attributes).toBeUndefined();
|
|
||||||
expect(options.order).toEqual([["name", "ASC"]]);
|
|
||||||
expect(options.where).toBeUndefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { type FindOptions, Op, type OrderItem, Sequelize, type WhereOptions } from "sequelize";
|
import { type FindOptions, Op, type OrderItem, Sequelize, type WhereOptions } from "sequelize";
|
||||||
|
|
||||||
|
import { buildBooleanFullTextQuery } from "./build-boolean-full-text-query";
|
||||||
import type { Criteria } from "./critera.js";
|
import type { Criteria } from "./critera.js";
|
||||||
import type {
|
import type {
|
||||||
ConvertParams,
|
ConvertParams,
|
||||||
@ -7,7 +8,6 @@ import type {
|
|||||||
CriteriaMappings,
|
CriteriaMappings,
|
||||||
ICriteriaToOrmConverter,
|
ICriteriaToOrmConverter,
|
||||||
} from "./types.js";
|
} from "./types.js";
|
||||||
import { buildBooleanFullTextQuery } from "./build-boolean-full-text-query.js";
|
|
||||||
import { appendOrder, normalizeOrder, prependOrder } from "./utils";
|
import { appendOrder, normalizeOrder, prependOrder } from "./utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -256,10 +256,7 @@ export class CriteriaToSequelizeConverter implements ICriteriaToOrmConverter {
|
|||||||
throw new Error(`[CriteriaToSequelizeConverter] Unsupported field mapping: ${String(value)}`);
|
throw new Error(`[CriteriaToSequelizeConverter] Unsupported field mapping: ${String(value)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildNullWhereCondition(
|
private buildNullWhereCondition(mapping: CriteriaFieldMapping, value: unknown): WhereOptions {
|
||||||
mapping: CriteriaFieldMapping,
|
|
||||||
value: unknown
|
|
||||||
): WhereOptions {
|
|
||||||
switch (mapping.type) {
|
switch (mapping.type) {
|
||||||
case "root":
|
case "root":
|
||||||
return {
|
return {
|
||||||
@ -267,11 +264,16 @@ export class CriteriaToSequelizeConverter implements ICriteriaToOrmConverter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
case "association":
|
case "association":
|
||||||
return Sequelize.where(Sequelize.col(`${mapping.association}.${mapping.column}`), value) as
|
return Sequelize.where(
|
||||||
unknown as WhereOptions;
|
Sequelize.col(`${mapping.association}.${mapping.column}`),
|
||||||
|
value
|
||||||
|
) as unknown as WhereOptions;
|
||||||
|
|
||||||
case "literal":
|
case "literal":
|
||||||
return Sequelize.where(Sequelize.literal(mapping.expression), value) as unknown as WhereOptions;
|
return Sequelize.where(
|
||||||
|
Sequelize.literal(mapping.expression),
|
||||||
|
value
|
||||||
|
) as unknown as WhereOptions;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return this.assertNever(mapping);
|
return this.assertNever(mapping);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
export * from "./critera";
|
|
||||||
export * from "./build-boolean-full-text-query";
|
export * from "./build-boolean-full-text-query";
|
||||||
|
export * from "./critera";
|
||||||
export * from "./criteria-from-url-converter";
|
export * from "./criteria-from-url-converter";
|
||||||
export * from "./criteria-to-sequelize-converter";
|
export * from "./criteria-to-sequelize-converter";
|
||||||
export * from "./defaults";
|
export * from "./defaults";
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/rdx-ddd",
|
"name": "@repo/rdx-ddd",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"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.10.1",
|
"version": "0.10.2",
|
||||||
"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.10.1",
|
"version": "0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/rdx-utils",
|
"name": "@repo/rdx-utils",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/shadcn-ui",
|
"name": "@repo/shadcn-ui",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@repo/typescript-config",
|
"name": "@repo/typescript-config",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user