actualizar versión a 0.10.9 en todos los módulos y archivos de configuración

This commit is contained in:
David Arranz 2026-09-21 13:11:28 +02:00
parent 78f5236fe9
commit 947639c6e6
37 changed files with 96 additions and 404 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@erp/factuges-server",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"scripts": {
"build": "tsup src/index.ts --config tsup.config.ts",
@ -83,4 +83,4 @@
"engines": {
"node": ">=22"
}
}
}

View File

@ -1,7 +1,7 @@
{
"name": "@erp/factuges-web",
"private": true,
"version": "0.10.8",
"version": "0.10.9",
"type": "module",
"scripts": {
"typecheck": "tsc -p tsconfig.json --noEmit",
@ -64,4 +64,4 @@
"tw-animate-css": "^1.4.0",
"vite-plugin-html": "^3.2.2"
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@erp/factuges-worker",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"scripts": {
"build": "tsup src/index.ts --config tsup.config.ts",
@ -38,4 +38,4 @@
"engines": {
"node": ">=22"
}
}
}

View File

@ -1,17 +0,0 @@
CREATE TABLE `companies` (
`id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`legal_name` varchar(255) NOT NULL,
`trade_name` varchar(255) DEFAULT NULL,
`tin` varchar(255) DEFAULT NULL,
`slug` varchar(255) NOT NULL,
`email` varchar(255) DEFAULT NULL,
`phone` varchar(255) DEFAULT NULL,
`website` varchar(255) DEFAULT NULL,
`status` varchar(255) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uq_companies_slug` (`slug`),
KEY `idx_companies_status` (`status`),
KEY `idx_companies_tin` (`tin`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci;

View File

@ -1,72 +0,0 @@
-- Customer Invoices - InvoiceSeries
-- Estado: HISTORICO / TRANSICIONAL.
-- No ejecutar en entornos nuevos.
-- Sustituido por: /document-series como API canónica y document_series como tabla canónica.
-- Estado del repo a fecha 2026-07-07:
-- - no hay framework de migraciones versionadas localizado;
-- - el servidor registra modelos Sequelize y usa database.sync(...) según syncMode.
-- Este SQL es un artefacto manual para integrar en el sistema real de despliegue DB
-- cuando exista un pipeline formal de migraciones.
CREATE TABLE IF NOT EXISTS customer_invoice_series (
id CHAR(36) NOT NULL,
company_id CHAR(36) NOT NULL,
code VARCHAR(10) NOT NULL,
next_number INT UNSIGNED NOT NULL,
padding_length SMALLINT UNSIGNED NOT NULL,
is_default TINYINT(1) NOT NULL DEFAULT 0,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
CONSTRAINT uq_customer_invoice_series_company_code UNIQUE (company_id, code),
KEY idx_customer_invoice_series_company_id (company_id),
KEY idx_customer_invoice_series_company_active (company_id, is_active),
CONSTRAINT chk_customer_invoice_series_next_number CHECK (next_number >= 1),
CONSTRAINT chk_customer_invoice_series_padding_length CHECK (padding_length >= 1)
);
-- Seed automático:
-- No se incluye seed por empresa porque el repo no expone un sistema de seeders
-- ni una estrategia fiable para recorrer companies existentes desde SQL puro
-- sin acoplar el despliegue a un tenant concreto.
-- Requisito operativo: cada company necesita al menos una InvoiceSeries activa
-- antes de emitir facturas.
-- Ejemplo manual por company:
-- INSERT INTO customer_invoice_series (
-- id,
-- company_id,
-- code,
-- next_number,
-- padding_length,
-- is_default,
-- is_active,
-- created_at,
-- updated_at
-- ) VALUES (
-- 'REEMPLAZAR-UUID',
-- 'REEMPLAZAR-COMPANY-ID',
-- 'A',
-- 1,
-- 6,
-- 1,
-- 1,
-- NOW(),
-- NOW()
-- );
-- Auditoría previa recomendada para la constraint de facturas emitidas:
-- confirma si existen duplicados por company + serie + número antes de forzar cambios
-- en entornos donde la tabla customer_invoices ya tenga datos históricos.
--
-- SELECT
-- company_id,
-- series,
-- invoice_number,
-- is_proforma,
-- COUNT(*) AS duplicated_rows
-- FROM customer_invoices
-- WHERE deleted_at IS NULL
-- GROUP BY company_id, series, invoice_number, is_proforma
-- HAVING COUNT(*) > 1;

View File

@ -1,47 +0,0 @@
CREATE TABLE `identity_accounts` (
`id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`email` varchar(255) NOT NULL,
`password_hash` varchar(512) NOT NULL,
`name` varchar(255) NOT NULL,
`avatar_url` varchar(255) DEFAULT NULL,
`language_code` varchar(2) NOT NULL,
`status` varchar(255) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uq_identity_accounts_email` (`email`),
KEY `idx_identity_accounts_status` (`status`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci;
CREATE TABLE `identity_company_memberships` (
`id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`account_id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`company_id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`status` varchar(255) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uq_identity_company_memberships_account_company` (`account_id`, `company_id`),
KEY `idx_identity_company_memberships_account_id` (`account_id`),
KEY `idx_identity_company_memberships_company_id` (`company_id`),
KEY `idx_identity_company_memberships_status` (`status`),
CONSTRAINT `identity_company_memberships_ibfk_1` FOREIGN KEY (`account_id`) REFERENCES `identity_accounts` (`id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci;
CREATE TABLE `identity_refresh_tokens` (
`id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`account_id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`token_hash` varchar(512) NOT NULL,
`expires_at` datetime NOT NULL,
`revoked_at` datetime DEFAULT NULL,
`replaced_by_token_id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
`created_at` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uq_identity_refresh_tokens_hash` (`token_hash`),
KEY `idx_identity_refresh_tokens_account_id` (`account_id`),
KEY `idx_identity_refresh_tokens_expires_at` (`expires_at`),
KEY `idx_identity_refresh_tokens_revoked_at` (`revoked_at`),
KEY `replaced_by_token_id` (`replaced_by_token_id`),
CONSTRAINT `identity_refresh_tokens_ibfk_285` FOREIGN KEY (`account_id`) REFERENCES `identity_accounts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `identity_refresh_tokens_ibfk_286` FOREIGN KEY (`replaced_by_token_id`) REFERENCES `identity_refresh_tokens` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci;

View File

@ -1,27 +0,0 @@
INSERT INTO
companies (
id,
legal_name,
trade_name,
tin,
slug,
email,
phone,
website,
status,
created_at,
updated_at
)
VALUES (
'5e4dc5b3-96b9-4968-9490-14bd032fec5f',
'Rodax Software S.L.',
'Rodax',
NULL,
'rodax',
'admin@local.test',
NULL,
NULL,
'active',
'2026-07-06 13:12:33.000',
'2026-07-06 13:12:33.000'
);

View File

@ -1,159 +0,0 @@
-- ============================================================
-- seed-local-admin.sql
-- ERP Backend - Local development seed
-- ============================================================
--
-- Purpose:
-- Creates a local admin account, one active company and the
-- active membership between them.
-- Tables touched:
-- - identity_accounts
-- - companies
-- - identity_company_memberships
--
-- Intended use:
-- Local/dev environments only.
--
-- Credentials:
-- email: admin@local.test
-- password: password
--
-- Generate bcrypt hash from the workspace:
--
-- node -e "const bcrypt=require('bcrypt'); bcrypt.hash('Admin123!', 10).then(console.log)"
--
-- Replace the hash below if you want to regenerate it.
-- This script is idempotent:
-- - It does not duplicate the admin account if the email exists.
-- - It does not duplicate the company if the slug exists.
-- - It does not duplicate the membership if it already exists.
-- ============================================================
SET @admin_id = UUID();
SET @company_id = UUID();
SET @admin_email = 'admin@local.test';
SET
@admin_password_hash = '$2a$10$BP8gyjtjx4hjDtWXMRLm1unogTE82Ja8mdF.rPNvZWliaaVoZvSBW';
-- password
SET @company_slug = 'rodax';
SET @company_legal_name = 'Rodax Software S.L.';
SET @company_trade_name = 'Rodax';
INSERT INTO
identity_accounts (
id,
email,
password_hash,
name,
avatar_url,
language_code,
status,
created_at,
updated_at
)
SELECT
@admin_id,
@admin_email,
@admin_password_hash,
'Administrador',
NULL,
'es',
'active',
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
WHERE
NOT EXISTS (
SELECT 1
FROM identity_accounts
WHERE
email = @admin_email
);
SELECT id INTO @admin_id
FROM identity_accounts
WHERE
email = @admin_email
LIMIT 1;
INSERT INTO
companies (
id,
legal_name,
trade_name,
tin,
slug,
email,
phone,
website,
status,
created_at,
updated_at
)
SELECT
@company_id,
@company_legal_name,
@company_trade_name,
NULL,
@company_slug,
@admin_email,
NULL,
NULL,
'active',
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
WHERE
NOT EXISTS (
SELECT 1
FROM companies
WHERE
slug = @company_slug
);
SELECT id INTO @company_id
FROM companies
WHERE
slug = @company_slug
LIMIT 1;
INSERT INTO
identity_company_memberships (
id,
account_id,
company_id,
status,
created_at,
updated_at
)
SELECT UUID(), @admin_id, @company_id, 'active', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
WHERE
NOT EXISTS (
SELECT 1
FROM identity_company_memberships
WHERE
account_id = @admin_id
AND company_id = @company_id
);
SELECT
a.id AS account_id,
a.email,
a.status AS account_status,
c.id AS company_id,
c.legal_name,
c.trade_name,
c.slug,
c.status AS company_status,
m.status AS membership_status
FROM
identity_accounts a
JOIN identity_company_memberships m ON m.account_id = a.id
JOIN companies c ON c.id = m.company_id
WHERE
a.email = @admin_email
AND c.slug = @company_slug;

View File

@ -1,7 +1,7 @@
{
"name": "@erp/audit",
"description": "Audit frontend module",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -40,4 +40,4 @@
"react-router-dom": "^7.14.0",
"zod": "^4.3.6"
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@erp/auth",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -37,4 +37,4 @@
"react-router-dom": "^7.14.0",
"react-secure-storage": "^1.3.2"
}
}
}

View File

@ -1,7 +1,7 @@
{
"name": "@erp/catalogs",
"description": "Catalogs module",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -54,4 +54,4 @@
"use-debounce": "^10.1.1",
"zod": "^4.3.6"
}
}
}

View File

@ -1,7 +1,7 @@
{
"name": "@erp/companies",
"description": "Companies module",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -51,4 +51,4 @@
"sequelize": "^6.37.8",
"zod": "^4.3.6"
}
}
}

