.
This commit is contained in:
parent
54e23899c4
commit
4d76919e44
12
.vscode/extensions.json
vendored
12
.vscode/extensions.json
vendored
@ -1,3 +1,13 @@
|
||||
{
|
||||
"recommendations": ["biomejs.biome", "cweijan.vscode-mysql-client2"]
|
||||
"recommendations": [
|
||||
"biomejs.biome",
|
||||
"cweijan.vscode-mysql-client2",
|
||||
|
||||
"bradlc.vscode-tailwindcss",
|
||||
"ms-vscode.vscode-typescript-next",
|
||||
"yzhang.markdown-all-in-one",
|
||||
"ms-vscode.vscode-json",
|
||||
"formulahendry.auto-rename-tag",
|
||||
"christian-kohler.path-intellisense"
|
||||
]
|
||||
}
|
||||
|
||||
21
.vscode/settings.json
vendored
21
.vscode/settings.json
vendored
@ -20,15 +20,6 @@
|
||||
"strings": "on"
|
||||
},
|
||||
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": "always",
|
||||
"source.fixAll.biome": "always",
|
||||
"source.removeUnusedImports": "always"
|
||||
},
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnPaste": false,
|
||||
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
@ -48,8 +39,16 @@
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
|
||||
"prettier.enable": false,
|
||||
"eslint.enable": false,
|
||||
// Biome
|
||||
"biome.enabled": true,
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnPaste": false,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports.biome": "explicit",
|
||||
"source.fixAll.biome": "explicit",
|
||||
"source.removeUnusedImports": "always"
|
||||
},
|
||||
|
||||
// other vscode settings
|
||||
"[handlebars]": {
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import { DateTime } from "luxon";
|
||||
import http from "node:http";
|
||||
import os from "node:os";
|
||||
|
||||
import { DateTime } from "luxon";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
import { createApp } from "./app.ts";
|
||||
import { tryConnectToDatabase } from "./config/database.ts";
|
||||
import { ENV } from "./config/index.ts";
|
||||
|
||||
373
biome.json
373
biome.json
@ -1,69 +1,366 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.0.6/schema.json",
|
||||
"vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false },
|
||||
"files": { "ignoreUnknown": false, "includes": ["**", "!**/dist"] },
|
||||
"$schema": "https://biomejs.dev/schemas/2.2.4/schema.json",
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": true,
|
||||
"defaultBranch": "main"
|
||||
},
|
||||
"files": {
|
||||
"ignoreUnknown": true,
|
||||
"includes": [
|
||||
"**/*.js",
|
||||
"**/*.jsx",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.json",
|
||||
"**/*.css",
|
||||
"**/*.scss"
|
||||
],
|
||||
"experimentalScannerIgnores": [
|
||||
"**/node_modules/**",
|
||||
"**/.next/**",
|
||||
"**/dist/**",
|
||||
"**/build/**",
|
||||
"**/coverage/**",
|
||||
"**/.turbo/**",
|
||||
"**/out/**",
|
||||
"**/.env*",
|
||||
"**/public/**",
|
||||
"**/*.d.ts",
|
||||
"**/storybook-static/**",
|
||||
"**/.vercel/**"
|
||||
]
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"useEditorconfig": true,
|
||||
"formatWithErrors": false,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineEnding": "lf",
|
||||
"lineWidth": 100,
|
||||
"attributePosition": "auto",
|
||||
"bracketSpacing": true
|
||||
"lineEnding": "lf",
|
||||
"attributePosition": "auto"
|
||||
},
|
||||
"assist": { "actions": { "source": { "organizeImports": "on" } } },
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true,
|
||||
"correctness": {
|
||||
"useExhaustiveDependencies": "info",
|
||||
"noUnreachable": "warn"
|
||||
},
|
||||
"complexity": {
|
||||
"noForEach": "off",
|
||||
"noBannedTypes": "info",
|
||||
"noUselessFragments": "off",
|
||||
"useOptionalChain": "off",
|
||||
"noThisInStatic": "off"
|
||||
},
|
||||
"suspicious": {
|
||||
"noImplicitAnyLet": "info",
|
||||
"noExplicitAny": "info",
|
||||
"noArrayIndexKey": "info"
|
||||
},
|
||||
"style": {
|
||||
"useImportType": "off",
|
||||
"noInferrableTypes": "off",
|
||||
"noDefaultExport": "off",
|
||||
"noImplicitBoolean": "off",
|
||||
"noInferrableTypes": "error",
|
||||
"noNamespace": "error",
|
||||
"noNegationElse": "warn",
|
||||
"noNonNullAssertion": "info",
|
||||
"noUselessElse": "off",
|
||||
"noParameterAssign": "error",
|
||||
"useAsConstAssertion": "error",
|
||||
"noUnusedTemplateLiteral": "error",
|
||||
"noUselessElse": "warn",
|
||||
"useBlockStatements": "off",
|
||||
"useCollapsedElseIf": "error",
|
||||
"useConst": "error",
|
||||
"useDefaultParameterLast": "error",
|
||||
"useEnumInitializers": "error",
|
||||
"useExportType": "error",
|
||||
"useFilenamingConvention": {
|
||||
"level": "error",
|
||||
"options": {
|
||||
"strictCase": false,
|
||||
"requireAscii": true,
|
||||
"filenameCases": ["kebab-case"]
|
||||
}
|
||||
},
|
||||
"useForOf": "error",
|
||||
"useFragmentSyntax": "error",
|
||||
"useImportType": "error",
|
||||
"useNamingConvention": {
|
||||
"level": "off",
|
||||
"options": {
|
||||
"strictCase": false,
|
||||
"conventions": [
|
||||
{
|
||||
"selector": {
|
||||
"kind": "function"
|
||||
},
|
||||
"formats": ["camelCase", "PascalCase"]
|
||||
},
|
||||
{
|
||||
"selector": {
|
||||
"kind": "variable"
|
||||
},
|
||||
"formats": ["camelCase", "PascalCase", "CONSTANT_CASE"]
|
||||
},
|
||||
{
|
||||
"selector": {
|
||||
"kind": "typeLike"
|
||||
},
|
||||
"formats": ["PascalCase"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"useNodejsImportProtocol": "error",
|
||||
"useNumberNamespace": "error",
|
||||
"useSelfClosingElements": "error",
|
||||
"useShorthandAssign": "error",
|
||||
"useShorthandFunctionType": "error",
|
||||
"useSingleVarDeclarator": "error",
|
||||
"noUnusedTemplateLiteral": "error",
|
||||
"useNumberNamespace": "error"
|
||||
"useTemplate": "error",
|
||||
"useThrowOnlyError": "error"
|
||||
},
|
||||
"suspicious": {
|
||||
"noExplicitAny": "error",
|
||||
"noDebugger": "error",
|
||||
"noDuplicateJsxProps": "error",
|
||||
"noDuplicateObjectKeys": "error",
|
||||
"noDuplicateParameters": "error",
|
||||
"noShadowRestrictedNames": "error",
|
||||
"noSparseArray": "error",
|
||||
"noUnsafeNegation": "error",
|
||||
"noArrayIndexKey": "warn",
|
||||
"noAssignInExpressions": "error",
|
||||
"noCatchAssign": "error",
|
||||
"noClassAssign": "error",
|
||||
"noCommentText": "error",
|
||||
"noCompareNegZero": "error",
|
||||
"noConsole": "warn",
|
||||
"noConstEnum": "error",
|
||||
"noControlCharactersInRegex": "error",
|
||||
"noDoubleEquals": "error",
|
||||
"noDuplicateCase": "error",
|
||||
"noEmptyBlockStatements": "error",
|
||||
"noFallthroughSwitchClause": "error",
|
||||
"noFunctionAssign": "error",
|
||||
"noGlobalAssign": "error",
|
||||
"noLabelVar": "error",
|
||||
"noMisleadingCharacterClass": "error",
|
||||
"noPrototypeBuiltins": "error",
|
||||
"noRedeclare": "error",
|
||||
"noSelfCompare": "error",
|
||||
"noUnknownAtRules": "off"
|
||||
},
|
||||
"correctness": {
|
||||
"noConstAssign": "error",
|
||||
"noConstructorReturn": "error",
|
||||
"noEmptyPattern": "error",
|
||||
"noInvalidConstructorSuper": "error",
|
||||
"noInvalidUseBeforeDeclaration": "error",
|
||||
"noSelfAssign": "error",
|
||||
"noSetterReturn": "error",
|
||||
"noSwitchDeclarations": "error",
|
||||
"noUnreachable": "error",
|
||||
"noUnreachableSuper": "error",
|
||||
"noUnsafeFinally": "error",
|
||||
"noUnsafeOptionalChaining": "error",
|
||||
"noUnusedLabels": "error",
|
||||
"noUnusedVariables": "warn",
|
||||
"useExhaustiveDependencies": "error",
|
||||
"useHookAtTopLevel": "error",
|
||||
"useIsNan": "error",
|
||||
"useJsxKeyInIterable": "error",
|
||||
"useValidForDirection": "error",
|
||||
"useYield": "error"
|
||||
},
|
||||
"complexity": {
|
||||
"noBannedTypes": "error",
|
||||
"noExcessiveCognitiveComplexity": {
|
||||
"level": "warn",
|
||||
"options": {
|
||||
"maxAllowedComplexity": 15
|
||||
}
|
||||
},
|
||||
"noForEach": "warn",
|
||||
"noStaticOnlyClass": "error",
|
||||
"noThisInStatic": "error",
|
||||
"noUselessCatch": "error",
|
||||
"noUselessConstructor": "error",
|
||||
"noUselessFragments": "error",
|
||||
"noUselessLabel": "error",
|
||||
"noUselessRename": "error",
|
||||
"noUselessSwitchCase": "error",
|
||||
"noUselessTernary": "error",
|
||||
"noUselessTypeConstraint": "error",
|
||||
"noVoid": "error",
|
||||
"useFlatMap": "error",
|
||||
"useLiteralKeys": "error",
|
||||
"useOptionalChain": "error",
|
||||
"useSimpleNumberKeys": "error",
|
||||
"useSimplifiedLogicExpression": "error"
|
||||
},
|
||||
"security": {
|
||||
"noDangerouslySetInnerHtml": "error",
|
||||
"noDangerouslySetInnerHtmlWithChildren": "error",
|
||||
"noGlobalEval": "error"
|
||||
},
|
||||
"a11y": {
|
||||
"useSemanticElements": "info"
|
||||
"noAccessKey": "error",
|
||||
"noAriaHiddenOnFocusable": "error",
|
||||
"noAriaUnsupportedElements": "error",
|
||||
"noAutofocus": "error",
|
||||
"noDistractingElements": "error",
|
||||
"noHeaderScope": "error",
|
||||
"noInteractiveElementToNoninteractiveRole": "error",
|
||||
"noNoninteractiveElementToInteractiveRole": "error",
|
||||
"noNoninteractiveTabindex": "error",
|
||||
"noPositiveTabindex": "error",
|
||||
"noRedundantAlt": "error",
|
||||
"noRedundantRoles": "error",
|
||||
"useFocusableInteractive": "error",
|
||||
"useIframeTitle": "error",
|
||||
"useKeyWithClickEvents": "error",
|
||||
"useKeyWithMouseEvents": "error",
|
||||
"useMediaCaption": "error",
|
||||
"useSemanticElements": "error",
|
||||
"useValidAnchor": "error",
|
||||
"useValidAriaProps": "error",
|
||||
"useValidAriaValues": "error",
|
||||
"useValidLang": "error"
|
||||
},
|
||||
"performance": {
|
||||
"noAccumulatingSpread": "warn",
|
||||
"noDelete": "error"
|
||||
}
|
||||
},
|
||||
"domains": {
|
||||
"next": "all",
|
||||
"react": "recommended"
|
||||
}
|
||||
},
|
||||
"assist": {
|
||||
"actions": {
|
||||
"source": {
|
||||
"organizeImports": {
|
||||
"level": "on",
|
||||
"options": {
|
||||
"groups": [
|
||||
":URL:",
|
||||
":BLANK_LINE:",
|
||||
[":BUN:", ":NODE:"],
|
||||
":BLANK_LINE:",
|
||||
":PACKAGE_WITH_PROTOCOL:",
|
||||
":BLANK_LINE:",
|
||||
[":PACKAGE:"],
|
||||
":BLANK_LINE:",
|
||||
["!@/**", "!#*", "!~*", "!$*", "!%*"],
|
||||
":BLANK_LINE:",
|
||||
["@/**", "#*", "~*", "$*", "%*"],
|
||||
":BLANK_LINE:",
|
||||
[":PATH:", "!./**", "!../**"],
|
||||
":BLANK_LINE:",
|
||||
["../**"],
|
||||
":BLANK_LINE:",
|
||||
["./**"]
|
||||
],
|
||||
"identifierOrder": "lexicographic"
|
||||
}
|
||||
},
|
||||
"useSortedAttributes": "on"
|
||||
}
|
||||
}
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"jsxQuoteStyle": "single",
|
||||
"quoteProperties": "asNeeded",
|
||||
"trailingCommas": "es5",
|
||||
"semicolons": "always",
|
||||
"arrowParentheses": "always",
|
||||
"bracketSameLine": false,
|
||||
"bracketSpacing": true,
|
||||
"jsxQuoteStyle": "double",
|
||||
"quoteProperties": "asNeeded",
|
||||
"quoteStyle": "double",
|
||||
"attributePosition": "auto",
|
||||
"bracketSpacing": true
|
||||
"semicolons": "always",
|
||||
"trailingCommas": "es5"
|
||||
},
|
||||
"globals": ["console", "process", "__dirname", "__filename"]
|
||||
},
|
||||
"json": {
|
||||
"formatter": {
|
||||
"trailingCommas": "none",
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"css": {
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineWidth": 100,
|
||||
"quoteStyle": "double"
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"includes": ["**/*.test.{js,ts,tsx}", "**/*.spec.{js,ts,tsx}", "**/__tests__/**"],
|
||||
"linter": {
|
||||
"rules": {
|
||||
"suspicious": {
|
||||
"noExplicitAny": "off",
|
||||
"noConsole": "off"
|
||||
},
|
||||
"style": {
|
||||
"noNonNullAssertion": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"includes": ["**/next.config.{js,ts}", "**/tailwind.config.{js,ts}", "**/*.config.{js,ts}"],
|
||||
"linter": {
|
||||
"rules": {
|
||||
"style": {
|
||||
"noDefaultExport": "off"
|
||||
},
|
||||
"suspicious": {
|
||||
"noExplicitAny": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"includes": ["**/pages/**", "**/app/**/page.{tsx,jsx}", "**/app/**/layout.{tsx,jsx}"],
|
||||
"linter": {
|
||||
"rules": {
|
||||
"style": {
|
||||
"noDefaultExport": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"includes": ["**/*.d.ts", "**/lib/env/*.ts"],
|
||||
"linter": {
|
||||
"rules": {
|
||||
"style": {
|
||||
"noNamespace": "off",
|
||||
"useNamingConvention": {
|
||||
"level": "error",
|
||||
"options": {
|
||||
"strictCase": false,
|
||||
"conventions": [
|
||||
{
|
||||
"selector": {
|
||||
"kind": "objectLiteralProperty"
|
||||
},
|
||||
"formats": ["CONSTANT_CASE", "camelCase"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"suspicious": {
|
||||
"noExplicitAny": "error"
|
||||
},
|
||||
"complexity": {
|
||||
"noExcessiveCognitiveComplexity": {
|
||||
"level": "error",
|
||||
"options": {
|
||||
"maxAllowedComplexity": 12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { GetCustomerInvoiceByIdResponseDTO } from "@erp/customer-invoices/common";
|
||||
import type { GetIssueInvoiceByIdResponseDTO } from "@erp/customer-invoices/common";
|
||||
|
||||
export function formatPaymentMethodDTO(
|
||||
paymentMethod?: GetCustomerInvoiceByIdResponseDTO["payment_method"]
|
||||
paymentMethod?: GetIssueInvoiceByIdResponseDTO["payment_method"]
|
||||
) {
|
||||
if (!paymentMethod) {
|
||||
return null;
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
import { Presenter } from "@erp/core/api";
|
||||
import { toEmptyString } from "@repo/rdx-ddd";
|
||||
import { ArrayElement } from "@repo/rdx-utils";
|
||||
import { GetCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||
import { CustomerInvoiceItem, CustomerInvoiceItems } from "../../../domain";
|
||||
import type { ArrayElement } from "@repo/rdx-utils";
|
||||
|
||||
import type { GetIssueInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||
import type { CustomerInvoiceItem, CustomerInvoiceItems } from "../../../domain";
|
||||
|
||||
type GetCustomerInvoiceItemByInvoiceIdResponseDTO = ArrayElement<
|
||||
GetCustomerInvoiceByIdResponseDTO["items"]
|
||||
GetIssueInvoiceByIdResponseDTO["items"]
|
||||
>;
|
||||
|
||||
export class CustomerInvoiceItemsFullPresenter extends Presenter {
|
||||
@ -48,7 +49,7 @@ export class CustomerInvoiceItemsFullPresenter extends Presenter {
|
||||
};
|
||||
}
|
||||
|
||||
toOutput(invoiceItems: CustomerInvoiceItems): GetCustomerInvoiceByIdResponseDTO["items"] {
|
||||
toOutput(invoiceItems: CustomerInvoiceItems): GetIssueInvoiceByIdResponseDTO["items"] {
|
||||
return invoiceItems.map(this._mapItem);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
import { Presenter } from "@erp/core/api";
|
||||
import { toEmptyString } from "@repo/rdx-ddd";
|
||||
import { GetCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||
import { CustomerInvoice } from "../../../domain";
|
||||
import { CustomerInvoiceItemsFullPresenter } from "./customer-invoice-items.full.presenter";
|
||||
import { RecipientInvoiceFullPresenter } from "./recipient-invoice.full.representer";
|
||||
|
||||
import type { GetIssueInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||
import type { CustomerInvoice } from "../../../domain";
|
||||
|
||||
import type { CustomerInvoiceItemsFullPresenter } from "./customer-invoice-items.full.presenter";
|
||||
import type { RecipientInvoiceFullPresenter } from "./recipient-invoice.full.representer";
|
||||
|
||||
export class CustomerInvoiceFullPresenter extends Presenter<
|
||||
CustomerInvoice,
|
||||
GetCustomerInvoiceByIdResponseDTO
|
||||
GetIssueInvoiceByIdResponseDTO
|
||||
> {
|
||||
toOutput(invoice: CustomerInvoice): GetCustomerInvoiceByIdResponseDTO {
|
||||
toOutput(invoice: CustomerInvoice): GetIssueInvoiceByIdResponseDTO {
|
||||
const itemsPresenter = this.presenterRegistry.getPresenter({
|
||||
resource: "customer-invoice-items",
|
||||
projection: "FULL",
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { Presenter } from "@erp/core/api";
|
||||
import { DomainValidationError, toEmptyString } from "@repo/rdx-ddd";
|
||||
import { GetCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||
import { CustomerInvoice, InvoiceRecipient } from "../../../domain";
|
||||
|
||||
type GetRecipientInvoiceByInvoiceIdResponseDTO = GetCustomerInvoiceByIdResponseDTO["recipient"];
|
||||
import type { GetIssueInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||
import type { CustomerInvoice, InvoiceRecipient } from "../../../domain";
|
||||
|
||||
type GetRecipientInvoiceByInvoiceIdResponseDTO = GetIssueInvoiceByIdResponseDTO["recipient"];
|
||||
|
||||
export class RecipientInvoiceFullPresenter extends Presenter {
|
||||
toOutput(invoice: CustomerInvoice): GetRecipientInvoiceByInvoiceIdResponseDTO {
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { IPresenterOutputParams, Presenter } from "@erp/core/api";
|
||||
import { GetCustomerInvoiceByIdResponseDTO } from "@erp/customer-invoices/common";
|
||||
import { ArrayElement } from "@repo/rdx-utils";
|
||||
import { FormatMoneyOptions, formatMoneyDTO, formatQuantityDTO } from "../../helpers";
|
||||
import { type IPresenterOutputParams, Presenter } from "@erp/core/api";
|
||||
import type { GetIssueInvoiceByIdResponseDTO } from "@erp/customer-invoices/common";
|
||||
import type { ArrayElement } from "@repo/rdx-utils";
|
||||
|
||||
type CustomerInvoiceItemsDTO = GetCustomerInvoiceByIdResponseDTO["items"];
|
||||
import { type FormatMoneyOptions, formatMoneyDTO, formatQuantityDTO } from "../../helpers";
|
||||
|
||||
type CustomerInvoiceItemsDTO = GetIssueInvoiceByIdResponseDTO["items"];
|
||||
type CustomerInvoiceItemDTO = ArrayElement<CustomerInvoiceItemsDTO>;
|
||||
|
||||
export class CustomerInvoiceItemsReportPersenter extends Presenter<
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { Presenter } from "@erp/core/api";
|
||||
import { GetCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||
|
||||
import type { GetIssueInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||
import {
|
||||
FormatMoneyOptions,
|
||||
type FormatMoneyOptions,
|
||||
formatDateDTO,
|
||||
formatMoneyDTO,
|
||||
formatPercentageDTO,
|
||||
@ -9,10 +10,10 @@ import {
|
||||
import { formatPaymentMethodDTO } from "../../helpers/format-payment_method-dto";
|
||||
|
||||
export class CustomerInvoiceReportPresenter extends Presenter<
|
||||
GetCustomerInvoiceByIdResponseDTO,
|
||||
GetIssueInvoiceByIdResponseDTO,
|
||||
unknown
|
||||
> {
|
||||
toOutput(invoiceDTO: GetCustomerInvoiceByIdResponseDTO) {
|
||||
toOutput(invoiceDTO: GetIssueInvoiceByIdResponseDTO) {
|
||||
const itemsPresenter = this.presenterRegistry.getPresenter({
|
||||
resource: "customer-invoice-items",
|
||||
projection: "REPORT",
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
import { Presenter } from "@erp/core/api";
|
||||
import { Criteria } from "@repo/rdx-criteria/server";
|
||||
import type { Criteria } from "@repo/rdx-criteria/server";
|
||||
import { toEmptyString } from "@repo/rdx-ddd";
|
||||
import { ArrayElement, Collection } from "@repo/rdx-utils";
|
||||
import { ListCustomerInvoicesResponseDTO } from "../../../../common/dto";
|
||||
import { CustomerInvoiceListDTO } from "../../../infrastructure";
|
||||
import type { ArrayElement, Collection } from "@repo/rdx-utils";
|
||||
|
||||
import type { ListIssueInvoicesResponseDTO } from "../../../../common/dto";
|
||||
import type { CustomerInvoiceListDTO } from "../../../infrastructure";
|
||||
|
||||
export class ListCustomerInvoicesPresenter extends Presenter {
|
||||
protected _mapInvoice(invoice: CustomerInvoiceListDTO) {
|
||||
const recipientDTO = invoice.recipient.toObjectString();
|
||||
|
||||
const invoiceDTO: ArrayElement<ListCustomerInvoicesResponseDTO["items"]> = {
|
||||
const invoiceDTO: ArrayElement<ListIssueInvoicesResponseDTO["items"]> = {
|
||||
id: invoice.id.toString(),
|
||||
company_id: invoice.companyId.toString(),
|
||||
is_proforma: invoice.isProforma,
|
||||
@ -49,7 +50,7 @@ export class ListCustomerInvoicesPresenter extends Presenter {
|
||||
toOutput(params: {
|
||||
customerInvoices: Collection<CustomerInvoiceListDTO>;
|
||||
criteria: Criteria;
|
||||
}): ListCustomerInvoicesResponseDTO {
|
||||
}): ListIssueInvoicesResponseDTO {
|
||||
const { customerInvoices, criteria } = params;
|
||||
|
||||
const invoices = customerInvoices.map((invoice) => this._mapInvoice(invoice));
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { Criteria } from "@repo/rdx-criteria/server";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Collection, Maybe, Result } from "@repo/rdx-utils";
|
||||
import { Transaction } from "sequelize";
|
||||
import {
|
||||
import type { Criteria } from "@repo/rdx-criteria/server";
|
||||
import type { UniqueID } from "@repo/rdx-ddd";
|
||||
import { type Collection, Maybe, Result } from "@repo/rdx-utils";
|
||||
import type { Transaction } from "sequelize";
|
||||
|
||||
import type {
|
||||
CustomerInvoiceNumber,
|
||||
CustomerInvoiceSerie,
|
||||
CustomerInvoiceStatus,
|
||||
@ -10,11 +11,11 @@ import {
|
||||
} from "../../domain";
|
||||
import {
|
||||
CustomerInvoice,
|
||||
CustomerInvoicePatchProps,
|
||||
CustomerInvoiceProps,
|
||||
type CustomerInvoicePatchProps,
|
||||
type CustomerInvoiceProps,
|
||||
} from "../../domain/aggregates";
|
||||
import { ICustomerInvoiceRepository } from "../../domain/repositories";
|
||||
import { CustomerInvoiceListDTO } from "../../infrastructure";
|
||||
import type { ICustomerInvoiceRepository } from "../../domain/repositories";
|
||||
import type { CustomerInvoiceListDTO } from "../../infrastructure";
|
||||
|
||||
export class CustomerInvoiceApplicationService {
|
||||
constructor(
|
||||
@ -57,57 +58,57 @@ export class CustomerInvoiceApplicationService {
|
||||
*
|
||||
* @param companyId - Identificador de la empresa a la que pertenece la proforma.
|
||||
* @param props - Las propiedades ya validadas para crear la proforma.
|
||||
* @param invoiceId - Identificador UUID de la proforma (opcional).
|
||||
* @param proformaId - Identificador UUID de la proforma (opcional).
|
||||
* @returns Result<CustomerInvoice, Error> - El agregado construido o un error si falla la creación.
|
||||
*/
|
||||
buildProformaInCompany(
|
||||
companyId: UniqueID,
|
||||
props: Omit<CustomerInvoiceProps, "companyId">,
|
||||
invoiceId?: UniqueID
|
||||
proformaId?: UniqueID
|
||||
): Result<CustomerInvoice, Error> {
|
||||
return CustomerInvoice.create({ ...props, companyId }, invoiceId);
|
||||
return CustomerInvoice.create({ ...props, companyId }, proformaId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Guarda una nueva factura y devuelve la factura guardada.
|
||||
* Guarda una nueva proforma y devuelve la proforma guardada.
|
||||
*
|
||||
* @param companyId - Identificador de la empresa a la que pertenece la factura.
|
||||
* @param invoice - El agregado a guardar.
|
||||
* @param companyId - Identificador de la empresa a la que pertenece la proforma.
|
||||
* @param proforma - La proforma a guardar.
|
||||
* @param transaction - Transacción activa para la operación.
|
||||
* @returns Result<CustomerInvoice, Error> - El agregado guardado o un error si falla la operación.
|
||||
* @returns Result<CustomerInvoice, Error> - La proforma guardada o un error si falla la operación.
|
||||
*/
|
||||
async createInvoiceInCompany(
|
||||
companyId: UniqueID,
|
||||
invoice: CustomerInvoice,
|
||||
proforma: CustomerInvoice,
|
||||
transaction: Transaction
|
||||
): Promise<Result<CustomerInvoice, Error>> {
|
||||
const result = await this.repository.create(invoice, transaction);
|
||||
const result = await this.repository.create(proforma, transaction);
|
||||
if (result.isFailure) {
|
||||
return Result.fail(result.error);
|
||||
}
|
||||
|
||||
return this.getInvoiceByIdInCompany(companyId, invoice.id, transaction);
|
||||
return this.getProformaByIdInCompany(companyId, proforma.id, transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Actualiza una factura existente y devuelve la factura actualizada.
|
||||
* Actualiza una proforma existente y devuelve la proforma actualizada.
|
||||
*
|
||||
* @param companyId - Identificador de la empresa a la que pertenece la factura.
|
||||
* @param invoice - El agregado a guardar.
|
||||
* @param proforma - La proforma a guardar.
|
||||
* @param transaction - Transacción activa para la operación.
|
||||
* @returns Result<CustomerInvoice, Error> - El agregado guardado o un error si falla la operación.
|
||||
* @returns Result<CustomerInvoice, Error> - La proforma guardada o un error si falla la operación.
|
||||
*/
|
||||
async updateInvoiceInCompany(
|
||||
async updateProformaInCompany(
|
||||
companyId: UniqueID,
|
||||
invoice: CustomerInvoice,
|
||||
proforma: CustomerInvoice,
|
||||
transaction: Transaction
|
||||
): Promise<Result<CustomerInvoice, Error>> {
|
||||
const result = await this.repository.update(invoice, transaction);
|
||||
const result = await this.repository.update(proforma, transaction);
|
||||
if (result.isFailure) {
|
||||
return Result.fail(result.error);
|
||||
}
|
||||
|
||||
return this.getInvoiceByIdInCompany(companyId, invoice.id, transaction);
|
||||
return this.getProformaByIdInCompany(companyId, proforma.id, transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -151,12 +152,35 @@ export class CustomerInvoiceApplicationService {
|
||||
* @param transaction - Transacción activa para la operación.
|
||||
* @returns Result<CustomerInvoice, Error> - Factura encontrada o error.
|
||||
*/
|
||||
async getInvoiceByIdInCompany(
|
||||
async getIssueInvoiceByIdInCompany(
|
||||
companyId: UniqueID,
|
||||
invoiceId: UniqueID,
|
||||
transaction?: Transaction
|
||||
): Promise<Result<CustomerInvoice>> {
|
||||
return await this.repository.getByIdInCompany(companyId, invoiceId, transaction);
|
||||
return await this.repository.getByIdInCompany(companyId, invoiceId, transaction, {
|
||||
where: {
|
||||
is_proforma: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Recupera una proforma por su identificador único.
|
||||
*
|
||||
* @param proformaId - Identificador UUID de la proforma.
|
||||
* @param transaction - Transacción activa para la operación.
|
||||
* @returns Result<CustomerInvoice, Error> - proforma encontrada o error.
|
||||
*/
|
||||
async getProformaByIdInCompany(
|
||||
companyId: UniqueID,
|
||||
proformaId: UniqueID,
|
||||
transaction?: Transaction
|
||||
): Promise<Result<CustomerInvoice>> {
|
||||
return await this.repository.getByIdInCompany(companyId, proformaId, transaction, {
|
||||
where: {
|
||||
is_proforma: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -164,18 +188,18 @@ export class CustomerInvoiceApplicationService {
|
||||
* No lo guarda en el repositorio.
|
||||
*
|
||||
* @param companyId - Identificador de la empresa a la que pertenece la factura.
|
||||
* @param invoiceId - Identificador de la factura a actualizar.
|
||||
* @param proformaId - Identificador de la factura a actualizar.
|
||||
* @param changes - Subconjunto de props válidas para aplicar.
|
||||
* @param transaction - Transacción activa para la operación.
|
||||
* @returns Result<CustomerInvoice, Error> - Factura actualizada o error.
|
||||
*/
|
||||
async patchInvoiceByIdInCompany(
|
||||
async patchProformaByIdInCompany(
|
||||
companyId: UniqueID,
|
||||
invoiceId: UniqueID,
|
||||
proformaId: UniqueID,
|
||||
changes: CustomerInvoicePatchProps,
|
||||
transaction?: Transaction
|
||||
): Promise<Result<CustomerInvoice, Error>> {
|
||||
const invoiceResult = await this.getInvoiceByIdInCompany(companyId, invoiceId, transaction);
|
||||
const invoiceResult = await this.getProformaByIdInCompany(companyId, proformaId, transaction);
|
||||
|
||||
if (invoiceResult.isFailure) {
|
||||
return Result.fail(invoiceResult.error);
|
||||
|
||||
@ -1 +0,0 @@
|
||||
export * from "./create-customer-invoice.use-case";
|
||||
@ -1,7 +1,2 @@
|
||||
export * from "./change-status-customer-invoice.use-case";
|
||||
export * from "./create";
|
||||
export * from "./get-customer-invoice.use-case";
|
||||
export * from "./issue-customer-invoice.use-case";
|
||||
export * from "./list-customer-invoices.use-case";
|
||||
export * from "./report";
|
||||
export * from "./update";
|
||||
export * from "./issue-invoices";
|
||||
export * from "./proformas";
|
||||
|
||||
@ -1,22 +1,23 @@
|
||||
import { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import type { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { CustomerInvoiceFullPresenter } from "../presenters/domain";
|
||||
import { CustomerInvoiceApplicationService } from "../services";
|
||||
|
||||
type GetCustomerInvoiceUseCaseInput = {
|
||||
import type { CustomerInvoiceFullPresenter } from "../../presenters/domain";
|
||||
import type { CustomerInvoiceApplicationService } from "../../services";
|
||||
|
||||
type GetIssueInvoiceUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
invoice_id: string;
|
||||
};
|
||||
|
||||
export class GetCustomerInvoiceUseCase {
|
||||
export class GetIssueInvoiceUseCase {
|
||||
constructor(
|
||||
private readonly service: CustomerInvoiceApplicationService,
|
||||
private readonly transactionManager: ITransactionManager,
|
||||
private readonly presenterRegistry: IPresenterRegistry
|
||||
) {}
|
||||
|
||||
public execute(params: GetCustomerInvoiceUseCaseInput) {
|
||||
public execute(params: GetIssueInvoiceUseCaseInput) {
|
||||
const { invoice_id, companyId } = params;
|
||||
|
||||
const idOrError = UniqueID.create(invoice_id);
|
||||
@ -32,17 +33,18 @@ export class GetCustomerInvoiceUseCase {
|
||||
|
||||
return this.transactionManager.complete(async (transaction) => {
|
||||
try {
|
||||
const invoiceOrError = await this.service.getInvoiceByIdInCompany(
|
||||
const invoiceOrError = await this.service.getIssueInvoiceByIdInCompany(
|
||||
companyId,
|
||||
invoiceId,
|
||||
transaction
|
||||
);
|
||||
|
||||
if (invoiceOrError.isFailure) {
|
||||
return Result.fail(invoiceOrError.error);
|
||||
}
|
||||
|
||||
const customerInvoice = invoiceOrError.data;
|
||||
const dto = presenter.toOutput(customerInvoice);
|
||||
const invoice = invoiceOrError.data;
|
||||
const dto = presenter.toOutput(invoice);
|
||||
|
||||
return Result.ok(dto);
|
||||
} catch (error: unknown) {
|
||||
@ -0,0 +1,2 @@
|
||||
export * from "./get-issue-invoice.use-case";
|
||||
export * from "./report-issue-invoice.use-case";
|
||||
@ -1,22 +1,23 @@
|
||||
import { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import type { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { CustomerInvoiceApplicationService } from "../../services/customer-invoice-application.service";
|
||||
import { CustomerInvoiceReportPDFPresenter } from "./reporter";
|
||||
|
||||
type ReportCustomerInvoiceUseCaseInput = {
|
||||
import type { CustomerInvoiceApplicationService } from "../../services";
|
||||
import type { CustomerInvoiceReportPDFPresenter } from "../proformas";
|
||||
|
||||
type ReportIssueInvoiceUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
invoice_id: string;
|
||||
};
|
||||
|
||||
export class ReportCustomerInvoiceUseCase {
|
||||
export class ReportIssueInvoiceUseCase {
|
||||
constructor(
|
||||
private readonly service: CustomerInvoiceApplicationService,
|
||||
private readonly transactionManager: ITransactionManager,
|
||||
private readonly presenterRegistry: IPresenterRegistry
|
||||
) {}
|
||||
|
||||
public async execute(params: ReportCustomerInvoiceUseCaseInput) {
|
||||
public async execute(params: ReportIssueInvoiceUseCaseInput) {
|
||||
const { invoice_id, companyId } = params;
|
||||
|
||||
const idOrError = UniqueID.create(invoice_id);
|
||||
@ -34,11 +35,12 @@ export class ReportCustomerInvoiceUseCase {
|
||||
|
||||
return this.transactionManager.complete(async (transaction) => {
|
||||
try {
|
||||
const invoiceOrError = await this.service.getInvoiceByIdInCompany(
|
||||
const invoiceOrError = await this.service.getIssueInvoiceByIdInCompany(
|
||||
companyId,
|
||||
invoiceId,
|
||||
transaction
|
||||
);
|
||||
|
||||
if (invoiceOrError.isFailure) {
|
||||
return Result.fail(invoiceOrError.error);
|
||||
}
|
||||
@ -1,17 +1,18 @@
|
||||
import { ITransactionManager } from "@erp/core/api";
|
||||
import { ChangeStatusCustomerInvoiceByIdRequestDTO } from "@erp/customer-invoices/common";
|
||||
import type { ITransactionManager } from "@erp/core/api";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { ProformaCustomerInvoiceDomainService } from "../../domain";
|
||||
import { CustomerInvoiceApplicationService } from "../services";
|
||||
|
||||
type ChangeStatusCustomerInvoiceUseCaseInput = {
|
||||
import type { ChangeStatusProformaByIdRequestDTO } from "../../../../common";
|
||||
import { ProformaCustomerInvoiceDomainService } from "../../../domain";
|
||||
import type { CustomerInvoiceApplicationService } from "../../services";
|
||||
|
||||
type ChangeStatusProformaUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
proforma_id: string;
|
||||
dto: ChangeStatusCustomerInvoiceByIdRequestDTO;
|
||||
dto: ChangeStatusProformaByIdRequestDTO;
|
||||
};
|
||||
|
||||
export class ChangeStatusCustomerInvoiceUseCase {
|
||||
export class ChangeStatusProformaUseCase {
|
||||
private readonly proformaDomainService: ProformaCustomerInvoiceDomainService;
|
||||
|
||||
constructor(
|
||||
@ -21,7 +22,7 @@ export class ChangeStatusCustomerInvoiceUseCase {
|
||||
this.proformaDomainService = new ProformaCustomerInvoiceDomainService();
|
||||
}
|
||||
|
||||
public execute(params: ChangeStatusCustomerInvoiceUseCaseInput) {
|
||||
public execute(params: ChangeStatusProformaUseCaseInput) {
|
||||
const {
|
||||
proforma_id,
|
||||
companyId,
|
||||
@ -1,19 +1,25 @@
|
||||
import { JsonTaxCatalogProvider } from "@erp/core";
|
||||
import { DuplicateEntityError, IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Maybe, Result } from "@repo/rdx-utils";
|
||||
import { Transaction } from "sequelize";
|
||||
import { CreateCustomerInvoiceRequestDTO } from "../../../../common/dto";
|
||||
import { CustomerInvoiceFullPresenter } from "../../presenters";
|
||||
import { CustomerInvoiceApplicationService } from "../../services/customer-invoice-application.service";
|
||||
import { CreateCustomerInvoicePropsMapper } from "./map-dto-to-create-customer-invoice-props";
|
||||
import type { JsonTaxCatalogProvider } from "@erp/core";
|
||||
import {
|
||||
DuplicateEntityError,
|
||||
type IPresenterRegistry,
|
||||
type ITransactionManager,
|
||||
} from "@erp/core/api";
|
||||
import type { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import type { Transaction } from "sequelize";
|
||||
|
||||
type CreateCustomerInvoiceUseCaseInput = {
|
||||
import type { CreateProformaRequestDTO } from "../../../../../common";
|
||||
import type { CustomerInvoiceFullPresenter } from "../../../presenters";
|
||||
import type { CustomerInvoiceApplicationService } from "../../../services";
|
||||
|
||||
import { CreateCustomerInvoicePropsMapper } from "./map-dto-to-create-proforma-props";
|
||||
|
||||
type CreateProformaUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
dto: CreateCustomerInvoiceRequestDTO;
|
||||
dto: CreateProformaRequestDTO;
|
||||
};
|
||||
|
||||
export class CreateCustomerInvoiceUseCase {
|
||||
export class CreateProformaUseCase {
|
||||
constructor(
|
||||
private readonly service: CustomerInvoiceApplicationService,
|
||||
private readonly transactionManager: ITransactionManager,
|
||||
@ -21,7 +27,7 @@ export class CreateCustomerInvoiceUseCase {
|
||||
private readonly taxCatalog: JsonTaxCatalogProvider
|
||||
) {}
|
||||
|
||||
public async execute(params: CreateCustomerInvoiceUseCaseInput) {
|
||||
public async execute(params: CreateProformaUseCaseInput) {
|
||||
const { dto, companyId } = params;
|
||||
const presenter = this.presenterRegistry.getPresenter({
|
||||
resource: "customer-invoice",
|
||||
@ -51,7 +57,7 @@ export class CreateCustomerInvoiceUseCase {
|
||||
// 3) Construir entidad de dominio
|
||||
const proformaProps = {
|
||||
...props,
|
||||
invoiceNumber: Maybe.some(newProformaNumber),
|
||||
invoiceNumber: newProformaNumber,
|
||||
};
|
||||
|
||||
const buildResult = this.service.buildProformaInCompany(companyId, proformaProps, id);
|
||||
@ -0,0 +1 @@
|
||||
export * from "./create-proforma.use-case";
|
||||
@ -1,39 +1,37 @@
|
||||
import { JsonTaxCatalogProvider } from "@erp/core";
|
||||
import type { JsonTaxCatalogProvider } from "@erp/core";
|
||||
import { Tax } from "@erp/core/api";
|
||||
import {
|
||||
CurrencyCode,
|
||||
DomainError,
|
||||
extractOrPushError,
|
||||
LanguageCode,
|
||||
maybeFromNullableVO,
|
||||
Percentage,
|
||||
TextValue,
|
||||
UniqueID,
|
||||
UtcDate,
|
||||
ValidationErrorCollection,
|
||||
ValidationErrorDetail,
|
||||
type ValidationErrorDetail,
|
||||
extractOrPushError,
|
||||
maybeFromNullableVO,
|
||||
} from "@repo/rdx-ddd";
|
||||
import { Maybe, Result } from "@repo/rdx-utils";
|
||||
import {
|
||||
CreateCustomerInvoiceItemRequestDTO,
|
||||
CreateCustomerInvoiceRequestDTO,
|
||||
} from "../../../../common/dto";
|
||||
|
||||
import type { CreateProformaItemRequestDTO, CreateProformaRequestDTO } from "../../../../../common";
|
||||
import {
|
||||
CustomerInvoiceItem,
|
||||
CustomerInvoiceItemDescription,
|
||||
CustomerInvoiceItemProps,
|
||||
type CustomerInvoiceItemProps,
|
||||
CustomerInvoiceItems,
|
||||
CustomerInvoiceNumber,
|
||||
CustomerInvoiceProps,
|
||||
type CustomerInvoiceProps,
|
||||
CustomerInvoiceSerie,
|
||||
CustomerInvoiceStatus,
|
||||
InvoicePaymentMethod,
|
||||
InvoiceRecipient,
|
||||
type InvoiceRecipient,
|
||||
ItemAmount,
|
||||
ItemDiscount,
|
||||
ItemQuantity,
|
||||
ItemTaxes,
|
||||
} from "../../../domain";
|
||||
} from "../../../../domain";
|
||||
|
||||
/**
|
||||
* Convierte el DTO a las props validadas (CustomerProps).
|
||||
@ -56,13 +54,13 @@ export class CreateCustomerInvoicePropsMapper {
|
||||
this.errors = [];
|
||||
}
|
||||
|
||||
public map(dto: CreateCustomerInvoiceRequestDTO, companyId: UniqueID) {
|
||||
public map(dto: CreateProformaRequestDTO, companyId: UniqueID) {
|
||||
try {
|
||||
this.errors = [];
|
||||
|
||||
const defaultStatus = CustomerInvoiceStatus.createDraft();
|
||||
|
||||
const invoiceId = extractOrPushError(UniqueID.create(dto.id), "id", this.errors);
|
||||
const proformaId = extractOrPushError(UniqueID.create(dto.id), "id", this.errors);
|
||||
|
||||
const isProforma = true;
|
||||
|
||||
@ -74,8 +72,8 @@ export class CreateCustomerInvoicePropsMapper {
|
||||
|
||||
const recipient = Maybe.none<InvoiceRecipient>();
|
||||
|
||||
const invoiceNumber = extractOrPushError(
|
||||
maybeFromNullableVO(dto.invoice_number, (value) => CustomerInvoiceNumber.create(value)),
|
||||
const proformaNumber = extractOrPushError(
|
||||
CustomerInvoiceNumber.create(dto.invoice_number),
|
||||
"invoice_number",
|
||||
this.errors
|
||||
);
|
||||
@ -153,13 +151,14 @@ export class CreateCustomerInvoicePropsMapper {
|
||||
);
|
||||
}
|
||||
|
||||
const invoiceProps: CustomerInvoiceProps = {
|
||||
const proformaProps: CustomerInvoiceProps = {
|
||||
companyId,
|
||||
isProforma,
|
||||
proformaId: Maybe.none(),
|
||||
status: defaultStatus!,
|
||||
|
||||
invoiceNumber: proformaNumber!,
|
||||
series: series!,
|
||||
invoiceNumber: invoiceNumber!,
|
||||
|
||||
invoiceDate: invoiceDate!,
|
||||
operationDate: operationDate!,
|
||||
@ -181,13 +180,13 @@ export class CreateCustomerInvoicePropsMapper {
|
||||
discountPercentage: discountPercentage!,
|
||||
};
|
||||
|
||||
return Result.ok({ id: invoiceId!, props: invoiceProps });
|
||||
return Result.ok({ id: proformaId!, props: proformaProps });
|
||||
} catch (err: unknown) {
|
||||
return Result.fail(new DomainError("Customer invoice props mapping failed", { cause: err }));
|
||||
}
|
||||
}
|
||||
|
||||
private mapItems(items: CreateCustomerInvoiceItemRequestDTO[]) {
|
||||
private mapItems(items: CreateProformaItemRequestDTO[]) {
|
||||
const invoiceItems = CustomerInvoiceItems.create({
|
||||
currencyCode: this.currencyCode!,
|
||||
languageCode: this.languageCode!,
|
||||
@ -246,10 +245,10 @@ export class CreateCustomerInvoicePropsMapper {
|
||||
return invoiceItems;
|
||||
}
|
||||
|
||||
private mapTaxes(item: CreateCustomerInvoiceItemRequestDTO, itemIndex: number) {
|
||||
private mapTaxes(item: CreateProformaItemRequestDTO, itemIndex: number) {
|
||||
const taxes = ItemTaxes.create([]);
|
||||
|
||||
item.taxes.split(",").every((tax_code, taxIndex) => {
|
||||
item.taxes.split(",").forEach((tax_code, taxIndex) => {
|
||||
const taxResult = Tax.createFromCode(tax_code, this.taxCatalog);
|
||||
if (taxResult.isSuccess) {
|
||||
taxes.add(taxResult.data);
|
||||
@ -1,23 +1,24 @@
|
||||
import { EntityNotFoundError, ITransactionManager } from "@erp/core/api";
|
||||
import { EntityNotFoundError, type ITransactionManager } from "@erp/core/api";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { CustomerInvoiceApplicationService } from "../services";
|
||||
|
||||
type DeleteCustomerInvoiceUseCaseInput = {
|
||||
import type { CustomerInvoiceApplicationService } from "../../services";
|
||||
|
||||
type DeleteProformaUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
invoice_id: string;
|
||||
proforma_id: string;
|
||||
};
|
||||
|
||||
export class DeleteCustomerInvoiceUseCase {
|
||||
export class DeleteProformaUseCase {
|
||||
constructor(
|
||||
private readonly service: CustomerInvoiceApplicationService,
|
||||
private readonly transactionManager: ITransactionManager
|
||||
) {}
|
||||
|
||||
public execute(params: DeleteCustomerInvoiceUseCaseInput) {
|
||||
const { invoice_id, companyId } = params;
|
||||
public execute(params: DeleteProformaUseCaseInput) {
|
||||
const { proforma_id, companyId } = params;
|
||||
|
||||
const idOrError = UniqueID.create(invoice_id);
|
||||
const idOrError = UniqueID.create(proforma_id);
|
||||
|
||||
if (idOrError.isFailure) {
|
||||
return Result.fail(idOrError.error);
|
||||
@ -40,9 +41,7 @@ export class DeleteCustomerInvoiceUseCase {
|
||||
const invoiceExists = existsCheck.data;
|
||||
|
||||
if (!invoiceExists) {
|
||||
return Result.fail(
|
||||
new EntityNotFoundError("Customer invoice", "id", invoiceId.toString())
|
||||
);
|
||||
return Result.fail(new EntityNotFoundError("Proforma", "id", invoiceId.toString()));
|
||||
}
|
||||
|
||||
return await this.service.deleteInvoiceByIdInCompany(companyId, invoiceId, transaction);
|
||||
@ -0,0 +1,54 @@
|
||||
import type { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
|
||||
import type { CustomerInvoiceFullPresenter } from "../../presenters/domain";
|
||||
import type { CustomerInvoiceApplicationService } from "../../services";
|
||||
|
||||
type GetProformaUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
proforma_id: string;
|
||||
};
|
||||
|
||||
export class GetProformaUseCase {
|
||||
constructor(
|
||||
private readonly service: CustomerInvoiceApplicationService,
|
||||
private readonly transactionManager: ITransactionManager,
|
||||
private readonly presenterRegistry: IPresenterRegistry
|
||||
) {}
|
||||
|
||||
public execute(params: GetProformaUseCaseInput) {
|
||||
const { proforma_id, companyId } = params;
|
||||
|
||||
const idOrError = UniqueID.create(proforma_id);
|
||||
if (idOrError.isFailure) {
|
||||
return Result.fail(idOrError.error);
|
||||
}
|
||||
|
||||
const proformaId = idOrError.data;
|
||||
const presenter = this.presenterRegistry.getPresenter({
|
||||
resource: "customer-invoice",
|
||||
projection: "FULL",
|
||||
}) as CustomerInvoiceFullPresenter;
|
||||
|
||||
return this.transactionManager.complete(async (transaction) => {
|
||||
try {
|
||||
const proformaOrError = await this.service.getProformaByIdInCompany(
|
||||
companyId,
|
||||
proformaId,
|
||||
transaction
|
||||
);
|
||||
if (proformaOrError.isFailure) {
|
||||
return Result.fail(proformaOrError.error);
|
||||
}
|
||||
|
||||
const proforma = proformaOrError.data;
|
||||
const dto = presenter.toOutput(proforma);
|
||||
|
||||
return Result.ok(dto);
|
||||
} catch (error: unknown) {
|
||||
return Result.fail(error as Error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
export * from "./change-status-proforma.use-case";
|
||||
export * from "./create-proforma";
|
||||
export * from "./delete-proforma.use-case";
|
||||
export * from "./get-proforma.use-case";
|
||||
export * from "./issue-proforma.use-case";
|
||||
export * from "./list-proformas.use-case";
|
||||
export * from "./report-proforma";
|
||||
export * from "./update-proforma";
|
||||
@ -1,12 +1,13 @@
|
||||
import { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import type { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import { UniqueID, UtcDate } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
|
||||
import {
|
||||
IssueCustomerInvoiceDomainService,
|
||||
ProformaCustomerInvoiceDomainService,
|
||||
} from "../../domain";
|
||||
import { CustomerInvoiceFullPresenter } from "../presenters";
|
||||
import { CustomerInvoiceApplicationService } from "../services";
|
||||
} from "../../../domain";
|
||||
import type { CustomerInvoiceFullPresenter } from "../../presenters";
|
||||
import type { CustomerInvoiceApplicationService } from "../../services";
|
||||
|
||||
type IssueCustomerInvoiceUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
@ -22,7 +23,7 @@ type IssueCustomerInvoiceUseCaseInput = {
|
||||
* - Marca la proforma como "issued"
|
||||
* - Persiste ambas dentro de la misma transacción
|
||||
*/
|
||||
export class IssueCustomerInvoiceUseCase {
|
||||
export class IssueProformaInvoiceUseCase {
|
||||
private readonly issueDomainService: IssueCustomerInvoiceDomainService;
|
||||
private readonly proformaDomainService: ProformaCustomerInvoiceDomainService;
|
||||
|
||||
@ -1,18 +1,19 @@
|
||||
import { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import { Criteria } from "@repo/rdx-criteria/server";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import type { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import type { Criteria } from "@repo/rdx-criteria/server";
|
||||
import type { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { Transaction } from "sequelize";
|
||||
import { ListCustomerInvoicesResponseDTO } from "../../../common/dto";
|
||||
import { ListCustomerInvoicesPresenter } from "../presenters";
|
||||
import { CustomerInvoiceApplicationService } from "../services";
|
||||
import type { Transaction } from "sequelize";
|
||||
|
||||
type ListCustomerInvoicesUseCaseInput = {
|
||||
import type { ListIssueInvoicesResponseDTO } from "../../../../common/dto";
|
||||
import type { ListCustomerInvoicesPresenter } from "../../presenters";
|
||||
import type { CustomerInvoiceApplicationService } from "../../services";
|
||||
|
||||
type ListProformasUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
criteria: Criteria;
|
||||
};
|
||||
|
||||
export class ListCustomerInvoicesUseCase {
|
||||
export class ListProformasUseCase {
|
||||
constructor(
|
||||
private readonly service: CustomerInvoiceApplicationService,
|
||||
private readonly transactionManager: ITransactionManager,
|
||||
@ -20,8 +21,8 @@ export class ListCustomerInvoicesUseCase {
|
||||
) {}
|
||||
|
||||
public execute(
|
||||
params: ListCustomerInvoicesUseCaseInput
|
||||
): Promise<Result<ListCustomerInvoicesResponseDTO, Error>> {
|
||||
params: ListProformasUseCaseInput
|
||||
): Promise<Result<ListIssueInvoicesResponseDTO, Error>> {
|
||||
const { criteria, companyId } = params;
|
||||
const presenter = this.presenterRegistry.getPresenter({
|
||||
resource: "customer-invoice",
|
||||
@ -0,0 +1,2 @@
|
||||
export * from "./report-proforma.use-case";
|
||||
export * from "./reporter";
|
||||
@ -0,0 +1,59 @@
|
||||
import type { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
|
||||
import type { CustomerInvoiceApplicationService } from "../../../services/customer-invoice-application.service";
|
||||
|
||||
import type { CustomerInvoiceReportPDFPresenter } from "./reporter";
|
||||
|
||||
type ReportProformaUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
proforma_id: string;
|
||||
};
|
||||
|
||||
export class ReportProformaUseCase {
|
||||
constructor(
|
||||
private readonly service: CustomerInvoiceApplicationService,
|
||||
private readonly transactionManager: ITransactionManager,
|
||||
private readonly presenterRegistry: IPresenterRegistry
|
||||
) {}
|
||||
|
||||
public async execute(params: ReportProformaUseCaseInput) {
|
||||
const { proforma_id, companyId } = params;
|
||||
|
||||
const idOrError = UniqueID.create(proforma_id);
|
||||
|
||||
if (idOrError.isFailure) {
|
||||
return Result.fail(idOrError.error);
|
||||
}
|
||||
|
||||
const invoiceId = idOrError.data;
|
||||
const pdfPresenter = this.presenterRegistry.getPresenter({
|
||||
resource: "customer-invoice",
|
||||
projection: "REPORT",
|
||||
format: "PDF",
|
||||
}) as CustomerInvoiceReportPDFPresenter;
|
||||
|
||||
return this.transactionManager.complete(async (transaction) => {
|
||||
try {
|
||||
const proformaOrError = await this.service.getProformaByIdInCompany(
|
||||
companyId,
|
||||
invoiceId,
|
||||
transaction
|
||||
);
|
||||
if (proformaOrError.isFailure) {
|
||||
return Result.fail(proformaOrError.error);
|
||||
}
|
||||
|
||||
const proforma = proformaOrError.data;
|
||||
const pdfData = await pdfPresenter.toOutput(proforma);
|
||||
return Result.ok({
|
||||
data: pdfData,
|
||||
filename: `proforma-${proforma.invoiceNumber}.pdf`,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
return Result.fail(error as Error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,14 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
import { Presenter } from "@erp/core/api";
|
||||
import * as handlebars from "handlebars";
|
||||
import { CustomerInvoice } from "../../../../domain";
|
||||
import { CustomerInvoiceFullPresenter, CustomerInvoiceReportPresenter } from "../../../presenters";
|
||||
|
||||
import type { CustomerInvoice } from "../../../../../domain";
|
||||
import type {
|
||||
CustomerInvoiceFullPresenter,
|
||||
CustomerInvoiceReportPresenter,
|
||||
} from "../../../../presenters";
|
||||
|
||||
export class CustomerInvoiceReportHTMLPresenter extends Presenter {
|
||||
toOutput(customerInvoice: CustomerInvoice): string {
|
||||
@ -1,8 +1,10 @@
|
||||
import { Presenter } from "@erp/core/api";
|
||||
import puppeteer from "puppeteer";
|
||||
import report from "puppeteer-report";
|
||||
import { CustomerInvoice } from "../../../../domain";
|
||||
import { CustomerInvoiceReportHTMLPresenter } from "./customer-invoice.report.html";
|
||||
|
||||
import type { CustomerInvoice } from "../../../../../domain";
|
||||
|
||||
import type { CustomerInvoiceReportHTMLPresenter } from "./customer-invoice.report.html";
|
||||
|
||||
// https://plnkr.co/edit/lWk6Yd?preview
|
||||
|
||||
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@ -6,14 +6,14 @@ import {
|
||||
UniqueID,
|
||||
UtcDate,
|
||||
ValidationErrorCollection,
|
||||
ValidationErrorDetail,
|
||||
type ValidationErrorDetail,
|
||||
extractOrPushError,
|
||||
maybeFromNullableVO,
|
||||
} from "@repo/rdx-ddd";
|
||||
import { Result, isNullishOrEmpty, toPatchField } from "@repo/rdx-utils";
|
||||
|
||||
import { UpdateCustomerInvoiceByIdRequestDTO } from "../../../../common/dto";
|
||||
import { CustomerInvoicePatchProps, CustomerInvoiceSerie } from "../../../domain";
|
||||
import type { UpdateProformaByIdRequestDTO } from "../../../../../common/dto";
|
||||
import { type CustomerInvoicePatchProps, CustomerInvoiceSerie } from "../../../../domain";
|
||||
|
||||
/**
|
||||
* mapDTOToUpdateCustomerInvoicePatchProps
|
||||
@ -29,7 +29,7 @@ import { CustomerInvoicePatchProps, CustomerInvoiceSerie } from "../../../domain
|
||||
*
|
||||
*/
|
||||
|
||||
export function mapDTOToUpdateCustomerInvoicePatchProps(dto: UpdateCustomerInvoiceByIdRequestDTO) {
|
||||
export function mapDTOToUpdateCustomerInvoicePatchProps(dto: UpdateProformaByIdRequestDTO) {
|
||||
try {
|
||||
const errors: ValidationErrorDetail[] = [];
|
||||
const props: CustomerInvoicePatchProps = {};
|
||||
@ -1,17 +1,19 @@
|
||||
import { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import type { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { Transaction } from "sequelize";
|
||||
import { UpdateCustomerInvoiceByIdRequestDTO } from "../../../../common";
|
||||
import { CustomerInvoicePatchProps } from "../../../domain";
|
||||
import { CustomerInvoiceFullPresenter } from "../../presenters";
|
||||
import { CustomerInvoiceApplicationService } from "../../services/customer-invoice-application.service";
|
||||
import type { Transaction } from "sequelize";
|
||||
|
||||
import type { UpdateProformaByIdRequestDTO } from "../../../../../common";
|
||||
import type { CustomerInvoicePatchProps } from "../../../../domain";
|
||||
import type { CustomerInvoiceFullPresenter } from "../../../presenters";
|
||||
import type { CustomerInvoiceApplicationService } from "../../../services/customer-invoice-application.service";
|
||||
|
||||
import { mapDTOToUpdateCustomerInvoicePatchProps } from "./map-dto-to-update-customer-invoice-props";
|
||||
|
||||
type UpdateCustomerInvoiceUseCaseInput = {
|
||||
companyId: UniqueID;
|
||||
invoice_id: string;
|
||||
dto: UpdateCustomerInvoiceByIdRequestDTO;
|
||||
proforma_id: string;
|
||||
dto: UpdateProformaByIdRequestDTO;
|
||||
};
|
||||
|
||||
export class UpdateCustomerInvoiceUseCase {
|
||||
@ -22,9 +24,9 @@ export class UpdateCustomerInvoiceUseCase {
|
||||
) {}
|
||||
|
||||
public execute(params: UpdateCustomerInvoiceUseCaseInput) {
|
||||
const { companyId, invoice_id, dto } = params;
|
||||
const { companyId, proforma_id, dto } = params;
|
||||
|
||||
const idOrError = UniqueID.create(invoice_id);
|
||||
const idOrError = UniqueID.create(proforma_id);
|
||||
if (idOrError.isFailure) {
|
||||
return Result.fail(idOrError.error);
|
||||
}
|
||||
@ -45,7 +47,7 @@ export class UpdateCustomerInvoiceUseCase {
|
||||
|
||||
return this.transactionManager.complete(async (transaction: Transaction) => {
|
||||
try {
|
||||
const updatedInvoice = await this.service.patchInvoiceByIdInCompany(
|
||||
const updatedInvoice = await this.service.patchProformaByIdInCompany(
|
||||
companyId,
|
||||
invoiceId,
|
||||
patchProps,
|
||||
@ -56,7 +58,7 @@ export class UpdateCustomerInvoiceUseCase {
|
||||
return Result.fail(updatedInvoice.error);
|
||||
}
|
||||
|
||||
const invoiceOrError = await this.service.updateInvoiceInCompany(
|
||||
const invoiceOrError = await this.service.updateProformaInCompany(
|
||||
companyId,
|
||||
updatedInvoice.data,
|
||||
transaction
|
||||
@ -1,2 +0,0 @@
|
||||
export * from "./report-customer-invoice.use-case";
|
||||
export * from "./reporter";
|
||||
@ -1,21 +1,22 @@
|
||||
import {
|
||||
AggregateRoot,
|
||||
CurrencyCode,
|
||||
type CurrencyCode,
|
||||
DomainValidationError,
|
||||
LanguageCode,
|
||||
Percentage,
|
||||
TextValue,
|
||||
UniqueID,
|
||||
UtcDate,
|
||||
type LanguageCode,
|
||||
type Percentage,
|
||||
type TextValue,
|
||||
type UniqueID,
|
||||
type UtcDate,
|
||||
} from "@repo/rdx-ddd";
|
||||
import { Maybe, Result } from "@repo/rdx-utils";
|
||||
import { CustomerInvoiceItems, InvoicePaymentMethod, InvoiceTaxTotal } from "../entities";
|
||||
import { type Maybe, Result } from "@repo/rdx-utils";
|
||||
|
||||
import { CustomerInvoiceItems, type InvoicePaymentMethod, type InvoiceTaxTotal } from "../entities";
|
||||
import {
|
||||
CustomerInvoiceNumber,
|
||||
CustomerInvoiceSerie,
|
||||
CustomerInvoiceStatus,
|
||||
type CustomerInvoiceNumber,
|
||||
type CustomerInvoiceSerie,
|
||||
type CustomerInvoiceStatus,
|
||||
InvoiceAmount,
|
||||
InvoiceRecipient,
|
||||
type InvoiceRecipient,
|
||||
} from "../value-objects";
|
||||
|
||||
export interface CustomerInvoiceProps {
|
||||
@ -24,7 +25,7 @@ export interface CustomerInvoiceProps {
|
||||
isProforma: boolean;
|
||||
status: CustomerInvoiceStatus;
|
||||
|
||||
proformaId: Maybe<UniqueID>;
|
||||
proformaId: Maybe<UniqueID>; // <- proforma padre en caso de issue
|
||||
|
||||
series: Maybe<CustomerInvoiceSerie>;
|
||||
invoiceNumber: CustomerInvoiceNumber;
|
||||
@ -106,7 +107,7 @@ export class CustomerInvoice
|
||||
|
||||
// Reglas de negocio / validaciones
|
||||
|
||||
if (!customerInvoice.isProforma && !customerInvoice.hasRecipient) {
|
||||
if (!(customerInvoice.isProforma || customerInvoice.hasRecipient)) {
|
||||
return Result.fail(
|
||||
new DomainValidationError(
|
||||
"MISSING_CUSTOMER_DATA",
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { Criteria } from "@repo/rdx-criteria/server";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Collection, Result } from "@repo/rdx-utils";
|
||||
import { CustomerInvoiceListDTO } from "../../infrastructure";
|
||||
import { CustomerInvoice } from "../aggregates";
|
||||
import { CustomerInvoiceStatus } from "../value-objects";
|
||||
import type { Criteria } from "@repo/rdx-criteria/server";
|
||||
import type { UniqueID } from "@repo/rdx-ddd";
|
||||
import type { Collection, Result } from "@repo/rdx-utils";
|
||||
|
||||
import type { CustomerInvoiceListDTO } from "../../infrastructure";
|
||||
import type { CustomerInvoice } from "../aggregates";
|
||||
import type { CustomerInvoiceStatus } from "../value-objects";
|
||||
|
||||
/**
|
||||
* Interfaz del repositorio para el agregado `CustomerInvoice`.
|
||||
@ -45,7 +46,8 @@ export interface ICustomerInvoiceRepository {
|
||||
getByIdInCompany(
|
||||
companyId: UniqueID,
|
||||
id: UniqueID,
|
||||
transaction?: unknown
|
||||
transaction: unknown,
|
||||
options: unknown
|
||||
): Promise<Result<CustomerInvoice, Error>>;
|
||||
|
||||
/**
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import { IModuleServer, ModuleParams } from "@erp/core/api";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Transaction } from "sequelize";
|
||||
import { buildCustomerInvoiceDependencies, customerInvoicesRouter, models } from "./infrastructure";
|
||||
import type { IModuleServer, ModuleParams } from "@erp/core/api";
|
||||
import type { UniqueID } from "@repo/rdx-ddd";
|
||||
import type { Transaction } from "sequelize";
|
||||
|
||||
import { buildCustomerInvoiceDependencies, models, proformasRouter } from "./infrastructure";
|
||||
import { issueInvoicesRouter } from "./infrastructure/express/issue-invoices.routes";
|
||||
|
||||
export const customerInvoicesAPIModule: IModuleServer = {
|
||||
name: "customer-invoices",
|
||||
@ -11,7 +13,8 @@ export const customerInvoicesAPIModule: IModuleServer = {
|
||||
async init(params: ModuleParams) {
|
||||
// const contacts = getService<ContactsService>("contacts");
|
||||
const { logger } = params;
|
||||
customerInvoicesRouter(params);
|
||||
proformasRouter(params);
|
||||
issueInvoicesRouter(params);
|
||||
logger.info("🚀 CustomerInvoices module initialized", { label: this.name });
|
||||
},
|
||||
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
// modules/invoice/infrastructure/invoice-dependencies.factory.ts
|
||||
|
||||
import { JsonTaxCatalogProvider, SpainTaxCatalogProvider } from "@erp/core";
|
||||
import { type JsonTaxCatalogProvider, SpainTaxCatalogProvider } from "@erp/core";
|
||||
import type { IMapperRegistry, IPresenterRegistry, ModuleParams } from "@erp/core/api";
|
||||
import {
|
||||
InMemoryMapperRegistry,
|
||||
InMemoryPresenterRegistry,
|
||||
SequelizeTransactionManager,
|
||||
} from "@erp/core/api";
|
||||
|
||||
import {
|
||||
ChangeStatusCustomerInvoiceUseCase,
|
||||
CreateCustomerInvoiceUseCase,
|
||||
ChangeStatusProformaUseCase,
|
||||
CreateProformaUseCase,
|
||||
CustomerInvoiceApplicationService,
|
||||
CustomerInvoiceFullPresenter,
|
||||
CustomerInvoiceItemsFullPresenter,
|
||||
@ -17,14 +18,15 @@ import {
|
||||
CustomerInvoiceReportHTMLPresenter,
|
||||
CustomerInvoiceReportPDFPresenter,
|
||||
CustomerInvoiceReportPresenter,
|
||||
GetCustomerInvoiceUseCase,
|
||||
IssueCustomerInvoiceUseCase,
|
||||
GetProformaUseCase,
|
||||
IssueProformaInvoiceUseCase,
|
||||
ListCustomerInvoicesPresenter,
|
||||
ListCustomerInvoicesUseCase,
|
||||
ListProformasUseCase,
|
||||
RecipientInvoiceFullPresenter,
|
||||
ReportCustomerInvoiceUseCase,
|
||||
ReportProformaUseCase,
|
||||
UpdateCustomerInvoiceUseCase,
|
||||
} from "../application";
|
||||
|
||||
import { CustomerInvoiceDomainMapper, CustomerInvoiceListMapper } from "./mappers";
|
||||
import { CustomerInvoiceRepository } from "./sequelize";
|
||||
import { SequelizeInvoiceNumberGenerator } from "./services";
|
||||
@ -39,14 +41,14 @@ export type CustomerInvoiceDeps = {
|
||||
taxes: JsonTaxCatalogProvider;
|
||||
};
|
||||
useCases: {
|
||||
list: () => ListCustomerInvoicesUseCase;
|
||||
get: () => GetCustomerInvoiceUseCase;
|
||||
create: () => CreateCustomerInvoiceUseCase;
|
||||
list: () => ListProformasUseCase;
|
||||
get: () => GetProformaUseCase;
|
||||
create: () => CreateProformaUseCase;
|
||||
update: () => UpdateCustomerInvoiceUseCase;
|
||||
//delete: () => DeleteCustomerInvoiceUseCase;
|
||||
report: () => ReportCustomerInvoiceUseCase;
|
||||
issue: () => IssueCustomerInvoiceUseCase;
|
||||
changeStatus: () => ChangeStatusCustomerInvoiceUseCase;
|
||||
report: () => ReportProformaUseCase;
|
||||
issue: () => IssueProformaInvoiceUseCase;
|
||||
changeStatus: () => ChangeStatusProformaUseCase;
|
||||
};
|
||||
};
|
||||
|
||||
@ -117,21 +119,15 @@ export function buildCustomerInvoiceDependencies(params: ModuleParams): Customer
|
||||
]);
|
||||
|
||||
const useCases = {
|
||||
list: () => new ListCustomerInvoicesUseCase(appService, transactionManager, presenterRegistry),
|
||||
get: () => new GetCustomerInvoiceUseCase(appService, transactionManager, presenterRegistry),
|
||||
list: () => new ListProformasUseCase(appService, transactionManager, presenterRegistry),
|
||||
get: () => new GetProformaUseCase(appService, transactionManager, presenterRegistry),
|
||||
create: () =>
|
||||
new CreateCustomerInvoiceUseCase(
|
||||
appService,
|
||||
transactionManager,
|
||||
presenterRegistry,
|
||||
catalogs.taxes
|
||||
),
|
||||
new CreateProformaUseCase(appService, transactionManager, presenterRegistry, catalogs.taxes),
|
||||
update: () =>
|
||||
new UpdateCustomerInvoiceUseCase(appService, transactionManager, presenterRegistry),
|
||||
report: () =>
|
||||
new ReportCustomerInvoiceUseCase(appService, transactionManager, presenterRegistry),
|
||||
issue: () => new IssueCustomerInvoiceUseCase(appService, transactionManager, presenterRegistry),
|
||||
changeStatus: () => new ChangeStatusCustomerInvoiceUseCase(appService, transactionManager),
|
||||
report: () => new ReportProformaUseCase(appService, transactionManager, presenterRegistry),
|
||||
issue: () => new IssueProformaInvoiceUseCase(appService, transactionManager, presenterRegistry),
|
||||
changeStatus: () => new ChangeStatusProformaUseCase(appService, transactionManager),
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
import { authGuard, ExpressController, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
import { DeleteCustomerInvoiceUseCase } from "../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../customer-invoices-api-error-mapper";
|
||||
|
||||
export class DeleteCustomerInvoiceController extends ExpressController {
|
||||
public constructor(
|
||||
private readonly useCase: DeleteCustomerInvoiceUseCase
|
||||
/* private readonly presenter: any */
|
||||
) {
|
||||
super();
|
||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||
|
||||
// 🔐 Reutiliza guards de auth/tenant y prohíbe 'companyId' en query
|
||||
this.registerGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
||||
}
|
||||
|
||||
async executeImpl() {
|
||||
const tenantId = this.getTenantId()!; // garantizado por tenantGuard
|
||||
const { id } = this.req.params;
|
||||
|
||||
const result = await this.useCase.execute({ id, tenantId });
|
||||
|
||||
return result.match(
|
||||
(data) => this.ok(data),
|
||||
(err) => this.handleError(err)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,2 @@
|
||||
export * from "./change-status-customer-invoice.controller";
|
||||
export * from "./create-customer-invoice.controller";
|
||||
//export * from "./delete-customer-invoice.controller";
|
||||
export * from "./get-customer-invoice.controller";
|
||||
export * from "./issue-customer-invoice.controller";
|
||||
export * from "./list-customer-invoices.controller";
|
||||
export * from "./report-customer-invoice.controller";
|
||||
export * from "./update-customer-invoice.controller";
|
||||
export * from "./issue-invoices";
|
||||
export * from "./proformas";
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { authGuard, ExpressController, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
import { GetCustomerInvoiceUseCase } from "../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../customer-invoices-api-error-mapper";
|
||||
import { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
|
||||
export class GetCustomerInvoiceController extends ExpressController {
|
||||
public constructor(private readonly useCase: GetCustomerInvoiceUseCase) {
|
||||
import type { GetProformaUseCase } from "../../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||
|
||||
export class GetIssueInvoiceController extends ExpressController {
|
||||
public constructor(private readonly useCase: GetProformaUseCase) {
|
||||
super();
|
||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||
|
||||
@ -18,7 +19,7 @@ export class GetCustomerInvoiceController extends ExpressController {
|
||||
}
|
||||
const { invoice_id } = this.req.params;
|
||||
|
||||
const result = await this.useCase.execute({ invoice_id, companyId });
|
||||
const result = await this.useCase.execute({ proforma_id: invoice_id, companyId });
|
||||
|
||||
return result.match(
|
||||
(data) => this.ok(data),
|
||||
@ -0,0 +1,2 @@
|
||||
export * from "./get-issue-invoice.controller";
|
||||
export * from "./list-issue-invoices.controller";
|
||||
@ -1,10 +1,11 @@
|
||||
import { authGuard, ExpressController, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
import { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
import { Criteria } from "@repo/rdx-criteria/server";
|
||||
import { ListCustomerInvoicesUseCase } from "../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../customer-invoices-api-error-mapper";
|
||||
|
||||
export class ListCustomerInvoicesController extends ExpressController {
|
||||
public constructor(private readonly useCase: ListCustomerInvoicesUseCase) {
|
||||
import type { ListProformasUseCase } from "../../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||
|
||||
export class ListIssueInvoicesController extends ExpressController {
|
||||
public constructor(private readonly useCase: ListProformasUseCase) {
|
||||
super();
|
||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { authGuard, ExpressController, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
import { ChangeStatusCustomerInvoiceByIdRequestDTO } from "@erp/customer-invoices/common";
|
||||
import { ChangeStatusCustomerInvoiceUseCase } from "../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../customer-invoices-api-error-mapper";
|
||||
import { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
|
||||
export class ChangeStatusCustomerInvoiceController extends ExpressController {
|
||||
public constructor(private readonly useCase: ChangeStatusCustomerInvoiceUseCase) {
|
||||
import type { ChangeStatusProformaByIdRequestDTO } from "../../../../../common/dto";
|
||||
import type { ChangeStatusProformaUseCase } from "../../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||
|
||||
export class ChangeStatusProformaController extends ExpressController {
|
||||
public constructor(private readonly useCase: ChangeStatusProformaUseCase) {
|
||||
super();
|
||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||
|
||||
@ -12,7 +13,7 @@ export class ChangeStatusCustomerInvoiceController extends ExpressController {
|
||||
this.registerGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
||||
}
|
||||
|
||||
async executeImpl(): Promise<any> {
|
||||
protected async executeImpl() {
|
||||
const companyId = this.getTenantId(); // garantizado por tenantGuard
|
||||
if (!companyId) {
|
||||
return this.forbiddenError("Tenant ID not found");
|
||||
@ -23,7 +24,7 @@ export class ChangeStatusCustomerInvoiceController extends ExpressController {
|
||||
return this.invalidInputError("Proforma ID missing");
|
||||
}
|
||||
|
||||
const dto = this.req.body as ChangeStatusCustomerInvoiceByIdRequestDTO;
|
||||
const dto = this.req.body as ChangeStatusProformaByIdRequestDTO;
|
||||
const result = await this.useCase.execute({ proforma_id, dto, companyId });
|
||||
|
||||
return result.match(
|
||||
@ -1,11 +1,11 @@
|
||||
import { authGuard, ExpressController, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
import { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
|
||||
import { CreateCustomerInvoiceRequestDTO } from "../../../../common/dto";
|
||||
import { CreateCustomerInvoiceUseCase } from "../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../customer-invoices-api-error-mapper";
|
||||
import type { CreateProformaRequestDTO } from "../../../../../common/dto";
|
||||
import type { CreateProformaUseCase } from "../../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||
|
||||
export class CreateCustomerInvoiceController extends ExpressController {
|
||||
public constructor(private readonly useCase: CreateCustomerInvoiceUseCase) {
|
||||
export class CreateProformaController extends ExpressController {
|
||||
public constructor(private readonly useCase: CreateProformaUseCase) {
|
||||
super();
|
||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||
|
||||
@ -18,7 +18,7 @@ export class CreateCustomerInvoiceController extends ExpressController {
|
||||
if (!companyId) {
|
||||
return this.forbiddenError("Tenant ID not found");
|
||||
}
|
||||
const dto = this.req.body as CreateCustomerInvoiceRequestDTO;
|
||||
const dto = this.req.body as CreateProformaRequestDTO;
|
||||
|
||||
const result = await this.useCase.execute({ dto, companyId });
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
import { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
|
||||
import type { DeleteProformaUseCase } from "../../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||
|
||||
export class DeleteProformaController extends ExpressController {
|
||||
public constructor(
|
||||
private readonly useCase: DeleteProformaUseCase
|
||||
/* private readonly presenter: any */
|
||||
) {
|
||||
super();
|
||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||
|
||||
// 🔐 Reutiliza guards de auth/tenant y prohíbe 'companyId' en query
|
||||
this.registerGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
||||
}
|
||||
|
||||
protected async executeImpl() {
|
||||
const companyId = this.getTenantId();
|
||||
if (!companyId) {
|
||||
return this.forbiddenError("Tenant ID not found");
|
||||
}
|
||||
|
||||
const { proforma_id } = this.req.params;
|
||||
|
||||
const result = await this.useCase.execute({ proforma_id, companyId });
|
||||
|
||||
return result.match(
|
||||
(data) => this.ok(data),
|
||||
(err) => this.handleError(err)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
import { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
|
||||
import type { GetProformaUseCase } from "../../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||
|
||||
export class GetProformaController extends ExpressController {
|
||||
public constructor(private readonly useCase: GetProformaUseCase) {
|
||||
super();
|
||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||
|
||||
// 🔐 Reutiliza guards de auth/tenant y prohíbe 'companyId' en query
|
||||
this.registerGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
||||
}
|
||||
|
||||
protected async executeImpl() {
|
||||
const companyId = this.getTenantId();
|
||||
if (!companyId) {
|
||||
return this.forbiddenError("Tenant ID not found");
|
||||
}
|
||||
const { proforma_id } = this.req.params;
|
||||
|
||||
const result = await this.useCase.execute({ proforma_id, companyId });
|
||||
|
||||
return result.match(
|
||||
(data) => this.ok(data),
|
||||
(err) => this.handleError(err)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
export * from "./change-status-proforma.controller";
|
||||
export * from "./create-proforma.controller";
|
||||
export * from "./delete-proforma.controller";
|
||||
export * from "./get-proforma.controller";
|
||||
export * from "./issue-proforma.controller";
|
||||
export * from "./list-proformas.controller";
|
||||
export * from "./report-proforma.controller";
|
||||
export * from "./update-proforma.controller";
|
||||
@ -1,9 +1,10 @@
|
||||
import { authGuard, ExpressController, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
import { IssueCustomerInvoiceUseCase } from "../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../customer-invoices-api-error-mapper";
|
||||
import { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
|
||||
export class IssueCustomerInvoiceController extends ExpressController {
|
||||
public constructor(private readonly useCase: IssueCustomerInvoiceUseCase) {
|
||||
import type { IssueProformaInvoiceUseCase } from "../../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||
|
||||
export class IssueProformaController extends ExpressController {
|
||||
public constructor(private readonly useCase: IssueProformaInvoiceUseCase) {
|
||||
super();
|
||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||
|
||||
@ -11,7 +12,7 @@ export class IssueCustomerInvoiceController extends ExpressController {
|
||||
this.registerGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
||||
}
|
||||
|
||||
async executeImpl(): Promise<any> {
|
||||
protected async executeImpl() {
|
||||
const companyId = this.getTenantId(); // garantizado por tenantGuard
|
||||
if (!companyId) {
|
||||
return this.forbiddenError("Tenant ID not found");
|
||||
@ -0,0 +1,52 @@
|
||||
import { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
import { Criteria } from "@repo/rdx-criteria/server";
|
||||
|
||||
import type { ListProformasUseCase } from "../../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||
|
||||
export class ListProformasController extends ExpressController {
|
||||
public constructor(private readonly useCase: ListProformasUseCase) {
|
||||
super();
|
||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||
|
||||
// 🔐 Reutiliza guards de auth/tenant y prohíbe 'companyId' en query
|
||||
this.registerGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
||||
}
|
||||
|
||||
private getCriteriaWithDefaultOrder() {
|
||||
if (this.criteria.hasOrder()) {
|
||||
return this.criteria;
|
||||
}
|
||||
|
||||
const { q: quicksearch, filters, pageSize, pageNumber } = this.criteria.toPrimitives();
|
||||
return Criteria.fromPrimitives(
|
||||
filters,
|
||||
"invoice_date",
|
||||
"DESC",
|
||||
pageSize,
|
||||
pageNumber,
|
||||
quicksearch
|
||||
);
|
||||
}
|
||||
|
||||
protected async executeImpl() {
|
||||
const companyId = this.getTenantId();
|
||||
if (!companyId) {
|
||||
return this.forbiddenError("Tenant ID not found");
|
||||
}
|
||||
|
||||
const criteria = this.getCriteriaWithDefaultOrder();
|
||||
const result = await this.useCase.execute({ criteria, companyId });
|
||||
|
||||
return result.match(
|
||||
(data) =>
|
||||
this.ok(data, {
|
||||
"X-Total-Count": String(data.total_items),
|
||||
"Pagination-Count": String(data.total_pages),
|
||||
"Pagination-Page": String(data.page),
|
||||
"Pagination-Limit": String(data.per_page),
|
||||
}),
|
||||
(err) => this.handleError(err)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,10 @@
|
||||
import { authGuard, ExpressController, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
import { ReportCustomerInvoiceUseCase } from "../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../customer-invoices-api-error-mapper";
|
||||
import { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
|
||||
export class ReportCustomerInvoiceController extends ExpressController {
|
||||
public constructor(private readonly useCase: ReportCustomerInvoiceUseCase) {
|
||||
import type { ReportProformaUseCase } from "../../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||
|
||||
export class ReportProformaController extends ExpressController {
|
||||
public constructor(private readonly useCase: ReportProformaUseCase) {
|
||||
super();
|
||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||
|
||||
@ -16,9 +17,9 @@ export class ReportCustomerInvoiceController extends ExpressController {
|
||||
if (!companyId) {
|
||||
return this.forbiddenError("Tenant ID not found");
|
||||
}
|
||||
const { invoice_id } = this.req.params;
|
||||
const { proforma_id } = this.req.params;
|
||||
|
||||
const result = await this.useCase.execute({ invoice_id, companyId });
|
||||
const result = await this.useCase.execute({ proforma_id, companyId });
|
||||
|
||||
return result.match(
|
||||
({ data, filename }) => this.downloadPDF(data, filename),
|
||||
@ -1,9 +1,10 @@
|
||||
import { authGuard, ExpressController, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
import { UpdateCustomerInvoiceByIdRequestDTO } from "../../../../common/dto";
|
||||
import { UpdateCustomerInvoiceUseCase } from "../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../customer-invoices-api-error-mapper";
|
||||
import { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||
|
||||
export class UpdateCustomerInvoiceController extends ExpressController {
|
||||
import type { UpdateProformaByIdRequestDTO } from "../../../../../common/dto";
|
||||
import type { UpdateCustomerInvoiceUseCase } from "../../../../application";
|
||||
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||
|
||||
export class UpdateProformaController extends ExpressController {
|
||||
public constructor(private readonly useCase: UpdateCustomerInvoiceUseCase) {
|
||||
super();
|
||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||
@ -12,7 +13,7 @@ export class UpdateCustomerInvoiceController extends ExpressController {
|
||||
this.registerGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
||||
}
|
||||
|
||||
async executeImpl(): Promise<any> {
|
||||
protected async executeImpl() {
|
||||
const companyId = this.getTenantId();
|
||||
if (!companyId) {
|
||||
return this.forbiddenError("Tenant ID not found");
|
||||
@ -23,9 +24,9 @@ export class UpdateCustomerInvoiceController extends ExpressController {
|
||||
return this.invalidInputError("Proforma ID missing");
|
||||
}
|
||||
|
||||
const dto = this.req.body as UpdateCustomerInvoiceByIdRequestDTO;
|
||||
const dto = this.req.body as UpdateProformaByIdRequestDTO;
|
||||
|
||||
const result = await this.useCase.execute({ invoice_id: proforma_id, companyId, dto });
|
||||
const result = await this.useCase.execute({ proforma_id, companyId, dto });
|
||||
|
||||
return result.match(
|
||||
(data) => this.ok(data),
|
||||
@ -4,16 +4,17 @@
|
||||
import {
|
||||
ApiErrorMapper,
|
||||
ConflictApiError,
|
||||
ErrorToApiRule,
|
||||
type ErrorToApiRule,
|
||||
ValidationApiError,
|
||||
} from "@erp/core/api";
|
||||
|
||||
import {
|
||||
CustomerInvoiceIdAlreadyExistsError,
|
||||
EntityIsNotProformaError,
|
||||
type CustomerInvoiceIdAlreadyExistsError,
|
||||
type EntityIsNotProformaError,
|
||||
type ProformaCannotBeConvertedToInvoiceError,
|
||||
isCustomerInvoiceIdAlreadyExistsError,
|
||||
isEntityIsNotProformaError,
|
||||
isProformaCannotBeConvertedToInvoiceError,
|
||||
ProformaCannotBeConvertedToInvoiceError,
|
||||
} from "../../domain";
|
||||
|
||||
// Crea una regla específica (prioridad alta para sobreescribir mensajes)
|
||||
|
||||
@ -1 +1,2 @@
|
||||
export * from "./customer-invoices.routes";
|
||||
export * from "./issue-invoices.routes";
|
||||
export * from "./proformas.routes";
|
||||
|
||||
@ -0,0 +1,83 @@
|
||||
import { type RequestWithAuth, enforceTenant, enforceUser, mockUser } from "@erp/auth/api";
|
||||
import { type ModuleParams, validateRequest } from "@erp/core/api";
|
||||
import type { ILogger } from "@repo/rdx-logger";
|
||||
import { type Application, type NextFunction, type Request, type Response, Router } from "express";
|
||||
import type { Sequelize } from "sequelize";
|
||||
|
||||
import {
|
||||
GetIssueInvoiceByIdRequestSchema,
|
||||
ListIssueInvoicesRequestSchema,
|
||||
ReportIssueInvoiceByIdRequestSchema,
|
||||
} from "../../../common/dto";
|
||||
import { buildCustomerInvoiceDependencies } from "../dependencies";
|
||||
|
||||
import {
|
||||
GetProformaController,
|
||||
ListProformasController,
|
||||
ReportProformaController,
|
||||
} from "./controllers";
|
||||
|
||||
export const issueInvoicesRouter = (params: ModuleParams) => {
|
||||
const { app, baseRoutePath, logger } = params as {
|
||||
app: Application;
|
||||
database: Sequelize;
|
||||
baseRoutePath: string;
|
||||
logger: ILogger;
|
||||
};
|
||||
|
||||
const deps = buildCustomerInvoiceDependencies(params);
|
||||
|
||||
const router: Router = Router({ mergeParams: true });
|
||||
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "production") {
|
||||
// 🔐 Autenticación + Tenancy para TODO el router
|
||||
router.use(
|
||||
(req: Request, res: Response, next: NextFunction) =>
|
||||
mockUser(req as RequestWithAuth, res, next) // Debe ir antes de las rutas protegidas
|
||||
);
|
||||
}
|
||||
|
||||
router.use([
|
||||
(req: Request, res: Response, next: NextFunction) =>
|
||||
enforceUser()(req as RequestWithAuth, res, next), // Debe ir antes de las rutas protegidas
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) =>
|
||||
enforceTenant()(req as RequestWithAuth, res, next), // Debe ir antes de las rutas protegidas
|
||||
]);
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
router.get(
|
||||
"/",
|
||||
//checkTabContext,
|
||||
validateRequest(ListIssueInvoicesRequestSchema, "params"),
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
const useCase = deps.useCases.list();
|
||||
const controller = new ListProformasController(useCase /*, deps.presenters.list */);
|
||||
return controller.execute(req, res, next);
|
||||
}
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/:invoice_id",
|
||||
//checkTabContext,
|
||||
validateRequest(GetIssueInvoiceByIdRequestSchema, "params"),
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const useCase = deps.useCases.get();
|
||||
const controller = new GetProformaController(useCase);
|
||||
return controller.execute(req, res, next);
|
||||
}
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/:invoice_id/report",
|
||||
//checkTabContext,
|
||||
validateRequest(ReportIssueInvoiceByIdRequestSchema, "params"),
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const useCase = deps.useCases.report();
|
||||
const controller = new ReportProformaController(useCase);
|
||||
return controller.execute(req, res, next);
|
||||
}
|
||||
);
|
||||
|
||||
app.use(`${baseRoutePath}/customer-invoices`, router);
|
||||
};
|
||||
@ -1,30 +1,32 @@
|
||||
import { enforceTenant, enforceUser, mockUser, RequestWithAuth } from "@erp/auth/api";
|
||||
import { ModuleParams, validateRequest } from "@erp/core/api";
|
||||
import { ILogger } from "@repo/rdx-logger";
|
||||
import { Application, NextFunction, Request, Response, Router } from "express";
|
||||
import { Sequelize } from "sequelize";
|
||||
import { type RequestWithAuth, enforceTenant, enforceUser, mockUser } from "@erp/auth/api";
|
||||
import { type ModuleParams, validateRequest } from "@erp/core/api";
|
||||
import {
|
||||
ChangeStatusCustomerInvoiceByIdParamsRequestSchema,
|
||||
ChangeStatusCustomerInvoiceByIdRequestSchema,
|
||||
CreateCustomerInvoiceRequestSchema,
|
||||
CustomerInvoiceListRequestSchema,
|
||||
GetCustomerInvoiceByIdRequestSchema,
|
||||
ReportCustomerInvoiceByIdRequestSchema,
|
||||
UpdateCustomerInvoiceByIdParamsRequestSchema,
|
||||
UpdateCustomerInvoiceByIdRequestSchema,
|
||||
} from "../../../common/dto";
|
||||
import { buildCustomerInvoiceDependencies } from "../dependencies";
|
||||
import {
|
||||
ChangeStatusCustomerInvoiceController,
|
||||
CreateCustomerInvoiceController,
|
||||
GetCustomerInvoiceController,
|
||||
ListCustomerInvoicesController,
|
||||
ReportCustomerInvoiceController,
|
||||
UpdateCustomerInvoiceController,
|
||||
} from "./controllers";
|
||||
import { IssueCustomerInvoiceController } from "./controllers/issue-customer-invoice.controller";
|
||||
ChangeStatusProformaByIdParamsRequestSchema,
|
||||
ChangeStatusProformaByIdRequestSchema,
|
||||
CreateProformaRequestSchema,
|
||||
GetProformaByIdRequestSchema,
|
||||
ListProformasRequestSchema,
|
||||
ReportProformaByIdRequestSchema,
|
||||
UpdateProformaByIdParamsRequestSchema,
|
||||
UpdateProformaByIdRequestSchema,
|
||||
} from "@erp/customer-invoices/common";
|
||||
import type { ILogger } from "@repo/rdx-logger";
|
||||
import { type Application, type NextFunction, type Request, type Response, Router } from "express";
|
||||
import type { Sequelize } from "sequelize";
|
||||
|
||||
export const customerInvoicesRouter = (params: ModuleParams) => {
|
||||
import { buildCustomerInvoiceDependencies } from "../dependencies";
|
||||
|
||||
import {
|
||||
ChangeStatusProformaController,
|
||||
CreateProformaController,
|
||||
GetProformaController,
|
||||
ListProformasController,
|
||||
ReportProformaController,
|
||||
UpdateProformaController,
|
||||
} from "./controllers/proformas";
|
||||
import { IssueProformaController } from "./controllers/proformas/issue-proforma.controller";
|
||||
|
||||
export const proformasRouter = (params: ModuleParams) => {
|
||||
const { app, baseRoutePath, logger } = params as {
|
||||
app: Application;
|
||||
database: Sequelize;
|
||||
@ -56,21 +58,21 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
||||
router.get(
|
||||
"/",
|
||||
//checkTabContext,
|
||||
validateRequest(CustomerInvoiceListRequestSchema, "params"),
|
||||
validateRequest(ListProformasRequestSchema, "params"),
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
const useCase = deps.useCases.list();
|
||||
const controller = new ListCustomerInvoicesController(useCase /*, deps.presenters.list */);
|
||||
const controller = new ListProformasController(useCase /*, deps.presenters.list */);
|
||||
return controller.execute(req, res, next);
|
||||
}
|
||||
);
|
||||
|
||||
router.get(
|
||||
"/:invoice_id",
|
||||
"/:proforma_id",
|
||||
//checkTabContext,
|
||||
validateRequest(GetCustomerInvoiceByIdRequestSchema, "params"),
|
||||
validateRequest(GetProformaByIdRequestSchema, "params"),
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const useCase = deps.useCases.get();
|
||||
const controller = new GetCustomerInvoiceController(useCase);
|
||||
const controller = new GetProformaController(useCase);
|
||||
return controller.execute(req, res, next);
|
||||
}
|
||||
);
|
||||
@ -79,10 +81,10 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
||||
"/",
|
||||
//checkTabContext,
|
||||
|
||||
validateRequest(CreateCustomerInvoiceRequestSchema, "body"),
|
||||
validateRequest(CreateProformaRequestSchema, "body"),
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const useCase = deps.useCases.create();
|
||||
const controller = new CreateCustomerInvoiceController(useCase);
|
||||
const controller = new CreateProformaController(useCase);
|
||||
return controller.execute(req, res, next);
|
||||
}
|
||||
);
|
||||
@ -91,17 +93,17 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
||||
"/:proforma_id",
|
||||
//checkTabContext,
|
||||
|
||||
validateRequest(UpdateCustomerInvoiceByIdParamsRequestSchema, "params"),
|
||||
validateRequest(UpdateCustomerInvoiceByIdRequestSchema, "body"),
|
||||
validateRequest(UpdateProformaByIdParamsRequestSchema, "params"),
|
||||
validateRequest(UpdateProformaByIdRequestSchema, "body"),
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const useCase = deps.useCases.update();
|
||||
const controller = new UpdateCustomerInvoiceController(useCase);
|
||||
const controller = new UpdateProformaController(useCase);
|
||||
return controller.execute(req, res, next);
|
||||
}
|
||||
);
|
||||
|
||||
/*router.delete(
|
||||
"/:invoice_id",
|
||||
"/:proforma_id",
|
||||
//checkTabContext,
|
||||
|
||||
validateRequest(DeleteCustomerInvoiceByIdRequestSchema, "params"),
|
||||
@ -113,12 +115,12 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
||||
);*/
|
||||
|
||||
router.get(
|
||||
"/:invoice_id/report",
|
||||
"/:proforma_id/report",
|
||||
//checkTabContext,
|
||||
validateRequest(ReportCustomerInvoiceByIdRequestSchema, "params"),
|
||||
validateRequest(ReportProformaByIdRequestSchema, "params"),
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const useCase = deps.useCases.report();
|
||||
const controller = new ReportCustomerInvoiceController(useCase);
|
||||
const controller = new ReportProformaController(useCase);
|
||||
return controller.execute(req, res, next);
|
||||
}
|
||||
);
|
||||
@ -127,12 +129,12 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
||||
"/:proforma_id/status",
|
||||
//checkTabContext,
|
||||
|
||||
validateRequest(ChangeStatusCustomerInvoiceByIdParamsRequestSchema, "params"),
|
||||
validateRequest(ChangeStatusCustomerInvoiceByIdRequestSchema, "body"),
|
||||
validateRequest(ChangeStatusProformaByIdParamsRequestSchema, "params"),
|
||||
validateRequest(ChangeStatusProformaByIdRequestSchema, "body"),
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const useCase = deps.useCases.changeStatus();
|
||||
const controller = new ChangeStatusCustomerInvoiceController(useCase);
|
||||
const controller = new ChangeStatusProformaController(useCase);
|
||||
return controller.execute(req, res, next);
|
||||
}
|
||||
);
|
||||
@ -146,10 +148,10 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
||||
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const useCase = deps.useCases.issue();
|
||||
const controller = new IssueCustomerInvoiceController(useCase);
|
||||
const controller = new IssueProformaController(useCase);
|
||||
return controller.execute(req, res, next);
|
||||
}
|
||||
);
|
||||
|
||||
app.use(`${baseRoutePath}/customer-invoices`, router);
|
||||
app.use(`${baseRoutePath}/proformas`, router);
|
||||
};
|
||||
@ -4,16 +4,22 @@ import {
|
||||
SequelizeRepository,
|
||||
translateSequelizeError,
|
||||
} from "@erp/core/api";
|
||||
import { Criteria, CriteriaToSequelizeConverter } from "@repo/rdx-criteria/server";
|
||||
import { UniqueID } from "@repo/rdx-ddd";
|
||||
import { Collection, Result } from "@repo/rdx-utils";
|
||||
import { Transaction } from "sequelize";
|
||||
import { CustomerInvoice, CustomerInvoiceStatus, ICustomerInvoiceRepository } from "../../domain";
|
||||
import {
|
||||
import { type Criteria, CriteriaToSequelizeConverter } from "@repo/rdx-criteria/server";
|
||||
import type { UniqueID } from "@repo/rdx-ddd";
|
||||
import { type Collection, Result } from "@repo/rdx-utils";
|
||||
import type { FindOptions, InferAttributes, Transaction } from "sequelize";
|
||||
|
||||
import type {
|
||||
CustomerInvoice,
|
||||
CustomerInvoiceStatus,
|
||||
ICustomerInvoiceRepository,
|
||||
} from "../../domain";
|
||||
import type {
|
||||
CustomerInvoiceListDTO,
|
||||
ICustomerInvoiceDomainMapper,
|
||||
ICustomerInvoiceListMapper,
|
||||
} from "../mappers";
|
||||
|
||||
import { CustomerInvoiceModel } from "./models/customer-invoice.model";
|
||||
import { CustomerInvoiceItemModel } from "./models/customer-invoice-item.model";
|
||||
import { CustomerInvoiceItemTaxModel } from "./models/customer-invoice-item-tax.model";
|
||||
@ -185,12 +191,14 @@ export class CustomerInvoiceRepository
|
||||
* @param companyId - Identificador UUID de la empresa a la que pertenece la factura.
|
||||
* @param id - UUID de la factura.
|
||||
* @param transaction - Transacción activa para la operación.
|
||||
* @params options - Opciones adicionales para la consulta (Sequelize FindOptions)
|
||||
* @returns Result<CustomerInvoice, Error>
|
||||
*/
|
||||
async getByIdInCompany(
|
||||
companyId: UniqueID,
|
||||
id: UniqueID,
|
||||
transaction: Transaction
|
||||
transaction: Transaction,
|
||||
options: FindOptions<InferAttributes<CustomerInvoiceModel>> = {}
|
||||
): Promise<Result<CustomerInvoice, Error>> {
|
||||
const { CustomerModel } = this._database.models;
|
||||
|
||||
@ -199,14 +207,36 @@ export class CustomerInvoiceRepository
|
||||
resource: "customer-invoice",
|
||||
});
|
||||
|
||||
const row = await CustomerInvoiceModel.findOne({
|
||||
where: { id: id.toString(), company_id: companyId.toString() },
|
||||
order: [[{ model: CustomerInvoiceItemModel, as: "items" }, "position", "ASC"]],
|
||||
// Normalización defensiva de order/include
|
||||
const normalizedOrder = Array.isArray(options.order)
|
||||
? options.order
|
||||
: options.order
|
||||
? [options.order]
|
||||
: [];
|
||||
|
||||
const normalizedInclude = Array.isArray(options.include)
|
||||
? options.include
|
||||
: options.include
|
||||
? [options.include]
|
||||
: [];
|
||||
|
||||
const mergedOptions: FindOptions<InferAttributes<CustomerInvoiceModel>> = {
|
||||
...options,
|
||||
where: {
|
||||
id: id.toString(),
|
||||
company_id: companyId.toString(),
|
||||
...(options.where ?? {}),
|
||||
},
|
||||
order: [
|
||||
...normalizedOrder,
|
||||
[{ model: CustomerInvoiceItemModel, as: "items" }, "position", "ASC"],
|
||||
],
|
||||
include: [
|
||||
...normalizedInclude,
|
||||
{
|
||||
model: CustomerModel,
|
||||
as: "current_customer",
|
||||
required: false, // false => LEFT JOIN
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
model: CustomerInvoiceItemModel,
|
||||
@ -227,7 +257,9 @@ export class CustomerInvoiceRepository
|
||||
},
|
||||
],
|
||||
transaction,
|
||||
});
|
||||
};
|
||||
|
||||
const row = await CustomerInvoiceModel.findOne(mergedOptions);
|
||||
|
||||
if (!row) {
|
||||
return Result.fail(new EntityNotFoundError("CustomerInvoice", "id", id.toString()));
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const ChangeStatusCustomerInvoiceByIdParamsRequestSchema = z.object({
|
||||
proforma_id: z.string(),
|
||||
});
|
||||
|
||||
export const ChangeStatusCustomerInvoiceByIdRequestSchema = z.object({
|
||||
new_status: z.string(),
|
||||
});
|
||||
|
||||
export type ChangeStatusCustomerInvoiceByIdRequestDTO = Partial<
|
||||
z.infer<typeof ChangeStatusCustomerInvoiceByIdRequestSchema>
|
||||
>;
|
||||
@ -1,5 +0,0 @@
|
||||
import { CriteriaSchema } from "@erp/core";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const CustomerInvoiceListRequestSchema = CriteriaSchema;
|
||||
export type CustomerInvoiceListRequestDTO = z.infer<typeof CustomerInvoiceListRequestSchema>;
|
||||
@ -1,15 +0,0 @@
|
||||
import { z } from "zod/v4";
|
||||
|
||||
/**
|
||||
* Este DTO es utilizado por el endpoint:
|
||||
* `DELETE /customer-invoices/:id` (eliminar una factura por ID).
|
||||
*
|
||||
*/
|
||||
|
||||
export const DeleteCustomerInvoiceByIdRequestSchema = z.object({
|
||||
id: z.string(),
|
||||
});
|
||||
|
||||
export type DeleteCustomerInvoiceByIdRequestDTO = z.infer<
|
||||
typeof DeleteCustomerInvoiceByIdRequestSchema
|
||||
>;
|
||||
@ -1,7 +0,0 @@
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const GetCustomerInvoiceByIdRequestSchema = z.object({
|
||||
invoice_id: z.string(),
|
||||
});
|
||||
|
||||
export type GetCustomerInvoiceByIdRequestDTO = z.infer<typeof GetCustomerInvoiceByIdRequestSchema>;
|
||||
@ -1,7 +1,2 @@
|
||||
export * from "./change-status-customer-invoice-by-id.request.dto";
|
||||
export * from "./create-customer-invoice.request.dto";
|
||||
export * from "./customer-invoices-list.request.dto";
|
||||
export * from "./delete-customer-invoice-by-id.request.dto";
|
||||
export * from "./get-customer-invoice-by-id.request.dto";
|
||||
export * from "./report-customer-invoice-by-id.request.dto";
|
||||
export * from "./update-customer-invoice-by-id.request.dto";
|
||||
export * from "./issue-invoices";
|
||||
export * from "./proformas";
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const GetIssueInvoiceByIdRequestSchema = z.object({
|
||||
invoice_id: z.string(),
|
||||
});
|
||||
|
||||
export type GetIssueInvoiceByIdRequestDTO = z.infer<typeof GetIssueInvoiceByIdRequestSchema>;
|
||||
@ -0,0 +1,3 @@
|
||||
export * from "./get-issue-invoice-by-id.request.dto";
|
||||
export * from "./list-issue-invoices.request.dto";
|
||||
export * from "./report-issue-invoice-by-id.request.dto";
|
||||
@ -0,0 +1,5 @@
|
||||
import { CriteriaSchema } from "@erp/core";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const ListIssueInvoicesRequestSchema = CriteriaSchema;
|
||||
export type ListIssueInvoicesRequestDTO = z.infer<typeof ListIssueInvoicesRequestSchema>;
|
||||
@ -0,0 +1,7 @@
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const ReportIssueInvoiceByIdRequestSchema = z.object({
|
||||
invoice_id: z.string(),
|
||||
});
|
||||
|
||||
export type ReportIssueInvoiceByIdRequestDTO = z.infer<typeof ReportIssueInvoiceByIdRequestSchema>;
|
||||
@ -0,0 +1,13 @@
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const ChangeStatusProformaByIdParamsRequestSchema = z.object({
|
||||
proforma_id: z.string(),
|
||||
});
|
||||
|
||||
export const ChangeStatusProformaByIdRequestSchema = z.object({
|
||||
new_status: z.string(),
|
||||
});
|
||||
|
||||
export type ChangeStatusProformaByIdRequestDTO = Partial<
|
||||
z.infer<typeof ChangeStatusProformaByIdRequestSchema>
|
||||
>;
|
||||
@ -1,7 +1,7 @@
|
||||
import { NumericStringSchema, PercentageSchema } from "@erp/core";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const CreateCustomerInvoiceItemRequestSchema = z.object({
|
||||
export const CreateProformaItemRequestSchema = z.object({
|
||||
id: z.uuid(),
|
||||
position: z.string(),
|
||||
description: z.string().default(""),
|
||||
@ -10,8 +10,9 @@ export const CreateCustomerInvoiceItemRequestSchema = z.object({
|
||||
discount_percentage: NumericStringSchema.default(""),
|
||||
taxes: z.string().default(""),
|
||||
});
|
||||
export type CreateProformaItemRequestDTO = z.infer<typeof CreateProformaItemRequestSchema>;
|
||||
|
||||
export const CreateCustomerInvoiceRequestSchema = z.object({
|
||||
export const CreateProformaRequestSchema = z.object({
|
||||
id: z.uuid(),
|
||||
|
||||
invoice_number: z.string(),
|
||||
@ -35,10 +36,6 @@ export const CreateCustomerInvoiceRequestSchema = z.object({
|
||||
|
||||
payment_method: z.string().default(""),
|
||||
|
||||
items: z.array(CreateCustomerInvoiceItemRequestSchema).default([]),
|
||||
items: z.array(CreateProformaItemRequestSchema).default([]),
|
||||
});
|
||||
|
||||
export type CreateCustomerInvoiceItemRequestDTO = z.infer<
|
||||
typeof CreateCustomerInvoiceItemRequestSchema
|
||||
>;
|
||||
export type CreateCustomerInvoiceRequestDTO = z.infer<typeof CreateCustomerInvoiceRequestSchema>;
|
||||
export type CreateProformaRequestDTO = z.infer<typeof CreateProformaRequestSchema>;
|
||||
@ -0,0 +1,13 @@
|
||||
import { z } from "zod/v4";
|
||||
|
||||
/**
|
||||
* Este DTO es utilizado por el endpoint:
|
||||
* `DELETE /customer-invoices/:id` (eliminar una factura por ID).
|
||||
*
|
||||
*/
|
||||
|
||||
export const DeleteProformaByIdRequestSchema = z.object({
|
||||
id: z.string(),
|
||||
});
|
||||
|
||||
export type DeleteProformaByIdRequestDTO = z.infer<typeof DeleteProformaByIdRequestSchema>;
|
||||
@ -0,0 +1,7 @@
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const GetProformaByIdRequestSchema = z.object({
|
||||
proforma_id: z.string(),
|
||||
});
|
||||
|
||||
export type GetProformaByIdRequestDTO = z.infer<typeof GetProformaByIdRequestSchema>;
|
||||
@ -0,0 +1,7 @@
|
||||
export * from "./change-status-proforma-by-id.request.dto";
|
||||
export * from "./create-proforma.request.dto";
|
||||
export * from "./delete-proforma-by-id.request.dto";
|
||||
export * from "./get-proforma-by-id.request.dto";
|
||||
export * from "./list-proformas.request.dto";
|
||||
export * from "./report-proforma-by-id.request.dto";
|
||||
export * from "./update-proforma-by-id.request.dto";
|
||||
@ -0,0 +1,5 @@
|
||||
import { CriteriaSchema } from "@erp/core";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
export const ListProformasRequestSchema = CriteriaSchema;
|
||||
export type ProformasListRequestDTO = z.infer<typeof ListProformasRequestSchema>;
|
||||
@ -0,0 +1,7 @@
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const ReportProformaByIdRequestSchema = z.object({
|
||||
proforma_id: z.string(),
|
||||
});
|
||||
|
||||
export type ReportProformaByIdRequestDTO = z.infer<typeof ReportProformaByIdRequestSchema>;
|
||||
@ -1,11 +1,11 @@
|
||||
import { MoneySchema, PercentageSchema, QuantitySchema } from "@erp/core";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const UpdateCustomerInvoiceByIdParamsRequestSchema = z.object({
|
||||
export const UpdateProformaByIdParamsRequestSchema = z.object({
|
||||
proforma_id: z.string(),
|
||||
});
|
||||
|
||||
export const UpdateCustomerInvoiceByIdRequestSchema = z.object({
|
||||
export const UpdateProformaByIdRequestSchema = z.object({
|
||||
series: z.string().optional(),
|
||||
|
||||
invoice_date: z.string().optional(),
|
||||
@ -38,6 +38,4 @@ export const UpdateCustomerInvoiceByIdRequestSchema = z.object({
|
||||
.default([]),
|
||||
});
|
||||
|
||||
export type UpdateCustomerInvoiceByIdRequestDTO = Partial<
|
||||
z.infer<typeof UpdateCustomerInvoiceByIdRequestSchema>
|
||||
>;
|
||||
export type UpdateProformaByIdRequestDTO = Partial<z.infer<typeof UpdateProformaByIdRequestSchema>>;
|
||||
@ -1,9 +0,0 @@
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const ReportCustomerInvoiceByIdRequestSchema = z.object({
|
||||
invoice_id: z.string(),
|
||||
});
|
||||
|
||||
export type ReportCustomerInvoiceByIdRequestDTO = z.infer<
|
||||
typeof ReportCustomerInvoiceByIdRequestSchema
|
||||
>;
|
||||
@ -1,4 +1,2 @@
|
||||
export * from "./create-customer-invoice.response.dto";
|
||||
export * from "./get-customer-invoice-by-id.response.dto";
|
||||
export * from "./list-customer-invoices.response.dto";
|
||||
export * from "./update-customer-invoice-by-id.response.dto";
|
||||
export * from "./issue-invoices";
|
||||
export * from "./proformas";
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { MetadataSchema, MoneySchema, PercentageSchema, QuantitySchema } from "@erp/core";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const GetCustomerInvoiceByIdResponseSchema = z.object({
|
||||
export const GetIssueInvoiceByIdResponseSchema = z.object({
|
||||
id: z.uuid(),
|
||||
company_id: z.uuid(),
|
||||
|
||||
@ -79,6 +79,4 @@ export const GetCustomerInvoiceByIdResponseSchema = z.object({
|
||||
metadata: MetadataSchema.optional(),
|
||||
});
|
||||
|
||||
export type GetCustomerInvoiceByIdResponseDTO = z.infer<
|
||||
typeof GetCustomerInvoiceByIdResponseSchema
|
||||
>;
|
||||
export type GetIssueInvoiceByIdResponseDTO = z.infer<typeof GetIssueInvoiceByIdResponseSchema>;
|
||||
@ -0,0 +1,2 @@
|
||||
export * from "./get-issue-invoice-by-id.response.dto";
|
||||
export * from "./list-issue-invoices.response.dto";
|
||||
@ -6,7 +6,7 @@ import {
|
||||
} from "@erp/core";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const ListCustomerInvoicesResponseSchema = createPaginatedListSchema(
|
||||
export const ListIssueInvoicesResponseSchema = createPaginatedListSchema(
|
||||
z.object({
|
||||
id: z.uuid(),
|
||||
company_id: z.uuid(),
|
||||
@ -51,4 +51,4 @@ export const ListCustomerInvoicesResponseSchema = createPaginatedListSchema(
|
||||
})
|
||||
);
|
||||
|
||||
export type ListCustomerInvoicesResponseDTO = z.infer<typeof ListCustomerInvoicesResponseSchema>;
|
||||
export type ListIssueInvoicesResponseDTO = z.infer<typeof ListIssueInvoicesResponseSchema>;
|
||||
@ -7,7 +7,7 @@ import {
|
||||
} from "@erp/core";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const CreateCustomerInvoiceResponseSchema = z.object({
|
||||
export const CreateProformaResponseSchema = z.object({
|
||||
id: z.uuid(),
|
||||
company_id: z.uuid(),
|
||||
|
||||
@ -52,4 +52,4 @@ export const CreateCustomerInvoiceResponseSchema = z.object({
|
||||
metadata: MetadataSchema.optional(),
|
||||
});
|
||||
|
||||
export type CreateCustomerInvoiceResponseDTO = z.infer<typeof CreateCustomerInvoiceResponseSchema>;
|
||||
export type CreateProformaResponseDTO = z.infer<typeof CreateProformaResponseSchema>;
|
||||
@ -0,0 +1,82 @@
|
||||
import { MetadataSchema, MoneySchema, PercentageSchema, QuantitySchema } from "@erp/core";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const GetProformaByIdResponseSchema = z.object({
|
||||
id: z.uuid(),
|
||||
company_id: z.uuid(),
|
||||
|
||||
is_proforma: z.string(),
|
||||
invoice_number: z.string(),
|
||||
status: z.string(),
|
||||
series: z.string(),
|
||||
|
||||
invoice_date: z.string(),
|
||||
operation_date: z.string(),
|
||||
|
||||
reference: z.string(),
|
||||
description: z.string(),
|
||||
notes: z.string(),
|
||||
|
||||
language_code: z.string(),
|
||||
currency_code: z.string(),
|
||||
|
||||
customer_id: z.string(),
|
||||
recipient: z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
tin: z.string(),
|
||||
street: z.string(),
|
||||
street2: z.string(),
|
||||
city: z.string(),
|
||||
province: z.string(),
|
||||
postal_code: z.string(),
|
||||
country: z.string(),
|
||||
}),
|
||||
|
||||
taxes: z.array(
|
||||
z.object({
|
||||
tax_code: z.string(),
|
||||
taxable_amount: MoneySchema,
|
||||
taxes_amount: MoneySchema,
|
||||
})
|
||||
),
|
||||
|
||||
payment_method: z
|
||||
.object({
|
||||
payment_id: z.string(),
|
||||
payment_description: z.string(),
|
||||
})
|
||||
.optional(),
|
||||
|
||||
subtotal_amount: MoneySchema,
|
||||
items_discount_amount: MoneySchema,
|
||||
discount_percentage: PercentageSchema,
|
||||
discount_amount: MoneySchema,
|
||||
taxable_amount: MoneySchema,
|
||||
taxes_amount: MoneySchema,
|
||||
total_amount: MoneySchema,
|
||||
|
||||
items: z.array(
|
||||
z.object({
|
||||
id: z.uuid(),
|
||||
is_valued: z.string(),
|
||||
position: z.string(),
|
||||
description: z.string(),
|
||||
quantity: QuantitySchema,
|
||||
unit_amount: MoneySchema,
|
||||
|
||||
tax_codes: z.array(z.string()),
|
||||
|
||||
subtotal_amount: MoneySchema,
|
||||
discount_percentage: PercentageSchema,
|
||||
discount_amount: MoneySchema,
|
||||
taxable_amount: MoneySchema,
|
||||
taxes_amount: MoneySchema,
|
||||
total_amount: MoneySchema,
|
||||
})
|
||||
),
|
||||
|
||||
metadata: MetadataSchema.optional(),
|
||||
});
|
||||
|
||||
export type GetProformaByIdResponseDTO = z.infer<typeof GetProformaByIdResponseSchema>;
|
||||
@ -0,0 +1,3 @@
|
||||
export * from "./create-proforma.response.dto";
|
||||
export * from "./get-proforma-by-id.response.dto";
|
||||
export * from "./list-proformas.response.dto";
|
||||
@ -0,0 +1,54 @@
|
||||
import {
|
||||
MetadataSchema,
|
||||
MoneySchema,
|
||||
PercentageSchema,
|
||||
createPaginatedListSchema,
|
||||
} from "@erp/core";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const ListProformasResponseSchema = createPaginatedListSchema(
|
||||
z.object({
|
||||
id: z.uuid(),
|
||||
company_id: z.uuid(),
|
||||
is_proforma: z.boolean(),
|
||||
|
||||
customer_id: z.string(),
|
||||
|
||||
invoice_number: z.string(),
|
||||
status: z.string(),
|
||||
series: z.string(),
|
||||
|
||||
invoice_date: z.string(),
|
||||
operation_date: z.string(),
|
||||
|
||||
language_code: z.string(),
|
||||
currency_code: z.string(),
|
||||
|
||||
reference: z.string(),
|
||||
description: z.string(),
|
||||
|
||||
recipient: z.object({
|
||||
tin: z.string(),
|
||||
name: z.string(),
|
||||
street: z.string(),
|
||||
street2: z.string(),
|
||||
city: z.string(),
|
||||
postal_code: z.string(),
|
||||
province: z.string(),
|
||||
country: z.string(),
|
||||
}),
|
||||
|
||||
taxes: z.string(),
|
||||
|
||||
subtotal_amount: MoneySchema,
|
||||
discount_percentage: PercentageSchema,
|
||||
discount_amount: MoneySchema,
|
||||
taxable_amount: MoneySchema,
|
||||
taxes_amount: MoneySchema,
|
||||
total_amount: MoneySchema,
|
||||
|
||||
metadata: MetadataSchema.optional(),
|
||||
})
|
||||
);
|
||||
|
||||
export type ListProformasResponseDTO = z.infer<typeof ListProformasResponseSchema>;
|
||||
@ -1,44 +0,0 @@
|
||||
import { AmountSchema, MetadataSchema, PercentageSchema, QuantitySchema } from "@erp/core";
|
||||
import { z } from "zod/v4";
|
||||
|
||||
export const UpdateCustomerInvoiceByIdResponseSchema = z.object({
|
||||
id: z.uuid(),
|
||||
company_id: z.uuid(),
|
||||
|
||||
invoice_number: z.string(),
|
||||
status: z.string(),
|
||||
series: z.string(),
|
||||
|
||||
invoice_date: z.string(),
|
||||
operation_date: z.string(),
|
||||
|
||||
notes: z.string(),
|
||||
|
||||
language_code: z.string(),
|
||||
currency_code: z.string(),
|
||||
|
||||
subtotal_amount: AmountSchema,
|
||||
discount_percentage: PercentageSchema,
|
||||
discount_amount: AmountSchema,
|
||||
taxable_amount: AmountSchema,
|
||||
tax_amount: AmountSchema,
|
||||
total_amount: AmountSchema,
|
||||
|
||||
items: z.array(
|
||||
z.object({
|
||||
id: z.uuid(),
|
||||
position: z.string(),
|
||||
description: z.string(),
|
||||
quantity: QuantitySchema,
|
||||
unit_amount: AmountSchema,
|
||||
discount_percentage: PercentageSchema,
|
||||
total_amount: AmountSchema,
|
||||
})
|
||||
),
|
||||
|
||||
metadata: MetadataSchema.optional(),
|
||||
});
|
||||
|
||||
export type UpdateCustomerInvoiceByIdResponseDTO = z.infer<
|
||||
typeof UpdateCustomerInvoiceByIdResponseSchema
|
||||
>;
|
||||
@ -1,15 +1,13 @@
|
||||
import { ModuleClientParams } from "@erp/core/client";
|
||||
import type { ModuleClientParams } from "@erp/core/client";
|
||||
import { lazy } from "react";
|
||||
import { Outlet, RouteObject } from "react-router-dom";
|
||||
import { Outlet, type RouteObject } from "react-router-dom";
|
||||
|
||||
// Lazy load components
|
||||
const InvoicesLayout = lazy(() =>
|
||||
import("./components").then((m) => ({ default: m.InvoicesLayout }))
|
||||
);
|
||||
|
||||
const InvoiceListPage = lazy(() =>
|
||||
import("./pages").then((m) => ({ default: m.InvoiceListPage }))
|
||||
);
|
||||
const InvoiceListPage = lazy(() => import("./pages").then((m) => ({ default: m.InvoiceListPage })));
|
||||
|
||||
const CustomerInvoiceAdd = lazy(() =>
|
||||
import("./pages").then((m) => ({ default: m.CustomerInvoiceCreate }))
|
||||
@ -20,6 +18,20 @@ const InvoiceUpdatePage = lazy(() =>
|
||||
|
||||
export const CustomerInvoiceRoutes = (params: ModuleClientParams): RouteObject[] => {
|
||||
return [
|
||||
{
|
||||
path: "proformas",
|
||||
element: (
|
||||
<InvoicesLayout>
|
||||
<Outlet context={params} />
|
||||
</InvoicesLayout>
|
||||
),
|
||||
children: [
|
||||
{ path: "", index: true, element: <ProformasListPage /> }, // index
|
||||
{ path: "list", element: <ProformasListPage /> },
|
||||
{ path: "create", element: <CustomerInvoiceAdd /> },
|
||||
{ path: ":id/edit", element: <InvoiceUpdatePage /> },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "customer-invoices",
|
||||
element: (
|
||||
@ -30,8 +42,6 @@ export const CustomerInvoiceRoutes = (params: ModuleClientParams): RouteObject[]
|
||||
children: [
|
||||
{ path: "", index: true, element: <InvoiceListPage /> }, // index
|
||||
{ path: "list", element: <InvoiceListPage /> },
|
||||
{ path: "create", element: <CustomerInvoiceAdd /> },
|
||||
{ path: ":id/edit", element: <InvoiceUpdatePage /> },
|
||||
|
||||
//
|
||||
/*{ path: "create", element: <CustomerInvoicesList /> },
|
||||
|
||||
@ -0,0 +1 @@
|
||||
export * from "./proforma-list-page";
|
||||
@ -0,0 +1,111 @@
|
||||
import { PageHeader } from "@erp/core/components";
|
||||
import { ErrorAlert } from "@erp/customers/components";
|
||||
import { AppContent, AppHeader, BackHistoryButton, useDebounce } from "@repo/rdx-ui/components";
|
||||
import { Button } from "@repo/shadcn-ui/components";
|
||||
import { PlusIcon } from "lucide-react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useInvoicesQuery } from "../../hooks";
|
||||
import { useTranslation } from "../../i18n";
|
||||
import { invoiceResumeDtoToFormAdapter } from "../../schemas/invoice-resume-dto.adapter";
|
||||
import { InvoicesListGrid } from "./invoices-list-grid";
|
||||
|
||||
export const ProformaListPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
const debouncedQ = useDebounce(search, 300);
|
||||
|
||||
const criteria = useMemo(
|
||||
() => ({
|
||||
q: debouncedQ || "",
|
||||
pageSize,
|
||||
pageNumber: pageIndex,
|
||||
}),
|
||||
[pageSize, pageIndex, debouncedQ]
|
||||
);
|
||||
|
||||
const { data, isLoading, isError, error } = useInvoicesQuery({
|
||||
criteria,
|
||||
});
|
||||
|
||||
const invoicesPageData = useMemo(() => {
|
||||
if (!data) return undefined;
|
||||
return {
|
||||
...data,
|
||||
items: invoiceResumeDtoToFormAdapter.fromDto(data.items),
|
||||
};
|
||||
}, [data]);
|
||||
|
||||
const handlePageChange = (newPageIndex: number) => {
|
||||
setPageIndex(newPageIndex);
|
||||
};
|
||||
|
||||
const handlePageSizeChange = (newSize: number) => {
|
||||
setPageSize(newSize);
|
||||
setPageIndex(0);
|
||||
};
|
||||
|
||||
const handleSearchChange = (value: string) => {
|
||||
// Normalización ligera: recorta y colapsa espacios internos
|
||||
const cleaned = value.trim().replace(/\s+/g, " ");
|
||||
setSearch(cleaned);
|
||||
setPageIndex(0);
|
||||
};
|
||||
|
||||
if (isError || !invoicesPageData) {
|
||||
return (
|
||||
<AppContent>
|
||||
<ErrorAlert
|
||||
title={t("pages.list.loadErrorTitle")}
|
||||
message={(error as Error)?.message || "Error al cargar el listado"}
|
||||
/>
|
||||
<BackHistoryButton />
|
||||
</AppContent>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader>
|
||||
<PageHeader
|
||||
title={t("pages.list.title")}
|
||||
description={t("pages.list.description")}
|
||||
rightSlot={
|
||||
<div className='flex items-center space-x-2'>
|
||||
<Button
|
||||
onClick={() => navigate("/customer-invoices/create")}
|
||||
variant={"default"}
|
||||
aria-label={t("pages.create.title")}
|
||||
className='cursor-pointer'
|
||||
>
|
||||
<PlusIcon className='mr-2 h-4 w-4' aria-hidden />
|
||||
{t("pages.create.title")}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</AppHeader>
|
||||
<AppContent>
|
||||
<div className='flex flex-col w-full h-full py-3'>
|
||||
<div className={"flex-1"}>
|
||||
<InvoicesListGrid
|
||||
invoicesPage={invoicesPageData}
|
||||
loading={isLoading}
|
||||
pageIndex={pageIndex}
|
||||
pageSize={pageSize}
|
||||
onPageChange={handlePageChange}
|
||||
onPageSizeChange={handlePageSizeChange}
|
||||
searchValue={search}
|
||||
onSearchChange={handleSearchChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</AppContent>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -1,5 +1,5 @@
|
||||
export * from "./invoice-dto.adapter";
|
||||
export * from "./invoice-resume-dto.adapter";
|
||||
export * from "./invoice-resume.form.schema";
|
||||
export * from "./invoice.form.schema";
|
||||
export * from "./invoice-dto.adapter";
|
||||
export * from "./invoice-resume.form.schema";
|
||||
export * from "./invoice-resume-dto.adapter";
|
||||
export * from "./invoices.api.schema";
|
||||
|
||||
@ -1,16 +1,18 @@
|
||||
import { MoneyDTOHelper, PercentageDTOHelper, QuantityDTOHelper } from "@erp/core";
|
||||
import {
|
||||
GetCustomerInvoiceByIdResponseDTO,
|
||||
|
||||
import type {
|
||||
GetIssueInvoiceByIdResponseDTO,
|
||||
UpdateCustomerInvoiceByIdRequestDTO,
|
||||
} from "../../common";
|
||||
import { InvoiceContextValue } from "../context";
|
||||
import { InvoiceFormData } from "./invoice.form.schema";
|
||||
import type { InvoiceContextValue } from "../context";
|
||||
|
||||
import type { InvoiceFormData } from "./invoice.form.schema";
|
||||
|
||||
/**
|
||||
* Convierte el DTO completo de API a datos numéricos para el formulario.
|
||||
*/
|
||||
export const invoiceDtoToFormAdapter = {
|
||||
fromDto(dto: GetCustomerInvoiceByIdResponseDTO, context: InvoiceContextValue): InvoiceFormData {
|
||||
fromDto(dto: GetIssueInvoiceByIdResponseDTO, context: InvoiceContextValue): InvoiceFormData {
|
||||
const { taxCatalog } = context;
|
||||
return {
|
||||
invoice_number: dto.invoice_number,
|
||||
@ -30,6 +32,7 @@ export const invoiceDtoToFormAdapter = {
|
||||
currency_code: dto.currency_code,
|
||||
|
||||
subtotal_amount: MoneyDTOHelper.toNumber(dto.subtotal_amount),
|
||||
items_discount_amount: 0,
|
||||
discount_percentage: PercentageDTOHelper.toNumber(dto.discount_percentage),
|
||||
discount_amount: MoneyDTOHelper.toNumber(dto.discount_amount),
|
||||
taxable_amount: MoneyDTOHelper.toNumber(dto.taxable_amount),
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import { z } from "zod/v4";
|
||||
import type { PaginationSchema } from "@erp/core";
|
||||
import type { ArrayElement } from "@repo/rdx-utils";
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import { PaginationSchema } from "@erp/core";
|
||||
import { ArrayElement } from "@repo/rdx-utils";
|
||||
import {
|
||||
CreateCustomerInvoiceRequestSchema,
|
||||
GetCustomerInvoiceByIdResponseSchema,
|
||||
ListCustomerInvoicesResponseSchema,
|
||||
GetIssueInvoiceByIdResponseSchema,
|
||||
ListIssueInvoicesResponseSchema,
|
||||
UpdateCustomerInvoiceByIdRequestSchema,
|
||||
} from "../../common";
|
||||
|
||||
export const CustomerInvoiceSchema = GetCustomerInvoiceByIdResponseSchema.omit({
|
||||
export const CustomerInvoiceSchema = GetIssueInvoiceByIdResponseSchema.omit({
|
||||
metadata: true,
|
||||
});
|
||||
export const CustomerInvoiceCreateSchema = CreateCustomerInvoiceRequestSchema;
|
||||
@ -24,7 +24,7 @@ export type CustomerInvoiceCreateInput = z.infer<typeof CustomerInvoiceCreateSch
|
||||
export type CustomerInvoiceUpdateInput = z.infer<typeof CustomerInvoiceUpdateSchema>; // Cuerpo para actualizar
|
||||
|
||||
// Resultado de consulta con criteria (paginado, etc.)
|
||||
export const CustomerInvoicesPageSchema = ListCustomerInvoicesResponseSchema.omit({
|
||||
export const CustomerInvoicesPageSchema = ListIssueInvoicesResponseSchema.omit({
|
||||
metadata: true,
|
||||
});
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { FindOptions, Op, OrderItem, Sequelize, WhereOptions } from "sequelize";
|
||||
import { Criteria } from "./critera";
|
||||
import { type ConvertParams, type CriteriaMappings, ICriteriaToOrmConverter } from "./types";
|
||||
import { type FindOptions, Op, type OrderItem, Sequelize, type WhereOptions } from "sequelize";
|
||||
|
||||
import type { Criteria } from "./critera";
|
||||
import type { ConvertParams, CriteriaMappings, ICriteriaToOrmConverter } from "./types";
|
||||
import { appendOrder, prependOrder } from "./utils";
|
||||
|
||||
/**
|
||||
@ -146,7 +147,7 @@ export class CriteriaToSequelizeConverter implements ICriteriaToOrmConverter {
|
||||
}
|
||||
}
|
||||
|
||||
private transformValue(operator: symbol, value: any): any {
|
||||
private transformValue(operator: symbol, value: unknown): unknown {
|
||||
if (operator === Op.like || operator === Op.notLike) return `%${value}%`;
|
||||
return value;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user