.
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"
|
"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]": {
|
"[typescript]": {
|
||||||
"editor.defaultFormatter": "biomejs.biome"
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
},
|
},
|
||||||
@ -48,8 +39,16 @@
|
|||||||
"editor.defaultFormatter": "biomejs.biome"
|
"editor.defaultFormatter": "biomejs.biome"
|
||||||
},
|
},
|
||||||
|
|
||||||
"prettier.enable": false,
|
// Biome
|
||||||
"eslint.enable": false,
|
"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
|
// other vscode settings
|
||||||
"[handlebars]": {
|
"[handlebars]": {
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import { DateTime } from "luxon";
|
|
||||||
import http from "node:http";
|
import http from "node:http";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
|
|
||||||
|
import { DateTime } from "luxon";
|
||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
import { createApp } from "./app.ts";
|
import { createApp } from "./app.ts";
|
||||||
import { tryConnectToDatabase } from "./config/database.ts";
|
import { tryConnectToDatabase } from "./config/database.ts";
|
||||||
import { ENV } from "./config/index.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",
|
"$schema": "https://biomejs.dev/schemas/2.2.4/schema.json",
|
||||||
"vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false },
|
"vcs": {
|
||||||
"files": { "ignoreUnknown": false, "includes": ["**", "!**/dist"] },
|
"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": {
|
"formatter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"useEditorconfig": true,
|
|
||||||
"formatWithErrors": false,
|
"formatWithErrors": false,
|
||||||
"indentStyle": "space",
|
"indentStyle": "space",
|
||||||
"indentWidth": 2,
|
"indentWidth": 2,
|
||||||
"lineEnding": "lf",
|
|
||||||
"lineWidth": 100,
|
"lineWidth": 100,
|
||||||
"attributePosition": "auto",
|
"lineEnding": "lf",
|
||||||
"bracketSpacing": true
|
"attributePosition": "auto"
|
||||||
},
|
},
|
||||||
"assist": { "actions": { "source": { "organizeImports": "on" } } },
|
|
||||||
"linter": {
|
"linter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"rules": {
|
"rules": {
|
||||||
"recommended": true,
|
"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": {
|
"style": {
|
||||||
"useImportType": "off",
|
"noDefaultExport": "off",
|
||||||
"noInferrableTypes": "off",
|
"noImplicitBoolean": "off",
|
||||||
|
"noInferrableTypes": "error",
|
||||||
|
"noNamespace": "error",
|
||||||
|
"noNegationElse": "warn",
|
||||||
"noNonNullAssertion": "info",
|
"noNonNullAssertion": "info",
|
||||||
"noUselessElse": "off",
|
|
||||||
"noParameterAssign": "error",
|
"noParameterAssign": "error",
|
||||||
"useAsConstAssertion": "error",
|
"noUnusedTemplateLiteral": "error",
|
||||||
|
"noUselessElse": "warn",
|
||||||
|
"useBlockStatements": "off",
|
||||||
|
"useCollapsedElseIf": "error",
|
||||||
|
"useConst": "error",
|
||||||
"useDefaultParameterLast": "error",
|
"useDefaultParameterLast": "error",
|
||||||
"useEnumInitializers": "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",
|
"useSelfClosingElements": "error",
|
||||||
|
"useShorthandAssign": "error",
|
||||||
|
"useShorthandFunctionType": "error",
|
||||||
"useSingleVarDeclarator": "error",
|
"useSingleVarDeclarator": "error",
|
||||||
"noUnusedTemplateLiteral": "error",
|
"useTemplate": "error",
|
||||||
"useNumberNamespace": "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": {
|
"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": {
|
"javascript": {
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"jsxQuoteStyle": "single",
|
|
||||||
"quoteProperties": "asNeeded",
|
|
||||||
"trailingCommas": "es5",
|
|
||||||
"semicolons": "always",
|
|
||||||
"arrowParentheses": "always",
|
"arrowParentheses": "always",
|
||||||
"bracketSameLine": false,
|
"bracketSameLine": false,
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"jsxQuoteStyle": "double",
|
||||||
|
"quoteProperties": "asNeeded",
|
||||||
"quoteStyle": "double",
|
"quoteStyle": "double",
|
||||||
"attributePosition": "auto",
|
"semicolons": "always",
|
||||||
"bracketSpacing": true
|
"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(
|
export function formatPaymentMethodDTO(
|
||||||
paymentMethod?: GetCustomerInvoiceByIdResponseDTO["payment_method"]
|
paymentMethod?: GetIssueInvoiceByIdResponseDTO["payment_method"]
|
||||||
) {
|
) {
|
||||||
if (!paymentMethod) {
|
if (!paymentMethod) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import { Presenter } from "@erp/core/api";
|
import { Presenter } from "@erp/core/api";
|
||||||
import { toEmptyString } from "@repo/rdx-ddd";
|
import { toEmptyString } from "@repo/rdx-ddd";
|
||||||
import { ArrayElement } from "@repo/rdx-utils";
|
import type { ArrayElement } from "@repo/rdx-utils";
|
||||||
import { GetCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
|
|
||||||
import { CustomerInvoiceItem, CustomerInvoiceItems } from "../../../domain";
|
import type { GetIssueInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||||
|
import type { CustomerInvoiceItem, CustomerInvoiceItems } from "../../../domain";
|
||||||
|
|
||||||
type GetCustomerInvoiceItemByInvoiceIdResponseDTO = ArrayElement<
|
type GetCustomerInvoiceItemByInvoiceIdResponseDTO = ArrayElement<
|
||||||
GetCustomerInvoiceByIdResponseDTO["items"]
|
GetIssueInvoiceByIdResponseDTO["items"]
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export class CustomerInvoiceItemsFullPresenter extends Presenter {
|
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);
|
return invoiceItems.map(this._mapItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
import { Presenter } from "@erp/core/api";
|
import { Presenter } from "@erp/core/api";
|
||||||
import { toEmptyString } from "@repo/rdx-ddd";
|
import { toEmptyString } from "@repo/rdx-ddd";
|
||||||
import { GetCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
|
|
||||||
import { CustomerInvoice } from "../../../domain";
|
import type { GetIssueInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||||
import { CustomerInvoiceItemsFullPresenter } from "./customer-invoice-items.full.presenter";
|
import type { CustomerInvoice } from "../../../domain";
|
||||||
import { RecipientInvoiceFullPresenter } from "./recipient-invoice.full.representer";
|
|
||||||
|
import type { CustomerInvoiceItemsFullPresenter } from "./customer-invoice-items.full.presenter";
|
||||||
|
import type { RecipientInvoiceFullPresenter } from "./recipient-invoice.full.representer";
|
||||||
|
|
||||||
export class CustomerInvoiceFullPresenter extends Presenter<
|
export class CustomerInvoiceFullPresenter extends Presenter<
|
||||||
CustomerInvoice,
|
CustomerInvoice,
|
||||||
GetCustomerInvoiceByIdResponseDTO
|
GetIssueInvoiceByIdResponseDTO
|
||||||
> {
|
> {
|
||||||
toOutput(invoice: CustomerInvoice): GetCustomerInvoiceByIdResponseDTO {
|
toOutput(invoice: CustomerInvoice): GetIssueInvoiceByIdResponseDTO {
|
||||||
const itemsPresenter = this.presenterRegistry.getPresenter({
|
const itemsPresenter = this.presenterRegistry.getPresenter({
|
||||||
resource: "customer-invoice-items",
|
resource: "customer-invoice-items",
|
||||||
projection: "FULL",
|
projection: "FULL",
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import { Presenter } from "@erp/core/api";
|
import { Presenter } from "@erp/core/api";
|
||||||
import { DomainValidationError, toEmptyString } from "@repo/rdx-ddd";
|
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 {
|
export class RecipientInvoiceFullPresenter extends Presenter {
|
||||||
toOutput(invoice: CustomerInvoice): GetRecipientInvoiceByInvoiceIdResponseDTO {
|
toOutput(invoice: CustomerInvoice): GetRecipientInvoiceByInvoiceIdResponseDTO {
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import { IPresenterOutputParams, Presenter } from "@erp/core/api";
|
import { type IPresenterOutputParams, Presenter } from "@erp/core/api";
|
||||||
import { GetCustomerInvoiceByIdResponseDTO } from "@erp/customer-invoices/common";
|
import type { GetIssueInvoiceByIdResponseDTO } from "@erp/customer-invoices/common";
|
||||||
import { ArrayElement } from "@repo/rdx-utils";
|
import type { ArrayElement } from "@repo/rdx-utils";
|
||||||
import { FormatMoneyOptions, formatMoneyDTO, formatQuantityDTO } from "../../helpers";
|
|
||||||
|
|
||||||
type CustomerInvoiceItemsDTO = GetCustomerInvoiceByIdResponseDTO["items"];
|
import { type FormatMoneyOptions, formatMoneyDTO, formatQuantityDTO } from "../../helpers";
|
||||||
|
|
||||||
|
type CustomerInvoiceItemsDTO = GetIssueInvoiceByIdResponseDTO["items"];
|
||||||
type CustomerInvoiceItemDTO = ArrayElement<CustomerInvoiceItemsDTO>;
|
type CustomerInvoiceItemDTO = ArrayElement<CustomerInvoiceItemsDTO>;
|
||||||
|
|
||||||
export class CustomerInvoiceItemsReportPersenter extends Presenter<
|
export class CustomerInvoiceItemsReportPersenter extends Presenter<
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { Presenter } from "@erp/core/api";
|
import { Presenter } from "@erp/core/api";
|
||||||
import { GetCustomerInvoiceByIdResponseDTO } from "../../../../common/dto";
|
|
||||||
|
import type { GetIssueInvoiceByIdResponseDTO } from "../../../../common/dto";
|
||||||
import {
|
import {
|
||||||
FormatMoneyOptions,
|
type FormatMoneyOptions,
|
||||||
formatDateDTO,
|
formatDateDTO,
|
||||||
formatMoneyDTO,
|
formatMoneyDTO,
|
||||||
formatPercentageDTO,
|
formatPercentageDTO,
|
||||||
@ -9,10 +10,10 @@ import {
|
|||||||
import { formatPaymentMethodDTO } from "../../helpers/format-payment_method-dto";
|
import { formatPaymentMethodDTO } from "../../helpers/format-payment_method-dto";
|
||||||
|
|
||||||
export class CustomerInvoiceReportPresenter extends Presenter<
|
export class CustomerInvoiceReportPresenter extends Presenter<
|
||||||
GetCustomerInvoiceByIdResponseDTO,
|
GetIssueInvoiceByIdResponseDTO,
|
||||||
unknown
|
unknown
|
||||||
> {
|
> {
|
||||||
toOutput(invoiceDTO: GetCustomerInvoiceByIdResponseDTO) {
|
toOutput(invoiceDTO: GetIssueInvoiceByIdResponseDTO) {
|
||||||
const itemsPresenter = this.presenterRegistry.getPresenter({
|
const itemsPresenter = this.presenterRegistry.getPresenter({
|
||||||
resource: "customer-invoice-items",
|
resource: "customer-invoice-items",
|
||||||
projection: "REPORT",
|
projection: "REPORT",
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
import { Presenter } from "@erp/core/api";
|
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 { toEmptyString } from "@repo/rdx-ddd";
|
||||||
import { ArrayElement, Collection } from "@repo/rdx-utils";
|
import type { ArrayElement, Collection } from "@repo/rdx-utils";
|
||||||
import { ListCustomerInvoicesResponseDTO } from "../../../../common/dto";
|
|
||||||
import { CustomerInvoiceListDTO } from "../../../infrastructure";
|
import type { ListIssueInvoicesResponseDTO } from "../../../../common/dto";
|
||||||
|
import type { CustomerInvoiceListDTO } from "../../../infrastructure";
|
||||||
|
|
||||||
export class ListCustomerInvoicesPresenter extends Presenter {
|
export class ListCustomerInvoicesPresenter extends Presenter {
|
||||||
protected _mapInvoice(invoice: CustomerInvoiceListDTO) {
|
protected _mapInvoice(invoice: CustomerInvoiceListDTO) {
|
||||||
const recipientDTO = invoice.recipient.toObjectString();
|
const recipientDTO = invoice.recipient.toObjectString();
|
||||||
|
|
||||||
const invoiceDTO: ArrayElement<ListCustomerInvoicesResponseDTO["items"]> = {
|
const invoiceDTO: ArrayElement<ListIssueInvoicesResponseDTO["items"]> = {
|
||||||
id: invoice.id.toString(),
|
id: invoice.id.toString(),
|
||||||
company_id: invoice.companyId.toString(),
|
company_id: invoice.companyId.toString(),
|
||||||
is_proforma: invoice.isProforma,
|
is_proforma: invoice.isProforma,
|
||||||
@ -49,7 +50,7 @@ export class ListCustomerInvoicesPresenter extends Presenter {
|
|||||||
toOutput(params: {
|
toOutput(params: {
|
||||||
customerInvoices: Collection<CustomerInvoiceListDTO>;
|
customerInvoices: Collection<CustomerInvoiceListDTO>;
|
||||||
criteria: Criteria;
|
criteria: Criteria;
|
||||||
}): ListCustomerInvoicesResponseDTO {
|
}): ListIssueInvoicesResponseDTO {
|
||||||
const { customerInvoices, criteria } = params;
|
const { customerInvoices, criteria } = params;
|
||||||
|
|
||||||
const invoices = customerInvoices.map((invoice) => this._mapInvoice(invoice));
|
const invoices = customerInvoices.map((invoice) => this._mapInvoice(invoice));
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { Criteria } from "@repo/rdx-criteria/server";
|
import type { Criteria } from "@repo/rdx-criteria/server";
|
||||||
import { UniqueID } from "@repo/rdx-ddd";
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Collection, Maybe, Result } from "@repo/rdx-utils";
|
import { type Collection, Maybe, Result } from "@repo/rdx-utils";
|
||||||
import { Transaction } from "sequelize";
|
import type { Transaction } from "sequelize";
|
||||||
import {
|
|
||||||
|
import type {
|
||||||
CustomerInvoiceNumber,
|
CustomerInvoiceNumber,
|
||||||
CustomerInvoiceSerie,
|
CustomerInvoiceSerie,
|
||||||
CustomerInvoiceStatus,
|
CustomerInvoiceStatus,
|
||||||
@ -10,11 +11,11 @@ import {
|
|||||||
} from "../../domain";
|
} from "../../domain";
|
||||||
import {
|
import {
|
||||||
CustomerInvoice,
|
CustomerInvoice,
|
||||||
CustomerInvoicePatchProps,
|
type CustomerInvoicePatchProps,
|
||||||
CustomerInvoiceProps,
|
type CustomerInvoiceProps,
|
||||||
} from "../../domain/aggregates";
|
} from "../../domain/aggregates";
|
||||||
import { ICustomerInvoiceRepository } from "../../domain/repositories";
|
import type { ICustomerInvoiceRepository } from "../../domain/repositories";
|
||||||
import { CustomerInvoiceListDTO } from "../../infrastructure";
|
import type { CustomerInvoiceListDTO } from "../../infrastructure";
|
||||||
|
|
||||||
export class CustomerInvoiceApplicationService {
|
export class CustomerInvoiceApplicationService {
|
||||||
constructor(
|
constructor(
|
||||||
@ -57,57 +58,57 @@ export class CustomerInvoiceApplicationService {
|
|||||||
*
|
*
|
||||||
* @param companyId - Identificador de la empresa a la que pertenece la proforma.
|
* @param companyId - Identificador de la empresa a la que pertenece la proforma.
|
||||||
* @param props - Las propiedades ya validadas para crear 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.
|
* @returns Result<CustomerInvoice, Error> - El agregado construido o un error si falla la creación.
|
||||||
*/
|
*/
|
||||||
buildProformaInCompany(
|
buildProformaInCompany(
|
||||||
companyId: UniqueID,
|
companyId: UniqueID,
|
||||||
props: Omit<CustomerInvoiceProps, "companyId">,
|
props: Omit<CustomerInvoiceProps, "companyId">,
|
||||||
invoiceId?: UniqueID
|
proformaId?: UniqueID
|
||||||
): Result<CustomerInvoice, Error> {
|
): 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 companyId - Identificador de la empresa a la que pertenece la proforma.
|
||||||
* @param invoice - El agregado a guardar.
|
* @param proforma - La proforma a guardar.
|
||||||
* @param transaction - Transacción activa para la operación.
|
* @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(
|
async createInvoiceInCompany(
|
||||||
companyId: UniqueID,
|
companyId: UniqueID,
|
||||||
invoice: CustomerInvoice,
|
proforma: CustomerInvoice,
|
||||||
transaction: Transaction
|
transaction: Transaction
|
||||||
): Promise<Result<CustomerInvoice, Error>> {
|
): Promise<Result<CustomerInvoice, Error>> {
|
||||||
const result = await this.repository.create(invoice, transaction);
|
const result = await this.repository.create(proforma, transaction);
|
||||||
if (result.isFailure) {
|
if (result.isFailure) {
|
||||||
return Result.fail(result.error);
|
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 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.
|
* @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,
|
companyId: UniqueID,
|
||||||
invoice: CustomerInvoice,
|
proforma: CustomerInvoice,
|
||||||
transaction: Transaction
|
transaction: Transaction
|
||||||
): Promise<Result<CustomerInvoice, Error>> {
|
): Promise<Result<CustomerInvoice, Error>> {
|
||||||
const result = await this.repository.update(invoice, transaction);
|
const result = await this.repository.update(proforma, transaction);
|
||||||
if (result.isFailure) {
|
if (result.isFailure) {
|
||||||
return Result.fail(result.error);
|
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.
|
* @param transaction - Transacción activa para la operación.
|
||||||
* @returns Result<CustomerInvoice, Error> - Factura encontrada o error.
|
* @returns Result<CustomerInvoice, Error> - Factura encontrada o error.
|
||||||
*/
|
*/
|
||||||
async getInvoiceByIdInCompany(
|
async getIssueInvoiceByIdInCompany(
|
||||||
companyId: UniqueID,
|
companyId: UniqueID,
|
||||||
invoiceId: UniqueID,
|
invoiceId: UniqueID,
|
||||||
transaction?: Transaction
|
transaction?: Transaction
|
||||||
): Promise<Result<CustomerInvoice>> {
|
): 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.
|
* No lo guarda en el repositorio.
|
||||||
*
|
*
|
||||||
* @param companyId - Identificador de la empresa a la que pertenece la factura.
|
* @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 changes - Subconjunto de props válidas para aplicar.
|
||||||
* @param transaction - Transacción activa para la operación.
|
* @param transaction - Transacción activa para la operación.
|
||||||
* @returns Result<CustomerInvoice, Error> - Factura actualizada o error.
|
* @returns Result<CustomerInvoice, Error> - Factura actualizada o error.
|
||||||
*/
|
*/
|
||||||
async patchInvoiceByIdInCompany(
|
async patchProformaByIdInCompany(
|
||||||
companyId: UniqueID,
|
companyId: UniqueID,
|
||||||
invoiceId: UniqueID,
|
proformaId: UniqueID,
|
||||||
changes: CustomerInvoicePatchProps,
|
changes: CustomerInvoicePatchProps,
|
||||||
transaction?: Transaction
|
transaction?: Transaction
|
||||||
): Promise<Result<CustomerInvoice, Error>> {
|
): Promise<Result<CustomerInvoice, Error>> {
|
||||||
const invoiceResult = await this.getInvoiceByIdInCompany(companyId, invoiceId, transaction);
|
const invoiceResult = await this.getProformaByIdInCompany(companyId, proformaId, transaction);
|
||||||
|
|
||||||
if (invoiceResult.isFailure) {
|
if (invoiceResult.isFailure) {
|
||||||
return Result.fail(invoiceResult.error);
|
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 "./issue-invoices";
|
||||||
export * from "./create";
|
export * from "./proformas";
|
||||||
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";
|
|
||||||
|
|||||||
@ -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 { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
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;
|
companyId: UniqueID;
|
||||||
invoice_id: string;
|
invoice_id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class GetCustomerInvoiceUseCase {
|
export class GetIssueInvoiceUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly service: CustomerInvoiceApplicationService,
|
private readonly service: CustomerInvoiceApplicationService,
|
||||||
private readonly transactionManager: ITransactionManager,
|
private readonly transactionManager: ITransactionManager,
|
||||||
private readonly presenterRegistry: IPresenterRegistry
|
private readonly presenterRegistry: IPresenterRegistry
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public execute(params: GetCustomerInvoiceUseCaseInput) {
|
public execute(params: GetIssueInvoiceUseCaseInput) {
|
||||||
const { invoice_id, companyId } = params;
|
const { invoice_id, companyId } = params;
|
||||||
|
|
||||||
const idOrError = UniqueID.create(invoice_id);
|
const idOrError = UniqueID.create(invoice_id);
|
||||||
@ -32,17 +33,18 @@ export class GetCustomerInvoiceUseCase {
|
|||||||
|
|
||||||
return this.transactionManager.complete(async (transaction) => {
|
return this.transactionManager.complete(async (transaction) => {
|
||||||
try {
|
try {
|
||||||
const invoiceOrError = await this.service.getInvoiceByIdInCompany(
|
const invoiceOrError = await this.service.getIssueInvoiceByIdInCompany(
|
||||||
companyId,
|
companyId,
|
||||||
invoiceId,
|
invoiceId,
|
||||||
transaction
|
transaction
|
||||||
);
|
);
|
||||||
|
|
||||||
if (invoiceOrError.isFailure) {
|
if (invoiceOrError.isFailure) {
|
||||||
return Result.fail(invoiceOrError.error);
|
return Result.fail(invoiceOrError.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const customerInvoice = invoiceOrError.data;
|
const invoice = invoiceOrError.data;
|
||||||
const dto = presenter.toOutput(customerInvoice);
|
const dto = presenter.toOutput(invoice);
|
||||||
|
|
||||||
return Result.ok(dto);
|
return Result.ok(dto);
|
||||||
} catch (error: unknown) {
|
} 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 { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
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;
|
companyId: UniqueID;
|
||||||
invoice_id: string;
|
invoice_id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ReportCustomerInvoiceUseCase {
|
export class ReportIssueInvoiceUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly service: CustomerInvoiceApplicationService,
|
private readonly service: CustomerInvoiceApplicationService,
|
||||||
private readonly transactionManager: ITransactionManager,
|
private readonly transactionManager: ITransactionManager,
|
||||||
private readonly presenterRegistry: IPresenterRegistry
|
private readonly presenterRegistry: IPresenterRegistry
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public async execute(params: ReportCustomerInvoiceUseCaseInput) {
|
public async execute(params: ReportIssueInvoiceUseCaseInput) {
|
||||||
const { invoice_id, companyId } = params;
|
const { invoice_id, companyId } = params;
|
||||||
|
|
||||||
const idOrError = UniqueID.create(invoice_id);
|
const idOrError = UniqueID.create(invoice_id);
|
||||||
@ -34,11 +35,12 @@ export class ReportCustomerInvoiceUseCase {
|
|||||||
|
|
||||||
return this.transactionManager.complete(async (transaction) => {
|
return this.transactionManager.complete(async (transaction) => {
|
||||||
try {
|
try {
|
||||||
const invoiceOrError = await this.service.getInvoiceByIdInCompany(
|
const invoiceOrError = await this.service.getIssueInvoiceByIdInCompany(
|
||||||
companyId,
|
companyId,
|
||||||
invoiceId,
|
invoiceId,
|
||||||
transaction
|
transaction
|
||||||
);
|
);
|
||||||
|
|
||||||
if (invoiceOrError.isFailure) {
|
if (invoiceOrError.isFailure) {
|
||||||
return Result.fail(invoiceOrError.error);
|
return Result.fail(invoiceOrError.error);
|
||||||
}
|
}
|
||||||
@ -1,17 +1,18 @@
|
|||||||
import { ITransactionManager } from "@erp/core/api";
|
import type { ITransactionManager } from "@erp/core/api";
|
||||||
import { ChangeStatusCustomerInvoiceByIdRequestDTO } from "@erp/customer-invoices/common";
|
|
||||||
import { UniqueID } from "@repo/rdx-ddd";
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
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;
|
companyId: UniqueID;
|
||||||
proforma_id: string;
|
proforma_id: string;
|
||||||
dto: ChangeStatusCustomerInvoiceByIdRequestDTO;
|
dto: ChangeStatusProformaByIdRequestDTO;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ChangeStatusCustomerInvoiceUseCase {
|
export class ChangeStatusProformaUseCase {
|
||||||
private readonly proformaDomainService: ProformaCustomerInvoiceDomainService;
|
private readonly proformaDomainService: ProformaCustomerInvoiceDomainService;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -21,7 +22,7 @@ export class ChangeStatusCustomerInvoiceUseCase {
|
|||||||
this.proformaDomainService = new ProformaCustomerInvoiceDomainService();
|
this.proformaDomainService = new ProformaCustomerInvoiceDomainService();
|
||||||
}
|
}
|
||||||
|
|
||||||
public execute(params: ChangeStatusCustomerInvoiceUseCaseInput) {
|
public execute(params: ChangeStatusProformaUseCaseInput) {
|
||||||
const {
|
const {
|
||||||
proforma_id,
|
proforma_id,
|
||||||
companyId,
|
companyId,
|
||||||
@ -1,19 +1,25 @@
|
|||||||
import { JsonTaxCatalogProvider } from "@erp/core";
|
import type { JsonTaxCatalogProvider } from "@erp/core";
|
||||||
import { DuplicateEntityError, IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
import {
|
||||||
import { UniqueID } from "@repo/rdx-ddd";
|
DuplicateEntityError,
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
type IPresenterRegistry,
|
||||||
import { Transaction } from "sequelize";
|
type ITransactionManager,
|
||||||
import { CreateCustomerInvoiceRequestDTO } from "../../../../common/dto";
|
} from "@erp/core/api";
|
||||||
import { CustomerInvoiceFullPresenter } from "../../presenters";
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { CustomerInvoiceApplicationService } from "../../services/customer-invoice-application.service";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { CreateCustomerInvoicePropsMapper } from "./map-dto-to-create-customer-invoice-props";
|
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;
|
companyId: UniqueID;
|
||||||
dto: CreateCustomerInvoiceRequestDTO;
|
dto: CreateProformaRequestDTO;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class CreateCustomerInvoiceUseCase {
|
export class CreateProformaUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly service: CustomerInvoiceApplicationService,
|
private readonly service: CustomerInvoiceApplicationService,
|
||||||
private readonly transactionManager: ITransactionManager,
|
private readonly transactionManager: ITransactionManager,
|
||||||
@ -21,7 +27,7 @@ export class CreateCustomerInvoiceUseCase {
|
|||||||
private readonly taxCatalog: JsonTaxCatalogProvider
|
private readonly taxCatalog: JsonTaxCatalogProvider
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public async execute(params: CreateCustomerInvoiceUseCaseInput) {
|
public async execute(params: CreateProformaUseCaseInput) {
|
||||||
const { dto, companyId } = params;
|
const { dto, companyId } = params;
|
||||||
const presenter = this.presenterRegistry.getPresenter({
|
const presenter = this.presenterRegistry.getPresenter({
|
||||||
resource: "customer-invoice",
|
resource: "customer-invoice",
|
||||||
@ -51,7 +57,7 @@ export class CreateCustomerInvoiceUseCase {
|
|||||||
// 3) Construir entidad de dominio
|
// 3) Construir entidad de dominio
|
||||||
const proformaProps = {
|
const proformaProps = {
|
||||||
...props,
|
...props,
|
||||||
invoiceNumber: Maybe.some(newProformaNumber),
|
invoiceNumber: newProformaNumber,
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildResult = this.service.buildProformaInCompany(companyId, proformaProps, id);
|
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 { Tax } from "@erp/core/api";
|
||||||
import {
|
import {
|
||||||
CurrencyCode,
|
CurrencyCode,
|
||||||
DomainError,
|
DomainError,
|
||||||
extractOrPushError,
|
|
||||||
LanguageCode,
|
LanguageCode,
|
||||||
maybeFromNullableVO,
|
|
||||||
Percentage,
|
Percentage,
|
||||||
TextValue,
|
TextValue,
|
||||||
UniqueID,
|
UniqueID,
|
||||||
UtcDate,
|
UtcDate,
|
||||||
ValidationErrorCollection,
|
ValidationErrorCollection,
|
||||||
ValidationErrorDetail,
|
type ValidationErrorDetail,
|
||||||
|
extractOrPushError,
|
||||||
|
maybeFromNullableVO,
|
||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
import {
|
|
||||||
CreateCustomerInvoiceItemRequestDTO,
|
import type { CreateProformaItemRequestDTO, CreateProformaRequestDTO } from "../../../../../common";
|
||||||
CreateCustomerInvoiceRequestDTO,
|
|
||||||
} from "../../../../common/dto";
|
|
||||||
import {
|
import {
|
||||||
CustomerInvoiceItem,
|
CustomerInvoiceItem,
|
||||||
CustomerInvoiceItemDescription,
|
CustomerInvoiceItemDescription,
|
||||||
CustomerInvoiceItemProps,
|
type CustomerInvoiceItemProps,
|
||||||
CustomerInvoiceItems,
|
CustomerInvoiceItems,
|
||||||
CustomerInvoiceNumber,
|
CustomerInvoiceNumber,
|
||||||
CustomerInvoiceProps,
|
type CustomerInvoiceProps,
|
||||||
CustomerInvoiceSerie,
|
CustomerInvoiceSerie,
|
||||||
CustomerInvoiceStatus,
|
CustomerInvoiceStatus,
|
||||||
InvoicePaymentMethod,
|
InvoicePaymentMethod,
|
||||||
InvoiceRecipient,
|
type InvoiceRecipient,
|
||||||
ItemAmount,
|
ItemAmount,
|
||||||
ItemDiscount,
|
ItemDiscount,
|
||||||
ItemQuantity,
|
ItemQuantity,
|
||||||
ItemTaxes,
|
ItemTaxes,
|
||||||
} from "../../../domain";
|
} from "../../../../domain";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convierte el DTO a las props validadas (CustomerProps).
|
* Convierte el DTO a las props validadas (CustomerProps).
|
||||||
@ -56,13 +54,13 @@ export class CreateCustomerInvoicePropsMapper {
|
|||||||
this.errors = [];
|
this.errors = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public map(dto: CreateCustomerInvoiceRequestDTO, companyId: UniqueID) {
|
public map(dto: CreateProformaRequestDTO, companyId: UniqueID) {
|
||||||
try {
|
try {
|
||||||
this.errors = [];
|
this.errors = [];
|
||||||
|
|
||||||
const defaultStatus = CustomerInvoiceStatus.createDraft();
|
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;
|
const isProforma = true;
|
||||||
|
|
||||||
@ -74,8 +72,8 @@ export class CreateCustomerInvoicePropsMapper {
|
|||||||
|
|
||||||
const recipient = Maybe.none<InvoiceRecipient>();
|
const recipient = Maybe.none<InvoiceRecipient>();
|
||||||
|
|
||||||
const invoiceNumber = extractOrPushError(
|
const proformaNumber = extractOrPushError(
|
||||||
maybeFromNullableVO(dto.invoice_number, (value) => CustomerInvoiceNumber.create(value)),
|
CustomerInvoiceNumber.create(dto.invoice_number),
|
||||||
"invoice_number",
|
"invoice_number",
|
||||||
this.errors
|
this.errors
|
||||||
);
|
);
|
||||||
@ -153,13 +151,14 @@ export class CreateCustomerInvoicePropsMapper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const invoiceProps: CustomerInvoiceProps = {
|
const proformaProps: CustomerInvoiceProps = {
|
||||||
companyId,
|
companyId,
|
||||||
isProforma,
|
isProforma,
|
||||||
|
proformaId: Maybe.none(),
|
||||||
status: defaultStatus!,
|
status: defaultStatus!,
|
||||||
|
|
||||||
|
invoiceNumber: proformaNumber!,
|
||||||
series: series!,
|
series: series!,
|
||||||
invoiceNumber: invoiceNumber!,
|
|
||||||
|
|
||||||
invoiceDate: invoiceDate!,
|
invoiceDate: invoiceDate!,
|
||||||
operationDate: operationDate!,
|
operationDate: operationDate!,
|
||||||
@ -181,13 +180,13 @@ export class CreateCustomerInvoicePropsMapper {
|
|||||||
discountPercentage: discountPercentage!,
|
discountPercentage: discountPercentage!,
|
||||||
};
|
};
|
||||||
|
|
||||||
return Result.ok({ id: invoiceId!, props: invoiceProps });
|
return Result.ok({ id: proformaId!, props: proformaProps });
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
return Result.fail(new DomainError("Customer invoice props mapping failed", { cause: err }));
|
return Result.fail(new DomainError("Customer invoice props mapping failed", { cause: err }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private mapItems(items: CreateCustomerInvoiceItemRequestDTO[]) {
|
private mapItems(items: CreateProformaItemRequestDTO[]) {
|
||||||
const invoiceItems = CustomerInvoiceItems.create({
|
const invoiceItems = CustomerInvoiceItems.create({
|
||||||
currencyCode: this.currencyCode!,
|
currencyCode: this.currencyCode!,
|
||||||
languageCode: this.languageCode!,
|
languageCode: this.languageCode!,
|
||||||
@ -246,10 +245,10 @@ export class CreateCustomerInvoicePropsMapper {
|
|||||||
return invoiceItems;
|
return invoiceItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
private mapTaxes(item: CreateCustomerInvoiceItemRequestDTO, itemIndex: number) {
|
private mapTaxes(item: CreateProformaItemRequestDTO, itemIndex: number) {
|
||||||
const taxes = ItemTaxes.create([]);
|
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);
|
const taxResult = Tax.createFromCode(tax_code, this.taxCatalog);
|
||||||
if (taxResult.isSuccess) {
|
if (taxResult.isSuccess) {
|
||||||
taxes.add(taxResult.data);
|
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 { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { CustomerInvoiceApplicationService } from "../services";
|
|
||||||
|
|
||||||
type DeleteCustomerInvoiceUseCaseInput = {
|
import type { CustomerInvoiceApplicationService } from "../../services";
|
||||||
|
|
||||||
|
type DeleteProformaUseCaseInput = {
|
||||||
companyId: UniqueID;
|
companyId: UniqueID;
|
||||||
invoice_id: string;
|
proforma_id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class DeleteCustomerInvoiceUseCase {
|
export class DeleteProformaUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly service: CustomerInvoiceApplicationService,
|
private readonly service: CustomerInvoiceApplicationService,
|
||||||
private readonly transactionManager: ITransactionManager
|
private readonly transactionManager: ITransactionManager
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public execute(params: DeleteCustomerInvoiceUseCaseInput) {
|
public execute(params: DeleteProformaUseCaseInput) {
|
||||||
const { invoice_id, companyId } = params;
|
const { proforma_id, companyId } = params;
|
||||||
|
|
||||||
const idOrError = UniqueID.create(invoice_id);
|
const idOrError = UniqueID.create(proforma_id);
|
||||||
|
|
||||||
if (idOrError.isFailure) {
|
if (idOrError.isFailure) {
|
||||||
return Result.fail(idOrError.error);
|
return Result.fail(idOrError.error);
|
||||||
@ -40,9 +41,7 @@ export class DeleteCustomerInvoiceUseCase {
|
|||||||
const invoiceExists = existsCheck.data;
|
const invoiceExists = existsCheck.data;
|
||||||
|
|
||||||
if (!invoiceExists) {
|
if (!invoiceExists) {
|
||||||
return Result.fail(
|
return Result.fail(new EntityNotFoundError("Proforma", "id", invoiceId.toString()));
|
||||||
new EntityNotFoundError("Customer invoice", "id", invoiceId.toString())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.service.deleteInvoiceByIdInCompany(companyId, invoiceId, transaction);
|
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 { UniqueID, UtcDate } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
IssueCustomerInvoiceDomainService,
|
IssueCustomerInvoiceDomainService,
|
||||||
ProformaCustomerInvoiceDomainService,
|
ProformaCustomerInvoiceDomainService,
|
||||||
} from "../../domain";
|
} from "../../../domain";
|
||||||
import { CustomerInvoiceFullPresenter } from "../presenters";
|
import type { CustomerInvoiceFullPresenter } from "../../presenters";
|
||||||
import { CustomerInvoiceApplicationService } from "../services";
|
import type { CustomerInvoiceApplicationService } from "../../services";
|
||||||
|
|
||||||
type IssueCustomerInvoiceUseCaseInput = {
|
type IssueCustomerInvoiceUseCaseInput = {
|
||||||
companyId: UniqueID;
|
companyId: UniqueID;
|
||||||
@ -22,7 +23,7 @@ type IssueCustomerInvoiceUseCaseInput = {
|
|||||||
* - Marca la proforma como "issued"
|
* - Marca la proforma como "issued"
|
||||||
* - Persiste ambas dentro de la misma transacción
|
* - Persiste ambas dentro de la misma transacción
|
||||||
*/
|
*/
|
||||||
export class IssueCustomerInvoiceUseCase {
|
export class IssueProformaInvoiceUseCase {
|
||||||
private readonly issueDomainService: IssueCustomerInvoiceDomainService;
|
private readonly issueDomainService: IssueCustomerInvoiceDomainService;
|
||||||
private readonly proformaDomainService: ProformaCustomerInvoiceDomainService;
|
private readonly proformaDomainService: ProformaCustomerInvoiceDomainService;
|
||||||
|
|
||||||
@ -1,18 +1,19 @@
|
|||||||
import { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
import type { IPresenterRegistry, ITransactionManager } from "@erp/core/api";
|
||||||
import { Criteria } from "@repo/rdx-criteria/server";
|
import type { Criteria } from "@repo/rdx-criteria/server";
|
||||||
import { UniqueID } from "@repo/rdx-ddd";
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { Transaction } from "sequelize";
|
import type { Transaction } from "sequelize";
|
||||||
import { ListCustomerInvoicesResponseDTO } from "../../../common/dto";
|
|
||||||
import { ListCustomerInvoicesPresenter } from "../presenters";
|
|
||||||
import { CustomerInvoiceApplicationService } from "../services";
|
|
||||||
|
|
||||||
type ListCustomerInvoicesUseCaseInput = {
|
import type { ListIssueInvoicesResponseDTO } from "../../../../common/dto";
|
||||||
|
import type { ListCustomerInvoicesPresenter } from "../../presenters";
|
||||||
|
import type { CustomerInvoiceApplicationService } from "../../services";
|
||||||
|
|
||||||
|
type ListProformasUseCaseInput = {
|
||||||
companyId: UniqueID;
|
companyId: UniqueID;
|
||||||
criteria: Criteria;
|
criteria: Criteria;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ListCustomerInvoicesUseCase {
|
export class ListProformasUseCase {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly service: CustomerInvoiceApplicationService,
|
private readonly service: CustomerInvoiceApplicationService,
|
||||||
private readonly transactionManager: ITransactionManager,
|
private readonly transactionManager: ITransactionManager,
|
||||||
@ -20,8 +21,8 @@ export class ListCustomerInvoicesUseCase {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
public execute(
|
public execute(
|
||||||
params: ListCustomerInvoicesUseCaseInput
|
params: ListProformasUseCaseInput
|
||||||
): Promise<Result<ListCustomerInvoicesResponseDTO, Error>> {
|
): Promise<Result<ListIssueInvoicesResponseDTO, Error>> {
|
||||||
const { criteria, companyId } = params;
|
const { criteria, companyId } = params;
|
||||||
const presenter = this.presenterRegistry.getPresenter({
|
const presenter = this.presenterRegistry.getPresenter({
|
||||||
resource: "customer-invoice",
|
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 { readFileSync } from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
|
||||||
import { Presenter } from "@erp/core/api";
|
import { Presenter } from "@erp/core/api";
|
||||||
import * as handlebars from "handlebars";
|
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 {
|
export class CustomerInvoiceReportHTMLPresenter extends Presenter {
|
||||||
toOutput(customerInvoice: CustomerInvoice): string {
|
toOutput(customerInvoice: CustomerInvoice): string {
|
||||||
@ -1,8 +1,10 @@
|
|||||||
import { Presenter } from "@erp/core/api";
|
import { Presenter } from "@erp/core/api";
|
||||||
import puppeteer from "puppeteer";
|
import puppeteer from "puppeteer";
|
||||||
import report from "puppeteer-report";
|
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
|
// 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,
|
UniqueID,
|
||||||
UtcDate,
|
UtcDate,
|
||||||
ValidationErrorCollection,
|
ValidationErrorCollection,
|
||||||
ValidationErrorDetail,
|
type ValidationErrorDetail,
|
||||||
extractOrPushError,
|
extractOrPushError,
|
||||||
maybeFromNullableVO,
|
maybeFromNullableVO,
|
||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import { Result, isNullishOrEmpty, toPatchField } from "@repo/rdx-utils";
|
import { Result, isNullishOrEmpty, toPatchField } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import { UpdateCustomerInvoiceByIdRequestDTO } from "../../../../common/dto";
|
import type { UpdateProformaByIdRequestDTO } from "../../../../../common/dto";
|
||||||
import { CustomerInvoicePatchProps, CustomerInvoiceSerie } from "../../../domain";
|
import { type CustomerInvoicePatchProps, CustomerInvoiceSerie } from "../../../../domain";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mapDTOToUpdateCustomerInvoicePatchProps
|
* mapDTOToUpdateCustomerInvoicePatchProps
|
||||||
@ -29,7 +29,7 @@ import { CustomerInvoicePatchProps, CustomerInvoiceSerie } from "../../../domain
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function mapDTOToUpdateCustomerInvoicePatchProps(dto: UpdateCustomerInvoiceByIdRequestDTO) {
|
export function mapDTOToUpdateCustomerInvoicePatchProps(dto: UpdateProformaByIdRequestDTO) {
|
||||||
try {
|
try {
|
||||||
const errors: ValidationErrorDetail[] = [];
|
const errors: ValidationErrorDetail[] = [];
|
||||||
const props: CustomerInvoicePatchProps = {};
|
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 { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
import { Transaction } from "sequelize";
|
import type { Transaction } from "sequelize";
|
||||||
import { UpdateCustomerInvoiceByIdRequestDTO } from "../../../../common";
|
|
||||||
import { CustomerInvoicePatchProps } from "../../../domain";
|
import type { UpdateProformaByIdRequestDTO } from "../../../../../common";
|
||||||
import { CustomerInvoiceFullPresenter } from "../../presenters";
|
import type { CustomerInvoicePatchProps } from "../../../../domain";
|
||||||
import { CustomerInvoiceApplicationService } from "../../services/customer-invoice-application.service";
|
import type { CustomerInvoiceFullPresenter } from "../../../presenters";
|
||||||
|
import type { CustomerInvoiceApplicationService } from "../../../services/customer-invoice-application.service";
|
||||||
|
|
||||||
import { mapDTOToUpdateCustomerInvoicePatchProps } from "./map-dto-to-update-customer-invoice-props";
|
import { mapDTOToUpdateCustomerInvoicePatchProps } from "./map-dto-to-update-customer-invoice-props";
|
||||||
|
|
||||||
type UpdateCustomerInvoiceUseCaseInput = {
|
type UpdateCustomerInvoiceUseCaseInput = {
|
||||||
companyId: UniqueID;
|
companyId: UniqueID;
|
||||||
invoice_id: string;
|
proforma_id: string;
|
||||||
dto: UpdateCustomerInvoiceByIdRequestDTO;
|
dto: UpdateProformaByIdRequestDTO;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class UpdateCustomerInvoiceUseCase {
|
export class UpdateCustomerInvoiceUseCase {
|
||||||
@ -22,9 +24,9 @@ export class UpdateCustomerInvoiceUseCase {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
public execute(params: UpdateCustomerInvoiceUseCaseInput) {
|
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) {
|
if (idOrError.isFailure) {
|
||||||
return Result.fail(idOrError.error);
|
return Result.fail(idOrError.error);
|
||||||
}
|
}
|
||||||
@ -45,7 +47,7 @@ export class UpdateCustomerInvoiceUseCase {
|
|||||||
|
|
||||||
return this.transactionManager.complete(async (transaction: Transaction) => {
|
return this.transactionManager.complete(async (transaction: Transaction) => {
|
||||||
try {
|
try {
|
||||||
const updatedInvoice = await this.service.patchInvoiceByIdInCompany(
|
const updatedInvoice = await this.service.patchProformaByIdInCompany(
|
||||||
companyId,
|
companyId,
|
||||||
invoiceId,
|
invoiceId,
|
||||||
patchProps,
|
patchProps,
|
||||||
@ -56,7 +58,7 @@ export class UpdateCustomerInvoiceUseCase {
|
|||||||
return Result.fail(updatedInvoice.error);
|
return Result.fail(updatedInvoice.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const invoiceOrError = await this.service.updateInvoiceInCompany(
|
const invoiceOrError = await this.service.updateProformaInCompany(
|
||||||
companyId,
|
companyId,
|
||||||
updatedInvoice.data,
|
updatedInvoice.data,
|
||||||
transaction
|
transaction
|
||||||
@ -1,2 +0,0 @@
|
|||||||
export * from "./report-customer-invoice.use-case";
|
|
||||||
export * from "./reporter";
|
|
||||||
@ -1,21 +1,22 @@
|
|||||||
import {
|
import {
|
||||||
AggregateRoot,
|
AggregateRoot,
|
||||||
CurrencyCode,
|
type CurrencyCode,
|
||||||
DomainValidationError,
|
DomainValidationError,
|
||||||
LanguageCode,
|
type LanguageCode,
|
||||||
Percentage,
|
type Percentage,
|
||||||
TextValue,
|
type TextValue,
|
||||||
UniqueID,
|
type UniqueID,
|
||||||
UtcDate,
|
type UtcDate,
|
||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { type Maybe, Result } from "@repo/rdx-utils";
|
||||||
import { CustomerInvoiceItems, InvoicePaymentMethod, InvoiceTaxTotal } from "../entities";
|
|
||||||
|
import { CustomerInvoiceItems, type InvoicePaymentMethod, type InvoiceTaxTotal } from "../entities";
|
||||||
import {
|
import {
|
||||||
CustomerInvoiceNumber,
|
type CustomerInvoiceNumber,
|
||||||
CustomerInvoiceSerie,
|
type CustomerInvoiceSerie,
|
||||||
CustomerInvoiceStatus,
|
type CustomerInvoiceStatus,
|
||||||
InvoiceAmount,
|
InvoiceAmount,
|
||||||
InvoiceRecipient,
|
type InvoiceRecipient,
|
||||||
} from "../value-objects";
|
} from "../value-objects";
|
||||||
|
|
||||||
export interface CustomerInvoiceProps {
|
export interface CustomerInvoiceProps {
|
||||||
@ -24,7 +25,7 @@ export interface CustomerInvoiceProps {
|
|||||||
isProforma: boolean;
|
isProforma: boolean;
|
||||||
status: CustomerInvoiceStatus;
|
status: CustomerInvoiceStatus;
|
||||||
|
|
||||||
proformaId: Maybe<UniqueID>;
|
proformaId: Maybe<UniqueID>; // <- proforma padre en caso de issue
|
||||||
|
|
||||||
series: Maybe<CustomerInvoiceSerie>;
|
series: Maybe<CustomerInvoiceSerie>;
|
||||||
invoiceNumber: CustomerInvoiceNumber;
|
invoiceNumber: CustomerInvoiceNumber;
|
||||||
@ -106,7 +107,7 @@ export class CustomerInvoice
|
|||||||
|
|
||||||
// Reglas de negocio / validaciones
|
// Reglas de negocio / validaciones
|
||||||
|
|
||||||
if (!customerInvoice.isProforma && !customerInvoice.hasRecipient) {
|
if (!(customerInvoice.isProforma || customerInvoice.hasRecipient)) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
new DomainValidationError(
|
new DomainValidationError(
|
||||||
"MISSING_CUSTOMER_DATA",
|
"MISSING_CUSTOMER_DATA",
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import { Criteria } from "@repo/rdx-criteria/server";
|
import type { Criteria } from "@repo/rdx-criteria/server";
|
||||||
import { UniqueID } from "@repo/rdx-ddd";
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Collection, Result } from "@repo/rdx-utils";
|
import type { Collection, Result } from "@repo/rdx-utils";
|
||||||
import { CustomerInvoiceListDTO } from "../../infrastructure";
|
|
||||||
import { CustomerInvoice } from "../aggregates";
|
import type { CustomerInvoiceListDTO } from "../../infrastructure";
|
||||||
import { CustomerInvoiceStatus } from "../value-objects";
|
import type { CustomerInvoice } from "../aggregates";
|
||||||
|
import type { CustomerInvoiceStatus } from "../value-objects";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interfaz del repositorio para el agregado `CustomerInvoice`.
|
* Interfaz del repositorio para el agregado `CustomerInvoice`.
|
||||||
@ -45,7 +46,8 @@ export interface ICustomerInvoiceRepository {
|
|||||||
getByIdInCompany(
|
getByIdInCompany(
|
||||||
companyId: UniqueID,
|
companyId: UniqueID,
|
||||||
id: UniqueID,
|
id: UniqueID,
|
||||||
transaction?: unknown
|
transaction: unknown,
|
||||||
|
options: unknown
|
||||||
): Promise<Result<CustomerInvoice, Error>>;
|
): Promise<Result<CustomerInvoice, Error>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import { IModuleServer, ModuleParams } from "@erp/core/api";
|
import type { IModuleServer, ModuleParams } from "@erp/core/api";
|
||||||
import { UniqueID } from "@repo/rdx-ddd";
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Transaction } from "sequelize";
|
import type { Transaction } from "sequelize";
|
||||||
import { buildCustomerInvoiceDependencies, customerInvoicesRouter, models } from "./infrastructure";
|
|
||||||
|
import { buildCustomerInvoiceDependencies, models, proformasRouter } from "./infrastructure";
|
||||||
|
import { issueInvoicesRouter } from "./infrastructure/express/issue-invoices.routes";
|
||||||
|
|
||||||
export const customerInvoicesAPIModule: IModuleServer = {
|
export const customerInvoicesAPIModule: IModuleServer = {
|
||||||
name: "customer-invoices",
|
name: "customer-invoices",
|
||||||
@ -11,7 +13,8 @@ export const customerInvoicesAPIModule: IModuleServer = {
|
|||||||
async init(params: ModuleParams) {
|
async init(params: ModuleParams) {
|
||||||
// const contacts = getService<ContactsService>("contacts");
|
// const contacts = getService<ContactsService>("contacts");
|
||||||
const { logger } = params;
|
const { logger } = params;
|
||||||
customerInvoicesRouter(params);
|
proformasRouter(params);
|
||||||
|
issueInvoicesRouter(params);
|
||||||
logger.info("🚀 CustomerInvoices module initialized", { label: this.name });
|
logger.info("🚀 CustomerInvoices module initialized", { label: this.name });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
// modules/invoice/infrastructure/invoice-dependencies.factory.ts
|
// 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 type { IMapperRegistry, IPresenterRegistry, ModuleParams } from "@erp/core/api";
|
||||||
import {
|
import {
|
||||||
InMemoryMapperRegistry,
|
InMemoryMapperRegistry,
|
||||||
InMemoryPresenterRegistry,
|
InMemoryPresenterRegistry,
|
||||||
SequelizeTransactionManager,
|
SequelizeTransactionManager,
|
||||||
} from "@erp/core/api";
|
} from "@erp/core/api";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ChangeStatusCustomerInvoiceUseCase,
|
ChangeStatusProformaUseCase,
|
||||||
CreateCustomerInvoiceUseCase,
|
CreateProformaUseCase,
|
||||||
CustomerInvoiceApplicationService,
|
CustomerInvoiceApplicationService,
|
||||||
CustomerInvoiceFullPresenter,
|
CustomerInvoiceFullPresenter,
|
||||||
CustomerInvoiceItemsFullPresenter,
|
CustomerInvoiceItemsFullPresenter,
|
||||||
@ -17,14 +18,15 @@ import {
|
|||||||
CustomerInvoiceReportHTMLPresenter,
|
CustomerInvoiceReportHTMLPresenter,
|
||||||
CustomerInvoiceReportPDFPresenter,
|
CustomerInvoiceReportPDFPresenter,
|
||||||
CustomerInvoiceReportPresenter,
|
CustomerInvoiceReportPresenter,
|
||||||
GetCustomerInvoiceUseCase,
|
GetProformaUseCase,
|
||||||
IssueCustomerInvoiceUseCase,
|
IssueProformaInvoiceUseCase,
|
||||||
ListCustomerInvoicesPresenter,
|
ListCustomerInvoicesPresenter,
|
||||||
ListCustomerInvoicesUseCase,
|
ListProformasUseCase,
|
||||||
RecipientInvoiceFullPresenter,
|
RecipientInvoiceFullPresenter,
|
||||||
ReportCustomerInvoiceUseCase,
|
ReportProformaUseCase,
|
||||||
UpdateCustomerInvoiceUseCase,
|
UpdateCustomerInvoiceUseCase,
|
||||||
} from "../application";
|
} from "../application";
|
||||||
|
|
||||||
import { CustomerInvoiceDomainMapper, CustomerInvoiceListMapper } from "./mappers";
|
import { CustomerInvoiceDomainMapper, CustomerInvoiceListMapper } from "./mappers";
|
||||||
import { CustomerInvoiceRepository } from "./sequelize";
|
import { CustomerInvoiceRepository } from "./sequelize";
|
||||||
import { SequelizeInvoiceNumberGenerator } from "./services";
|
import { SequelizeInvoiceNumberGenerator } from "./services";
|
||||||
@ -39,14 +41,14 @@ export type CustomerInvoiceDeps = {
|
|||||||
taxes: JsonTaxCatalogProvider;
|
taxes: JsonTaxCatalogProvider;
|
||||||
};
|
};
|
||||||
useCases: {
|
useCases: {
|
||||||
list: () => ListCustomerInvoicesUseCase;
|
list: () => ListProformasUseCase;
|
||||||
get: () => GetCustomerInvoiceUseCase;
|
get: () => GetProformaUseCase;
|
||||||
create: () => CreateCustomerInvoiceUseCase;
|
create: () => CreateProformaUseCase;
|
||||||
update: () => UpdateCustomerInvoiceUseCase;
|
update: () => UpdateCustomerInvoiceUseCase;
|
||||||
//delete: () => DeleteCustomerInvoiceUseCase;
|
//delete: () => DeleteCustomerInvoiceUseCase;
|
||||||
report: () => ReportCustomerInvoiceUseCase;
|
report: () => ReportProformaUseCase;
|
||||||
issue: () => IssueCustomerInvoiceUseCase;
|
issue: () => IssueProformaInvoiceUseCase;
|
||||||
changeStatus: () => ChangeStatusCustomerInvoiceUseCase;
|
changeStatus: () => ChangeStatusProformaUseCase;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -117,21 +119,15 @@ export function buildCustomerInvoiceDependencies(params: ModuleParams): Customer
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const useCases = {
|
const useCases = {
|
||||||
list: () => new ListCustomerInvoicesUseCase(appService, transactionManager, presenterRegistry),
|
list: () => new ListProformasUseCase(appService, transactionManager, presenterRegistry),
|
||||||
get: () => new GetCustomerInvoiceUseCase(appService, transactionManager, presenterRegistry),
|
get: () => new GetProformaUseCase(appService, transactionManager, presenterRegistry),
|
||||||
create: () =>
|
create: () =>
|
||||||
new CreateCustomerInvoiceUseCase(
|
new CreateProformaUseCase(appService, transactionManager, presenterRegistry, catalogs.taxes),
|
||||||
appService,
|
|
||||||
transactionManager,
|
|
||||||
presenterRegistry,
|
|
||||||
catalogs.taxes
|
|
||||||
),
|
|
||||||
update: () =>
|
update: () =>
|
||||||
new UpdateCustomerInvoiceUseCase(appService, transactionManager, presenterRegistry),
|
new UpdateCustomerInvoiceUseCase(appService, transactionManager, presenterRegistry),
|
||||||
report: () =>
|
report: () => new ReportProformaUseCase(appService, transactionManager, presenterRegistry),
|
||||||
new ReportCustomerInvoiceUseCase(appService, transactionManager, presenterRegistry),
|
issue: () => new IssueProformaInvoiceUseCase(appService, transactionManager, presenterRegistry),
|
||||||
issue: () => new IssueCustomerInvoiceUseCase(appService, transactionManager, presenterRegistry),
|
changeStatus: () => new ChangeStatusProformaUseCase(appService, transactionManager),
|
||||||
changeStatus: () => new ChangeStatusCustomerInvoiceUseCase(appService, transactionManager),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
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 "./issue-invoices";
|
||||||
export * from "./create-customer-invoice.controller";
|
export * from "./proformas";
|
||||||
//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";
|
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import { authGuard, ExpressController, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
import { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||||
import { GetCustomerInvoiceUseCase } from "../../../application";
|
|
||||||
import { customerInvoicesApiErrorMapper } from "../customer-invoices-api-error-mapper";
|
|
||||||
|
|
||||||
export class GetCustomerInvoiceController extends ExpressController {
|
import type { GetProformaUseCase } from "../../../../application";
|
||||||
public constructor(private readonly useCase: GetCustomerInvoiceUseCase) {
|
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||||
|
|
||||||
|
export class GetIssueInvoiceController extends ExpressController {
|
||||||
|
public constructor(private readonly useCase: GetProformaUseCase) {
|
||||||
super();
|
super();
|
||||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ export class GetCustomerInvoiceController extends ExpressController {
|
|||||||
}
|
}
|
||||||
const { invoice_id } = this.req.params;
|
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(
|
return result.match(
|
||||||
(data) => this.ok(data),
|
(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 { Criteria } from "@repo/rdx-criteria/server";
|
||||||
import { ListCustomerInvoicesUseCase } from "../../../application";
|
|
||||||
import { customerInvoicesApiErrorMapper } from "../customer-invoices-api-error-mapper";
|
|
||||||
|
|
||||||
export class ListCustomerInvoicesController extends ExpressController {
|
import type { ListProformasUseCase } from "../../../../application";
|
||||||
public constructor(private readonly useCase: ListCustomerInvoicesUseCase) {
|
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||||
|
|
||||||
|
export class ListIssueInvoicesController extends ExpressController {
|
||||||
|
public constructor(private readonly useCase: ListProformasUseCase) {
|
||||||
super();
|
super();
|
||||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||||
|
|
||||||
@ -1,10 +1,11 @@
|
|||||||
import { authGuard, ExpressController, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
import { ExpressController, authGuard, 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";
|
|
||||||
|
|
||||||
export class ChangeStatusCustomerInvoiceController extends ExpressController {
|
import type { ChangeStatusProformaByIdRequestDTO } from "../../../../../common/dto";
|
||||||
public constructor(private readonly useCase: ChangeStatusCustomerInvoiceUseCase) {
|
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();
|
super();
|
||||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ export class ChangeStatusCustomerInvoiceController extends ExpressController {
|
|||||||
this.registerGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
this.registerGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeImpl(): Promise<any> {
|
protected async executeImpl() {
|
||||||
const companyId = this.getTenantId(); // garantizado por tenantGuard
|
const companyId = this.getTenantId(); // garantizado por tenantGuard
|
||||||
if (!companyId) {
|
if (!companyId) {
|
||||||
return this.forbiddenError("Tenant ID not found");
|
return this.forbiddenError("Tenant ID not found");
|
||||||
@ -23,7 +24,7 @@ export class ChangeStatusCustomerInvoiceController extends ExpressController {
|
|||||||
return this.invalidInputError("Proforma ID missing");
|
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 });
|
const result = await this.useCase.execute({ proforma_id, dto, companyId });
|
||||||
|
|
||||||
return result.match(
|
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 type { CreateProformaRequestDTO } from "../../../../../common/dto";
|
||||||
import { CreateCustomerInvoiceUseCase } from "../../../application";
|
import type { CreateProformaUseCase } from "../../../../application";
|
||||||
import { customerInvoicesApiErrorMapper } from "../customer-invoices-api-error-mapper";
|
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||||
|
|
||||||
export class CreateCustomerInvoiceController extends ExpressController {
|
export class CreateProformaController extends ExpressController {
|
||||||
public constructor(private readonly useCase: CreateCustomerInvoiceUseCase) {
|
public constructor(private readonly useCase: CreateProformaUseCase) {
|
||||||
super();
|
super();
|
||||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ export class CreateCustomerInvoiceController extends ExpressController {
|
|||||||
if (!companyId) {
|
if (!companyId) {
|
||||||
return this.forbiddenError("Tenant ID not found");
|
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 });
|
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 { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||||
import { IssueCustomerInvoiceUseCase } from "../../../application";
|
|
||||||
import { customerInvoicesApiErrorMapper } from "../customer-invoices-api-error-mapper";
|
|
||||||
|
|
||||||
export class IssueCustomerInvoiceController extends ExpressController {
|
import type { IssueProformaInvoiceUseCase } from "../../../../application";
|
||||||
public constructor(private readonly useCase: IssueCustomerInvoiceUseCase) {
|
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||||
|
|
||||||
|
export class IssueProformaController extends ExpressController {
|
||||||
|
public constructor(private readonly useCase: IssueProformaInvoiceUseCase) {
|
||||||
super();
|
super();
|
||||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ export class IssueCustomerInvoiceController extends ExpressController {
|
|||||||
this.registerGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
this.registerGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeImpl(): Promise<any> {
|
protected async executeImpl() {
|
||||||
const companyId = this.getTenantId(); // garantizado por tenantGuard
|
const companyId = this.getTenantId(); // garantizado por tenantGuard
|
||||||
if (!companyId) {
|
if (!companyId) {
|
||||||
return this.forbiddenError("Tenant ID not found");
|
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 { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||||
import { ReportCustomerInvoiceUseCase } from "../../../application";
|
|
||||||
import { customerInvoicesApiErrorMapper } from "../customer-invoices-api-error-mapper";
|
|
||||||
|
|
||||||
export class ReportCustomerInvoiceController extends ExpressController {
|
import type { ReportProformaUseCase } from "../../../../application";
|
||||||
public constructor(private readonly useCase: ReportCustomerInvoiceUseCase) {
|
import { customerInvoicesApiErrorMapper } from "../../customer-invoices-api-error-mapper";
|
||||||
|
|
||||||
|
export class ReportProformaController extends ExpressController {
|
||||||
|
public constructor(private readonly useCase: ReportProformaUseCase) {
|
||||||
super();
|
super();
|
||||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||||
|
|
||||||
@ -16,9 +17,9 @@ export class ReportCustomerInvoiceController extends ExpressController {
|
|||||||
if (!companyId) {
|
if (!companyId) {
|
||||||
return this.forbiddenError("Tenant ID not found");
|
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(
|
return result.match(
|
||||||
({ data, filename }) => this.downloadPDF(data, filename),
|
({ data, filename }) => this.downloadPDF(data, filename),
|
||||||
@ -1,9 +1,10 @@
|
|||||||
import { authGuard, ExpressController, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
import { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from "@erp/core/api";
|
||||||
import { UpdateCustomerInvoiceByIdRequestDTO } from "../../../../common/dto";
|
|
||||||
import { UpdateCustomerInvoiceUseCase } from "../../../application";
|
|
||||||
import { customerInvoicesApiErrorMapper } from "../customer-invoices-api-error-mapper";
|
|
||||||
|
|
||||||
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) {
|
public constructor(private readonly useCase: UpdateCustomerInvoiceUseCase) {
|
||||||
super();
|
super();
|
||||||
this.errorMapper = customerInvoicesApiErrorMapper;
|
this.errorMapper = customerInvoicesApiErrorMapper;
|
||||||
@ -12,7 +13,7 @@ export class UpdateCustomerInvoiceController extends ExpressController {
|
|||||||
this.registerGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
this.registerGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId"));
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeImpl(): Promise<any> {
|
protected async executeImpl() {
|
||||||
const companyId = this.getTenantId();
|
const companyId = this.getTenantId();
|
||||||
if (!companyId) {
|
if (!companyId) {
|
||||||
return this.forbiddenError("Tenant ID not found");
|
return this.forbiddenError("Tenant ID not found");
|
||||||
@ -23,9 +24,9 @@ export class UpdateCustomerInvoiceController extends ExpressController {
|
|||||||
return this.invalidInputError("Proforma ID missing");
|
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(
|
return result.match(
|
||||||
(data) => this.ok(data),
|
(data) => this.ok(data),
|
||||||
@ -4,16 +4,17 @@
|
|||||||
import {
|
import {
|
||||||
ApiErrorMapper,
|
ApiErrorMapper,
|
||||||
ConflictApiError,
|
ConflictApiError,
|
||||||
ErrorToApiRule,
|
type ErrorToApiRule,
|
||||||
ValidationApiError,
|
ValidationApiError,
|
||||||
} from "@erp/core/api";
|
} from "@erp/core/api";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CustomerInvoiceIdAlreadyExistsError,
|
type CustomerInvoiceIdAlreadyExistsError,
|
||||||
EntityIsNotProformaError,
|
type EntityIsNotProformaError,
|
||||||
|
type ProformaCannotBeConvertedToInvoiceError,
|
||||||
isCustomerInvoiceIdAlreadyExistsError,
|
isCustomerInvoiceIdAlreadyExistsError,
|
||||||
isEntityIsNotProformaError,
|
isEntityIsNotProformaError,
|
||||||
isProformaCannotBeConvertedToInvoiceError,
|
isProformaCannotBeConvertedToInvoiceError,
|
||||||
ProformaCannotBeConvertedToInvoiceError,
|
|
||||||
} from "../../domain";
|
} from "../../domain";
|
||||||
|
|
||||||
// Crea una regla específica (prioridad alta para sobreescribir mensajes)
|
// 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 { type RequestWithAuth, enforceTenant, enforceUser, mockUser } from "@erp/auth/api";
|
||||||
import { ModuleParams, validateRequest } from "@erp/core/api";
|
import { type 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 {
|
import {
|
||||||
ChangeStatusCustomerInvoiceByIdParamsRequestSchema,
|
ChangeStatusProformaByIdParamsRequestSchema,
|
||||||
ChangeStatusCustomerInvoiceByIdRequestSchema,
|
ChangeStatusProformaByIdRequestSchema,
|
||||||
CreateCustomerInvoiceRequestSchema,
|
CreateProformaRequestSchema,
|
||||||
CustomerInvoiceListRequestSchema,
|
GetProformaByIdRequestSchema,
|
||||||
GetCustomerInvoiceByIdRequestSchema,
|
ListProformasRequestSchema,
|
||||||
ReportCustomerInvoiceByIdRequestSchema,
|
ReportProformaByIdRequestSchema,
|
||||||
UpdateCustomerInvoiceByIdParamsRequestSchema,
|
UpdateProformaByIdParamsRequestSchema,
|
||||||
UpdateCustomerInvoiceByIdRequestSchema,
|
UpdateProformaByIdRequestSchema,
|
||||||
} from "../../../common/dto";
|
} from "@erp/customer-invoices/common";
|
||||||
import { buildCustomerInvoiceDependencies } from "../dependencies";
|
import type { ILogger } from "@repo/rdx-logger";
|
||||||
import {
|
import { type Application, type NextFunction, type Request, type Response, Router } from "express";
|
||||||
ChangeStatusCustomerInvoiceController,
|
import type { Sequelize } from "sequelize";
|
||||||
CreateCustomerInvoiceController,
|
|
||||||
GetCustomerInvoiceController,
|
|
||||||
ListCustomerInvoicesController,
|
|
||||||
ReportCustomerInvoiceController,
|
|
||||||
UpdateCustomerInvoiceController,
|
|
||||||
} from "./controllers";
|
|
||||||
import { IssueCustomerInvoiceController } from "./controllers/issue-customer-invoice.controller";
|
|
||||||
|
|
||||||
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 {
|
const { app, baseRoutePath, logger } = params as {
|
||||||
app: Application;
|
app: Application;
|
||||||
database: Sequelize;
|
database: Sequelize;
|
||||||
@ -56,21 +58,21 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
|||||||
router.get(
|
router.get(
|
||||||
"/",
|
"/",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
validateRequest(CustomerInvoiceListRequestSchema, "params"),
|
validateRequest(ListProformasRequestSchema, "params"),
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const useCase = deps.useCases.list();
|
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);
|
return controller.execute(req, res, next);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
"/:invoice_id",
|
"/:proforma_id",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
validateRequest(GetCustomerInvoiceByIdRequestSchema, "params"),
|
validateRequest(GetProformaByIdRequestSchema, "params"),
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
const useCase = deps.useCases.get();
|
const useCase = deps.useCases.get();
|
||||||
const controller = new GetCustomerInvoiceController(useCase);
|
const controller = new GetProformaController(useCase);
|
||||||
return controller.execute(req, res, next);
|
return controller.execute(req, res, next);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -79,10 +81,10 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
|||||||
"/",
|
"/",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
|
|
||||||
validateRequest(CreateCustomerInvoiceRequestSchema, "body"),
|
validateRequest(CreateProformaRequestSchema, "body"),
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
const useCase = deps.useCases.create();
|
const useCase = deps.useCases.create();
|
||||||
const controller = new CreateCustomerInvoiceController(useCase);
|
const controller = new CreateProformaController(useCase);
|
||||||
return controller.execute(req, res, next);
|
return controller.execute(req, res, next);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -91,17 +93,17 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
|||||||
"/:proforma_id",
|
"/:proforma_id",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
|
|
||||||
validateRequest(UpdateCustomerInvoiceByIdParamsRequestSchema, "params"),
|
validateRequest(UpdateProformaByIdParamsRequestSchema, "params"),
|
||||||
validateRequest(UpdateCustomerInvoiceByIdRequestSchema, "body"),
|
validateRequest(UpdateProformaByIdRequestSchema, "body"),
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
const useCase = deps.useCases.update();
|
const useCase = deps.useCases.update();
|
||||||
const controller = new UpdateCustomerInvoiceController(useCase);
|
const controller = new UpdateProformaController(useCase);
|
||||||
return controller.execute(req, res, next);
|
return controller.execute(req, res, next);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
/*router.delete(
|
/*router.delete(
|
||||||
"/:invoice_id",
|
"/:proforma_id",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
|
|
||||||
validateRequest(DeleteCustomerInvoiceByIdRequestSchema, "params"),
|
validateRequest(DeleteCustomerInvoiceByIdRequestSchema, "params"),
|
||||||
@ -113,12 +115,12 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
|||||||
);*/
|
);*/
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
"/:invoice_id/report",
|
"/:proforma_id/report",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
validateRequest(ReportCustomerInvoiceByIdRequestSchema, "params"),
|
validateRequest(ReportProformaByIdRequestSchema, "params"),
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
const useCase = deps.useCases.report();
|
const useCase = deps.useCases.report();
|
||||||
const controller = new ReportCustomerInvoiceController(useCase);
|
const controller = new ReportProformaController(useCase);
|
||||||
return controller.execute(req, res, next);
|
return controller.execute(req, res, next);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -127,12 +129,12 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
|||||||
"/:proforma_id/status",
|
"/:proforma_id/status",
|
||||||
//checkTabContext,
|
//checkTabContext,
|
||||||
|
|
||||||
validateRequest(ChangeStatusCustomerInvoiceByIdParamsRequestSchema, "params"),
|
validateRequest(ChangeStatusProformaByIdParamsRequestSchema, "params"),
|
||||||
validateRequest(ChangeStatusCustomerInvoiceByIdRequestSchema, "body"),
|
validateRequest(ChangeStatusProformaByIdRequestSchema, "body"),
|
||||||
|
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
const useCase = deps.useCases.changeStatus();
|
const useCase = deps.useCases.changeStatus();
|
||||||
const controller = new ChangeStatusCustomerInvoiceController(useCase);
|
const controller = new ChangeStatusProformaController(useCase);
|
||||||
return controller.execute(req, res, next);
|
return controller.execute(req, res, next);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -146,10 +148,10 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
|||||||
|
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
const useCase = deps.useCases.issue();
|
const useCase = deps.useCases.issue();
|
||||||
const controller = new IssueCustomerInvoiceController(useCase);
|
const controller = new IssueProformaController(useCase);
|
||||||
return controller.execute(req, res, next);
|
return controller.execute(req, res, next);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
app.use(`${baseRoutePath}/customer-invoices`, router);
|
app.use(`${baseRoutePath}/proformas`, router);
|
||||||
};
|
};
|
||||||
@ -4,16 +4,22 @@ import {
|
|||||||
SequelizeRepository,
|
SequelizeRepository,
|
||||||
translateSequelizeError,
|
translateSequelizeError,
|
||||||
} from "@erp/core/api";
|
} from "@erp/core/api";
|
||||||
import { Criteria, CriteriaToSequelizeConverter } from "@repo/rdx-criteria/server";
|
import { type Criteria, CriteriaToSequelizeConverter } from "@repo/rdx-criteria/server";
|
||||||
import { UniqueID } from "@repo/rdx-ddd";
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Collection, Result } from "@repo/rdx-utils";
|
import { type Collection, Result } from "@repo/rdx-utils";
|
||||||
import { Transaction } from "sequelize";
|
import type { FindOptions, InferAttributes, Transaction } from "sequelize";
|
||||||
import { CustomerInvoice, CustomerInvoiceStatus, ICustomerInvoiceRepository } from "../../domain";
|
|
||||||
import {
|
import type {
|
||||||
|
CustomerInvoice,
|
||||||
|
CustomerInvoiceStatus,
|
||||||
|
ICustomerInvoiceRepository,
|
||||||
|
} from "../../domain";
|
||||||
|
import type {
|
||||||
CustomerInvoiceListDTO,
|
CustomerInvoiceListDTO,
|
||||||
ICustomerInvoiceDomainMapper,
|
ICustomerInvoiceDomainMapper,
|
||||||
ICustomerInvoiceListMapper,
|
ICustomerInvoiceListMapper,
|
||||||
} from "../mappers";
|
} from "../mappers";
|
||||||
|
|
||||||
import { CustomerInvoiceModel } from "./models/customer-invoice.model";
|
import { CustomerInvoiceModel } from "./models/customer-invoice.model";
|
||||||
import { CustomerInvoiceItemModel } from "./models/customer-invoice-item.model";
|
import { CustomerInvoiceItemModel } from "./models/customer-invoice-item.model";
|
||||||
import { CustomerInvoiceItemTaxModel } from "./models/customer-invoice-item-tax.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 companyId - Identificador UUID de la empresa a la que pertenece la factura.
|
||||||
* @param id - UUID de la factura.
|
* @param id - UUID de la factura.
|
||||||
* @param transaction - Transacción activa para la operación.
|
* @param transaction - Transacción activa para la operación.
|
||||||
|
* @params options - Opciones adicionales para la consulta (Sequelize FindOptions)
|
||||||
* @returns Result<CustomerInvoice, Error>
|
* @returns Result<CustomerInvoice, Error>
|
||||||
*/
|
*/
|
||||||
async getByIdInCompany(
|
async getByIdInCompany(
|
||||||
companyId: UniqueID,
|
companyId: UniqueID,
|
||||||
id: UniqueID,
|
id: UniqueID,
|
||||||
transaction: Transaction
|
transaction: Transaction,
|
||||||
|
options: FindOptions<InferAttributes<CustomerInvoiceModel>> = {}
|
||||||
): Promise<Result<CustomerInvoice, Error>> {
|
): Promise<Result<CustomerInvoice, Error>> {
|
||||||
const { CustomerModel } = this._database.models;
|
const { CustomerModel } = this._database.models;
|
||||||
|
|
||||||
@ -199,14 +207,36 @@ export class CustomerInvoiceRepository
|
|||||||
resource: "customer-invoice",
|
resource: "customer-invoice",
|
||||||
});
|
});
|
||||||
|
|
||||||
const row = await CustomerInvoiceModel.findOne({
|
// Normalización defensiva de order/include
|
||||||
where: { id: id.toString(), company_id: companyId.toString() },
|
const normalizedOrder = Array.isArray(options.order)
|
||||||
order: [[{ model: CustomerInvoiceItemModel, as: "items" }, "position", "ASC"]],
|
? 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: [
|
include: [
|
||||||
|
...normalizedInclude,
|
||||||
{
|
{
|
||||||
model: CustomerModel,
|
model: CustomerModel,
|
||||||
as: "current_customer",
|
as: "current_customer",
|
||||||
required: false, // false => LEFT JOIN
|
required: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
model: CustomerInvoiceItemModel,
|
model: CustomerInvoiceItemModel,
|
||||||
@ -227,7 +257,9 @@ export class CustomerInvoiceRepository
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
transaction,
|
transaction,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
const row = await CustomerInvoiceModel.findOne(mergedOptions);
|
||||||
|
|
||||||
if (!row) {
|
if (!row) {
|
||||||
return Result.fail(new EntityNotFoundError("CustomerInvoice", "id", id.toString()));
|
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 "./issue-invoices";
|
||||||
export * from "./create-customer-invoice.request.dto";
|
export * from "./proformas";
|
||||||
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";
|
|
||||||
|
|||||||
@ -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 { NumericStringSchema, PercentageSchema } from "@erp/core";
|
||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const CreateCustomerInvoiceItemRequestSchema = z.object({
|
export const CreateProformaItemRequestSchema = z.object({
|
||||||
id: z.uuid(),
|
id: z.uuid(),
|
||||||
position: z.string(),
|
position: z.string(),
|
||||||
description: z.string().default(""),
|
description: z.string().default(""),
|
||||||
@ -10,8 +10,9 @@ export const CreateCustomerInvoiceItemRequestSchema = z.object({
|
|||||||
discount_percentage: NumericStringSchema.default(""),
|
discount_percentage: NumericStringSchema.default(""),
|
||||||
taxes: z.string().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(),
|
id: z.uuid(),
|
||||||
|
|
||||||
invoice_number: z.string(),
|
invoice_number: z.string(),
|
||||||
@ -35,10 +36,6 @@ export const CreateCustomerInvoiceRequestSchema = z.object({
|
|||||||
|
|
||||||
payment_method: z.string().default(""),
|
payment_method: z.string().default(""),
|
||||||
|
|
||||||
items: z.array(CreateCustomerInvoiceItemRequestSchema).default([]),
|
items: z.array(CreateProformaItemRequestSchema).default([]),
|
||||||
});
|
});
|
||||||
|
export type CreateProformaRequestDTO = z.infer<typeof CreateProformaRequestSchema>;
|
||||||
export type CreateCustomerInvoiceItemRequestDTO = z.infer<
|
|
||||||
typeof CreateCustomerInvoiceItemRequestSchema
|
|
||||||
>;
|
|
||||||
export type CreateCustomerInvoiceRequestDTO = z.infer<typeof CreateCustomerInvoiceRequestSchema>;
|
|
||||||
@ -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 { MoneySchema, PercentageSchema, QuantitySchema } from "@erp/core";
|
||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const UpdateCustomerInvoiceByIdParamsRequestSchema = z.object({
|
export const UpdateProformaByIdParamsRequestSchema = z.object({
|
||||||
proforma_id: z.string(),
|
proforma_id: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const UpdateCustomerInvoiceByIdRequestSchema = z.object({
|
export const UpdateProformaByIdRequestSchema = z.object({
|
||||||
series: z.string().optional(),
|
series: z.string().optional(),
|
||||||
|
|
||||||
invoice_date: z.string().optional(),
|
invoice_date: z.string().optional(),
|
||||||
@ -38,6 +38,4 @@ export const UpdateCustomerInvoiceByIdRequestSchema = z.object({
|
|||||||
.default([]),
|
.default([]),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type UpdateCustomerInvoiceByIdRequestDTO = Partial<
|
export type UpdateProformaByIdRequestDTO = Partial<z.infer<typeof UpdateProformaByIdRequestSchema>>;
|
||||||
z.infer<typeof UpdateCustomerInvoiceByIdRequestSchema>
|
|
||||||
>;
|
|
||||||
@ -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 "./issue-invoices";
|
||||||
export * from "./get-customer-invoice-by-id.response.dto";
|
export * from "./proformas";
|
||||||
export * from "./list-customer-invoices.response.dto";
|
|
||||||
export * from "./update-customer-invoice-by-id.response.dto";
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { MetadataSchema, MoneySchema, PercentageSchema, QuantitySchema } from "@erp/core";
|
import { MetadataSchema, MoneySchema, PercentageSchema, QuantitySchema } from "@erp/core";
|
||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const GetCustomerInvoiceByIdResponseSchema = z.object({
|
export const GetIssueInvoiceByIdResponseSchema = z.object({
|
||||||
id: z.uuid(),
|
id: z.uuid(),
|
||||||
company_id: z.uuid(),
|
company_id: z.uuid(),
|
||||||
|
|
||||||
@ -79,6 +79,4 @@ export const GetCustomerInvoiceByIdResponseSchema = z.object({
|
|||||||
metadata: MetadataSchema.optional(),
|
metadata: MetadataSchema.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type GetCustomerInvoiceByIdResponseDTO = z.infer<
|
export type GetIssueInvoiceByIdResponseDTO = z.infer<typeof GetIssueInvoiceByIdResponseSchema>;
|
||||||
typeof GetCustomerInvoiceByIdResponseSchema
|
|
||||||
>;
|
|
||||||
@ -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";
|
} from "@erp/core";
|
||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const ListCustomerInvoicesResponseSchema = createPaginatedListSchema(
|
export const ListIssueInvoicesResponseSchema = createPaginatedListSchema(
|
||||||
z.object({
|
z.object({
|
||||||
id: z.uuid(),
|
id: z.uuid(),
|
||||||
company_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";
|
} from "@erp/core";
|
||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
export const CreateCustomerInvoiceResponseSchema = z.object({
|
export const CreateProformaResponseSchema = z.object({
|
||||||
id: z.uuid(),
|
id: z.uuid(),
|
||||||
company_id: z.uuid(),
|
company_id: z.uuid(),
|
||||||
|
|
||||||
@ -52,4 +52,4 @@ export const CreateCustomerInvoiceResponseSchema = z.object({
|
|||||||
metadata: MetadataSchema.optional(),
|
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 { lazy } from "react";
|
||||||
import { Outlet, RouteObject } from "react-router-dom";
|
import { Outlet, type RouteObject } from "react-router-dom";
|
||||||
|
|
||||||
// Lazy load components
|
// Lazy load components
|
||||||
const InvoicesLayout = lazy(() =>
|
const InvoicesLayout = lazy(() =>
|
||||||
import("./components").then((m) => ({ default: m.InvoicesLayout }))
|
import("./components").then((m) => ({ default: m.InvoicesLayout }))
|
||||||
);
|
);
|
||||||
|
|
||||||
const InvoiceListPage = lazy(() =>
|
const InvoiceListPage = lazy(() => import("./pages").then((m) => ({ default: m.InvoiceListPage })));
|
||||||
import("./pages").then((m) => ({ default: m.InvoiceListPage }))
|
|
||||||
);
|
|
||||||
|
|
||||||
const CustomerInvoiceAdd = lazy(() =>
|
const CustomerInvoiceAdd = lazy(() =>
|
||||||
import("./pages").then((m) => ({ default: m.CustomerInvoiceCreate }))
|
import("./pages").then((m) => ({ default: m.CustomerInvoiceCreate }))
|
||||||
@ -20,6 +18,20 @@ const InvoiceUpdatePage = lazy(() =>
|
|||||||
|
|
||||||
export const CustomerInvoiceRoutes = (params: ModuleClientParams): RouteObject[] => {
|
export const CustomerInvoiceRoutes = (params: ModuleClientParams): RouteObject[] => {
|
||||||
return [
|
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",
|
path: "customer-invoices",
|
||||||
element: (
|
element: (
|
||||||
@ -30,8 +42,6 @@ export const CustomerInvoiceRoutes = (params: ModuleClientParams): RouteObject[]
|
|||||||
children: [
|
children: [
|
||||||
{ path: "", index: true, element: <InvoiceListPage /> }, // index
|
{ path: "", index: true, element: <InvoiceListPage /> }, // index
|
||||||
{ path: "list", element: <InvoiceListPage /> },
|
{ path: "list", element: <InvoiceListPage /> },
|
||||||
{ path: "create", element: <CustomerInvoiceAdd /> },
|
|
||||||
{ path: ":id/edit", element: <InvoiceUpdatePage /> },
|
|
||||||
|
|
||||||
//
|
//
|
||||||
/*{ path: "create", element: <CustomerInvoicesList /> },
|
/*{ 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.form.schema";
|
||||||
|
export * from "./invoice-dto.adapter";
|
||||||
|
export * from "./invoice-resume.form.schema";
|
||||||
|
export * from "./invoice-resume-dto.adapter";
|
||||||
export * from "./invoices.api.schema";
|
export * from "./invoices.api.schema";
|
||||||
|
|||||||
@ -1,16 +1,18 @@
|
|||||||
import { MoneyDTOHelper, PercentageDTOHelper, QuantityDTOHelper } from "@erp/core";
|
import { MoneyDTOHelper, PercentageDTOHelper, QuantityDTOHelper } from "@erp/core";
|
||||||
import {
|
|
||||||
GetCustomerInvoiceByIdResponseDTO,
|
import type {
|
||||||
|
GetIssueInvoiceByIdResponseDTO,
|
||||||
UpdateCustomerInvoiceByIdRequestDTO,
|
UpdateCustomerInvoiceByIdRequestDTO,
|
||||||
} from "../../common";
|
} from "../../common";
|
||||||
import { InvoiceContextValue } from "../context";
|
import type { InvoiceContextValue } from "../context";
|
||||||
import { InvoiceFormData } from "./invoice.form.schema";
|
|
||||||
|
import type { InvoiceFormData } from "./invoice.form.schema";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convierte el DTO completo de API a datos numéricos para el formulario.
|
* Convierte el DTO completo de API a datos numéricos para el formulario.
|
||||||
*/
|
*/
|
||||||
export const invoiceDtoToFormAdapter = {
|
export const invoiceDtoToFormAdapter = {
|
||||||
fromDto(dto: GetCustomerInvoiceByIdResponseDTO, context: InvoiceContextValue): InvoiceFormData {
|
fromDto(dto: GetIssueInvoiceByIdResponseDTO, context: InvoiceContextValue): InvoiceFormData {
|
||||||
const { taxCatalog } = context;
|
const { taxCatalog } = context;
|
||||||
return {
|
return {
|
||||||
invoice_number: dto.invoice_number,
|
invoice_number: dto.invoice_number,
|
||||||
@ -30,6 +32,7 @@ export const invoiceDtoToFormAdapter = {
|
|||||||
currency_code: dto.currency_code,
|
currency_code: dto.currency_code,
|
||||||
|
|
||||||
subtotal_amount: MoneyDTOHelper.toNumber(dto.subtotal_amount),
|
subtotal_amount: MoneyDTOHelper.toNumber(dto.subtotal_amount),
|
||||||
|
items_discount_amount: 0,
|
||||||
discount_percentage: PercentageDTOHelper.toNumber(dto.discount_percentage),
|
discount_percentage: PercentageDTOHelper.toNumber(dto.discount_percentage),
|
||||||
discount_amount: MoneyDTOHelper.toNumber(dto.discount_amount),
|
discount_amount: MoneyDTOHelper.toNumber(dto.discount_amount),
|
||||||
taxable_amount: MoneyDTOHelper.toNumber(dto.taxable_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 {
|
import {
|
||||||
CreateCustomerInvoiceRequestSchema,
|
CreateCustomerInvoiceRequestSchema,
|
||||||
GetCustomerInvoiceByIdResponseSchema,
|
GetIssueInvoiceByIdResponseSchema,
|
||||||
ListCustomerInvoicesResponseSchema,
|
ListIssueInvoicesResponseSchema,
|
||||||
UpdateCustomerInvoiceByIdRequestSchema,
|
UpdateCustomerInvoiceByIdRequestSchema,
|
||||||
} from "../../common";
|
} from "../../common";
|
||||||
|
|
||||||
export const CustomerInvoiceSchema = GetCustomerInvoiceByIdResponseSchema.omit({
|
export const CustomerInvoiceSchema = GetIssueInvoiceByIdResponseSchema.omit({
|
||||||
metadata: true,
|
metadata: true,
|
||||||
});
|
});
|
||||||
export const CustomerInvoiceCreateSchema = CreateCustomerInvoiceRequestSchema;
|
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
|
export type CustomerInvoiceUpdateInput = z.infer<typeof CustomerInvoiceUpdateSchema>; // Cuerpo para actualizar
|
||||||
|
|
||||||
// Resultado de consulta con criteria (paginado, etc.)
|
// Resultado de consulta con criteria (paginado, etc.)
|
||||||
export const CustomerInvoicesPageSchema = ListCustomerInvoicesResponseSchema.omit({
|
export const CustomerInvoicesPageSchema = ListIssueInvoicesResponseSchema.omit({
|
||||||
metadata: true,
|
metadata: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { FindOptions, Op, OrderItem, Sequelize, WhereOptions } from "sequelize";
|
import { type FindOptions, Op, type OrderItem, Sequelize, type WhereOptions } from "sequelize";
|
||||||
import { Criteria } from "./critera";
|
|
||||||
import { type ConvertParams, type CriteriaMappings, ICriteriaToOrmConverter } from "./types";
|
import type { Criteria } from "./critera";
|
||||||
|
import type { ConvertParams, CriteriaMappings, ICriteriaToOrmConverter } from "./types";
|
||||||
import { appendOrder, prependOrder } from "./utils";
|
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}%`;
|
if (operator === Op.like || operator === Op.notLike) return `%${value}%`;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user