View File

@ -36,6 +36,7 @@ function mapAddress(source: CompanyModel): Result<Maybe<PostalAddress>, Error> {
source.address_province,
source.address_country_code,
];
if (values.every((value) => value === null) && source.address_street_2 === null) {
return Result.ok(Maybe.none());
}
@ -185,8 +186,6 @@ export class SequelizeCompanyDomainMapper extends SequelizeDomainMapper<
value.toPrimitive()
),
status: source.status.toPrimitive(),
created_at: source.createdAt.toDate(),
updated_at: source.updatedAt.toDate(),
});
}
}

View File

@ -28,9 +28,6 @@ export class CompanyModel extends Model<
declare address_country_code: string | null;
declare default_payment_term_id: string | null;
declare status: string;
declare created_at: Date;
declare updated_at: Date;
declare deleted_at: Date | null;
static associate(_database: Sequelize) {}
@ -79,12 +76,36 @@ export default (database: Sequelize) => {
allowNull: true,
defaultValue: null,
},
address_street: { type: DataTypes.STRING, allowNull: true, defaultValue: null },
address_street_2: { type: DataTypes.STRING, allowNull: true, defaultValue: null },
address_city: { type: DataTypes.STRING, allowNull: true, defaultValue: null },
address_postal_code: { type: DataTypes.STRING, allowNull: true, defaultValue: null },
address_province: { type: DataTypes.STRING, allowNull: true, defaultValue: null },
address_country_code: { type: DataTypes.CHAR(2), allowNull: true, defaultValue: null },
address_street: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
},
address_street_2: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
},
address_city: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
},
address_postal_code: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
},
address_province: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
},
address_country_code: {
type: DataTypes.CHAR(2),
allowNull: true,
defaultValue: null,
},
default_payment_term_id: {
type: DataTypes.UUID,
allowNull: true,
@ -94,19 +115,6 @@ export default (database: Sequelize) => {
type: DataTypes.STRING,
allowNull: false,
},
created_at: {
type: DataTypes.DATE,
allowNull: false,
},
updated_at: {
type: DataTypes.DATE,
allowNull: false,
},
deleted_at: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null,
},
},
{
sequelize: database,

View File

@ -1,6 +1,6 @@
{
"name": "@erp/core",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -59,4 +59,4 @@
"sequelize": "^6.37.8",
"zod": "^4.3.6"
}
}
}

