diff --git a/src/modules/financial/accounts.service.ts b/src/modules/financial/accounts.service.ts index 8cbc8ec..612c295 100644 --- a/src/modules/financial/accounts.service.ts +++ b/src/modules/financial/accounts.service.ts @@ -209,9 +209,10 @@ class AccountsService { userId: string ): Promise { try { - // Validate unique code within company + // Validate unique code within company and tenant (RLS compliance) const existing = await this.accountRepository.findOne({ where: { + tenantId, companyId: dto.companyId, code: dto.code, deletedAt: IsNull(), @@ -225,11 +226,12 @@ class AccountsService { // Validate account type exists await this.findAccountTypeById(dto.accountTypeId); - // Validate parent account if specified + // Validate parent account if specified (RLS compliance) if (dto.parentId) { const parent = await this.accountRepository.findOne({ where: { id: dto.parentId, + tenantId, companyId: dto.companyId, deletedAt: IsNull(), }, @@ -295,6 +297,7 @@ class AccountsService { const parent = await this.accountRepository.findOne({ where: { id: dto.parentId, + tenantId, companyId: existing.companyId, deletedAt: IsNull(), }, diff --git a/src/modules/products/products.service.ts b/src/modules/products/products.service.ts index 32e4b18..9b98886 100644 --- a/src/modules/products/products.service.ts +++ b/src/modules/products/products.service.ts @@ -164,6 +164,24 @@ class ProductsServiceClass { } async create(tenantId: string, dto: CreateProductDto, createdBy?: string): Promise { + // Validate unique SKU within tenant (RLS compliance) + const existingSku = await this.productRepository.findOne({ + where: { sku: dto.sku, tenantId, deletedAt: IsNull() }, + }); + if (existingSku) { + throw new Error(`Product with SKU '${dto.sku}' already exists`); + } + + // Validate unique barcode within tenant if provided (RLS compliance) + if (dto.barcode) { + const existingBarcode = await this.productRepository.findOne({ + where: { barcode: dto.barcode, tenantId, deletedAt: IsNull() }, + }); + if (existingBarcode) { + throw new Error(`Product with barcode '${dto.barcode}' already exists`); + } + } + const product = this.productRepository.create({ ...dto, tenantId, @@ -175,6 +193,27 @@ class ProductsServiceClass { async update(id: string, tenantId: string, dto: UpdateProductDto, updatedBy?: string): Promise { const product = await this.findOne(id, tenantId); if (!product) return null; + + // Validate unique SKU within tenant if changing (RLS compliance) + if (dto.sku && dto.sku !== product.sku) { + const existingSku = await this.productRepository.findOne({ + where: { sku: dto.sku, tenantId, deletedAt: IsNull() }, + }); + if (existingSku) { + throw new Error(`Product with SKU '${dto.sku}' already exists`); + } + } + + // Validate unique barcode within tenant if changing (RLS compliance) + if (dto.barcode && dto.barcode !== product.barcode) { + const existingBarcode = await this.productRepository.findOne({ + where: { barcode: dto.barcode, tenantId, deletedAt: IsNull() }, + }); + if (existingBarcode) { + throw new Error(`Product with barcode '${dto.barcode}' already exists`); + } + } + Object.assign(product, { ...dto, updatedBy }); return this.productRepository.save(product); } diff --git a/src/modules/warehouses/warehouses.service.ts b/src/modules/warehouses/warehouses.service.ts index a42999d..9adc958 100644 --- a/src/modules/warehouses/warehouses.service.ts +++ b/src/modules/warehouses/warehouses.service.ts @@ -136,6 +136,14 @@ class WarehousesServiceClass { } async create(tenantId: string, dto: CreateWarehouseDto, _createdBy?: string): Promise { + // Validate unique code within tenant (RLS compliance) + const existingCode = await this.warehouseRepository.findOne({ + where: { code: dto.code, tenantId, deletedAt: IsNull() }, + }); + if (existingCode) { + throw new Error(`Warehouse with code '${dto.code}' already exists`); + } + // If this is set as default, unset other defaults if (dto.isDefault) { await this.warehouseRepository.update(