View File

@ -30,7 +30,7 @@ export type DocumentGenerationServiceDeps<TSnapshot> = {
sideEffects: readonly IDocumentSideEffect[];
};
export type DocumentGenerationServiceRenderParams = Record<string, string>;
export type DocumentGenerationServiceRenderParams = Record<string, unknown>;
export class DocumentGenerationService<TSnapshot> {
private readonly renderer: IDocumentRenderer<TSnapshot>;
@ -56,9 +56,9 @@ export class DocumentGenerationService<TSnapshot> {
let metadata: IDocumentMetadata;
let properties: IDocumentProperties;
// 1. Metadata and Properties
// 1. Construimos los metadatas a partir del snapshot y el contexto (ej: company, localization, etc.)
try {
metadata = this.metadataFactory.build(snapshot);
metadata = this.metadataFactory.build(snapshot, params);
} catch (error) {
return Result.fail(DocumentGenerationError.metadata(error));
}

View File

@ -1,6 +1,6 @@
{
"name": "@erp/customer-invoices",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -72,4 +72,4 @@
"sequelize": "^6.37.8",
"zod": "^4.3.6"
}
}
}

View File

@ -77,21 +77,24 @@ export class ReportProformaPdfUseCase {
return Result.fail(new CompanyReportProfileNotFoundError(companyId.toString()));
}
const companyProfile = companyProfileResult.data.unwrap();
const fullSnapshot = this.deps.fullSnapshotBuilder.toOutput(readModelResult.data);
const localization = this.resolveLocalization({
languageCode: fullSnapshot.language_code,
currencyCode: fullSnapshot.currency_code,
companyLocale: companyProfileResult.data.unwrap().locale,
companyCurrencyCode: companyProfileResult.data.unwrap().currencyCode,
companyLocale: companyProfile.locale,
companyCurrencyCode: companyProfile.currencyCode,
});
const reportSnapshot = this.deps.reportSnapshotBuilder.toOutput(fullSnapshot, {
localization,
company: companyProfileResult.data.unwrap(),
company: companyProfile,
});
const documentResult = await this.deps.documentService.generate(reportSnapshot, {
companySlug: "", //reportSnapshot.company.slug,
//localization,
company: companyProfile,
});
if (documentResult.isFailure) {

View File

@ -1,7 +1,7 @@
{
"name": "@erp/customers",
"description": "Customers",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -59,4 +59,4 @@
"use-debounce": "^10.1.1",
"zod": "^4.3.6"
}
}
}

View File

@ -1,7 +1,7 @@
{
"name": "@erp/document-series",
"description": "Document series module",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -51,4 +51,4 @@
"use-debounce": "^10.1.1",
"zod": "^4.3.6"
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@erp/factuges",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -35,4 +35,4 @@
"sequelize": "^6.37.8",
"zod": "^4.3.6"
}
}
}

View File

@ -1,7 +1,7 @@
{
"name": "@erp/identity",
"description": "Identity module",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -54,4 +54,4 @@
"rimraf": "^6.1.3",
"typescript": "^6.0.2"
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@erp/onboarding",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -59,4 +59,4 @@
"rimraf": "^6.1.3",
"typescript": "^6.0.2"
}
}
}

View File

@ -1,7 +1,7 @@
{
"name": "@erp/supplier-invoices",
"description": "Supplier invoices",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -33,4 +33,4 @@
"sequelize": "^6.37.8",
"zod": "^4.3.6"
}
}
}

View File

@ -1,7 +1,7 @@
{
"name": "@erp/suppliers",
"description": "Suppliers",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -57,4 +57,4 @@
"use-debounce": "^10.1.1",
"zod": "^4.3.6"
}
}
}

View File

@ -1,8 +1,12 @@
{
"name": "factuges-erp-2025",
"private": true,
"version": "0.10.8",
"workspaces": ["apps/*", "modules/*", "packages/*"],
"version": "0.10.9",
"workspaces": [
"apps/*",
"modules/*",
"packages/*"
],
"scripts": {
"build": "turbo run build",
"build:templates": "bash scripts/build-templates.sh",
@ -49,4 +53,4 @@
"node": ">=24"
},
"packageManager": "pnpm@11.25.0"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@repo/i18next",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"scripts": {
@ -24,4 +24,4 @@
"i18next-http-backend": "^3.0.4",
"react-i18next": "^17.0.2"
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@repo/rdx-audit",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -24,4 +24,4 @@
"dependencies": {
"@repo/rdx-utils": "workspace:*"
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@repo/rdx-criteria",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -20,4 +20,4 @@
"dependencies": {
"sequelize": "^6.37.8"
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@repo/rdx-ddd",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -27,4 +27,4 @@
"shallow-equal-object": "^1.1.1",
"zod": "^4.3.6"
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@repo/rdx-logger",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -22,4 +22,4 @@
"winston": "^3.19.0",
"winston-daily-rotate-file": "^5.0.0"
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@repo/rdx-ui",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,

View File

@ -1,6 +1,6 @@
{
"name": "@repo/rdx-utils",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"type": "module",
"sideEffects": false,
@ -23,4 +23,4 @@
"joi": "^18.1.2",
"uuid": "^13.0.0"
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@repo/shadcn-ui",
"version": "0.10.8",
"version": "0.10.9",
"type": "module",
"private": true,
"exports": {

View File

@ -1,8 +1,8 @@
{
"name": "@repo/typescript-config",
"version": "0.10.8",
"version": "0.10.9",
"private": true,
"publishConfig": {
"access": "public"
}
}
}