feat(database): initialize database schema and triggers

- Created initial database schema with tables for Users, Roles, Products, and related entities.
- Added foreign key constraints to maintain data integrity across tables.
- Implemented triggers for managing stock movements on insert, update, and delete operations.
- Developed scripts to dump existing triggers and pull trigger definitions from the database.
This commit is contained in:
2025-12-10 16:54:08 +03:30
parent 807f6c2087
commit 41d7dd8802
26 changed files with 1108 additions and 515 deletions
+3
View File
@@ -10,6 +10,7 @@
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.3", "class-validator": "^0.14.3",
"dotenv": "^17.2.3", "dotenv": "^17.2.3",
"mysql2": "^3.15.3",
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1" "rxjs": "^7.8.1"
}, },
@@ -64,9 +65,11 @@
"private": true, "private": true,
"scripts": { "scripts": {
"build": "nest build", "build": "nest build",
"dump-triggers": "tsx scripts/dump-triggers.ts",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"generate:permissions": "tsx scripts/generate-permissions.ts", "generate:permissions": "tsx scripts/generate-permissions.ts",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"pullDBTriggers": "tsx scripts/pull-triggers.ts",
"start": "nest start", "start": "nest start",
"start:debug": "nest start --debug --watch", "start:debug": "nest start --debug --watch",
"start:dev": "nest start --watch", "start:dev": "nest start --watch",
+3
View File
@@ -35,6 +35,9 @@ importers:
dotenv: dotenv:
specifier: ^17.2.3 specifier: ^17.2.3
version: 17.2.3 version: 17.2.3
mysql2:
specifier: ^3.15.3
version: 3.15.3
reflect-metadata: reflect-metadata:
specifier: ^0.2.2 specifier: ^0.2.2
version: 0.2.2 version: 0.2.2
@@ -1,172 +0,0 @@
-- CreateTable
CREATE TABLE `Users` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`mobileNumber` CHAR(11) NOT NULL,
`password` VARCHAR(191) NOT NULL,
`firstName` VARCHAR(191) NOT NULL,
`lastName` VARCHAR(191) NOT NULL,
`roleId` INTEGER NOT NULL,
UNIQUE INDEX `Users_mobileNumber_key`(`mobileNumber`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Roles` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`description` TEXT NULL,
`permissions` JSON NULL,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`updatedAt` TIMESTAMP(0) NOT NULL,
`deletedAt` TIMESTAMP(0) NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Products` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`description` TEXT NULL,
`sku` VARCHAR(100) NULL,
`barcode` VARCHAR(100) NULL,
`imageUrl` VARCHAR(255) NULL,
`attachmentId` BIGINT UNSIGNED NULL,
`unit` VARCHAR(10) NOT NULL,
`discount` DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
`quantity` DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
`alertQuantity` DECIMAL(10, 2) NOT NULL DEFAULT 5.00,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`isFeatured` BOOLEAN NOT NULL DEFAULT false,
`createdAt` TIMESTAMP(0) NULL,
`updatedAt` TIMESTAMP(0) NULL,
`deletedAt` TIMESTAMP(0) NULL,
`productInfoId` INTEGER NOT NULL,
UNIQUE INDEX `products_sku_unique`(`sku`),
UNIQUE INDEX `products_barcode_unique`(`barcode`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Product_info` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`description` TEXT NULL,
`productType` VARCHAR(50) NULL DEFAULT 'simple',
`metaData` JSON NULL,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`updatedAt` TIMESTAMP(0) NOT NULL,
`deletedAt` TIMESTAMP(0) NULL,
`brandId` INTEGER NULL,
`categoryId` INTEGER NULL,
`vendorId` INTEGER NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Product_brands` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`description` TEXT NULL,
`imageUrl` VARCHAR(255) NULL,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`updatedAt` TIMESTAMP(0) NOT NULL,
`deletedAt` TIMESTAMP(0) NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Product_categories` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`description` TEXT NULL,
`imageUrl` VARCHAR(255) NULL,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`updatedAt` TIMESTAMP(0) NOT NULL,
`deletedAt` TIMESTAMP(0) NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Vendors` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`firstName` VARCHAR(255) NOT NULL,
`lastName` VARCHAR(255) NOT NULL,
`email` VARCHAR(255) NULL,
`mobileNumber` CHAR(11) NOT NULL,
`address` TEXT NULL,
`city` VARCHAR(100) NULL,
`state` VARCHAR(100) NULL,
`country` VARCHAR(100) NULL,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`createdAt` TIMESTAMP(0) NULL,
`updatedAt` TIMESTAMP(0) NULL,
`deletedAt` TIMESTAMP(0) NULL,
UNIQUE INDEX `Vendors_mobileNumber_key`(`mobileNumber`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Customers` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`firstName` VARCHAR(255) NOT NULL,
`lastName` VARCHAR(255) NOT NULL,
`email` VARCHAR(255) NULL,
`mobileNumber` CHAR(11) NOT NULL,
`address` TEXT NULL,
`city` VARCHAR(100) NULL,
`state` VARCHAR(100) NULL,
`country` VARCHAR(100) NULL,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`createdAt` TIMESTAMP(0) NULL,
`updatedAt` TIMESTAMP(0) NULL,
`deletedAt` TIMESTAMP(0) NULL,
UNIQUE INDEX `Customers_mobileNumber_key`(`mobileNumber`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Inventories` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`location` VARCHAR(255) NULL,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`createdAt` TIMESTAMP(0) NOT NULL,
`updatedAt` TIMESTAMP(0) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Stores` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`location` VARCHAR(255) NULL,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`createdAt` TIMESTAMP(0) NOT NULL,
`updatedAt` TIMESTAMP(0) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey
ALTER TABLE `Users` ADD CONSTRAINT `Users_roleId_fkey` FOREIGN KEY (`roleId`) REFERENCES `Roles`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `Products` ADD CONSTRAINT `Products_productInfoId_fkey` FOREIGN KEY (`productInfoId`) REFERENCES `Product_info`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `Product_info` ADD CONSTRAINT `Product_info_brandId_fkey` FOREIGN KEY (`brandId`) REFERENCES `Product_brands`(`id`) ON DELETE SET NULL ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `Product_info` ADD CONSTRAINT `Product_info_categoryId_fkey` FOREIGN KEY (`categoryId`) REFERENCES `Product_categories`(`id`) ON DELETE SET NULL ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `Product_info` ADD CONSTRAINT `Product_info_vendorId_fkey` FOREIGN KEY (`vendorId`) REFERENCES `Vendors`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
@@ -1,43 +0,0 @@
/*
Warnings:
- You are about to drop the column `vendorId` on the `Product_info` table. All the data in the column will be lost.
- You are about to drop the `Vendors` table. If the table is not empty, all the data it contains will be lost.
- Added the required column `supplierId` to the `Product_info` table without a default value. This is not possible if the table is not empty.
*/
-- DropForeignKey
ALTER TABLE `Product_info` DROP FOREIGN KEY `Product_info_vendorId_fkey`;
-- DropIndex
DROP INDEX `Product_info_vendorId_fkey` ON `Product_info`;
-- AlterTable
ALTER TABLE `Product_info` DROP COLUMN `vendorId`,
ADD COLUMN `supplierId` INTEGER NOT NULL;
-- DropTable
DROP TABLE `Vendors`;
-- CreateTable
CREATE TABLE `Suppliers` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`firstName` VARCHAR(255) NOT NULL,
`lastName` VARCHAR(255) NOT NULL,
`email` VARCHAR(255) NULL,
`mobileNumber` CHAR(11) NOT NULL,
`address` TEXT NULL,
`city` VARCHAR(100) NULL,
`state` VARCHAR(100) NULL,
`country` VARCHAR(100) NULL,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`createdAt` TIMESTAMP(0) NULL,
`updatedAt` TIMESTAMP(0) NULL,
`deletedAt` TIMESTAMP(0) NULL,
UNIQUE INDEX `Suppliers_mobileNumber_key`(`mobileNumber`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey
ALTER TABLE `Product_info` ADD CONSTRAINT `Product_info_supplierId_fkey` FOREIGN KEY (`supplierId`) REFERENCES `Suppliers`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
@@ -1,83 +0,0 @@
/*
Warnings:
- You are about to drop the column `alertQuantity` on the `Products` table. All the data in the column will be lost.
- You are about to drop the column `attachmentId` on the `Products` table. All the data in the column will be lost.
- You are about to drop the column `discount` on the `Products` table. All the data in the column will be lost.
- You are about to drop the column `imageUrl` on the `Products` table. All the data in the column will be lost.
- You are about to drop the column `isActive` on the `Products` table. All the data in the column will be lost.
- You are about to drop the column `isFeatured` on the `Products` table. All the data in the column will be lost.
- You are about to drop the column `productInfoId` on the `Products` table. All the data in the column will be lost.
- You are about to drop the column `quantity` on the `Products` table. All the data in the column will be lost.
- You are about to drop the column `unit` on the `Products` table. All the data in the column will be lost.
- You are about to drop the `Product_info` table. If the table is not empty, all the data it contains will be lost.
- Made the column `createdAt` on table `Products` required. This step will fail if there are existing NULL values in that column.
- Made the column `updatedAt` on table `Products` required. This step will fail if there are existing NULL values in that column.
*/
-- DropForeignKey
ALTER TABLE `Product_info` DROP FOREIGN KEY `Product_info_brandId_fkey`;
-- DropForeignKey
ALTER TABLE `Product_info` DROP FOREIGN KEY `Product_info_categoryId_fkey`;
-- DropForeignKey
ALTER TABLE `Product_info` DROP FOREIGN KEY `Product_info_supplierId_fkey`;
-- DropForeignKey
ALTER TABLE `Products` DROP FOREIGN KEY `Products_productInfoId_fkey`;
-- DropIndex
DROP INDEX `Products_productInfoId_fkey` ON `Products`;
-- AlterTable
ALTER TABLE `Products` DROP COLUMN `alertQuantity`,
DROP COLUMN `attachmentId`,
DROP COLUMN `discount`,
DROP COLUMN `imageUrl`,
DROP COLUMN `isActive`,
DROP COLUMN `isFeatured`,
DROP COLUMN `productInfoId`,
DROP COLUMN `quantity`,
DROP COLUMN `unit`,
ADD COLUMN `brandId` INTEGER NULL,
ADD COLUMN `categoryId` INTEGER NULL,
ADD COLUMN `metaData` JSON NULL,
ADD COLUMN `productType` VARCHAR(50) NULL DEFAULT 'simple',
MODIFY `createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
MODIFY `updatedAt` TIMESTAMP(0) NOT NULL;
-- DropTable
DROP TABLE `Product_info`;
-- CreateTable
CREATE TABLE `Product_Variants` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`basePrice` DECIMAL(10, 2) NOT NULL,
`salePrice` DECIMAL(10, 2) NOT NULL,
`description` TEXT NULL,
`barcode` VARCHAR(100) NULL,
`imageUrl` VARCHAR(255) NULL,
`unit` VARCHAR(10) NULL,
`quantity` DECIMAL(10, 2) NULL DEFAULT 0.00,
`alertQuantity` DECIMAL(10, 2) NULL DEFAULT 5.00,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`isFeatured` BOOLEAN NOT NULL DEFAULT false,
`createdAt` TIMESTAMP(0) NULL,
`updatedAt` TIMESTAMP(0) NULL,
`deletedAt` TIMESTAMP(0) NULL,
`productId` INTEGER NOT NULL,
UNIQUE INDEX `products_barcode_unique`(`barcode`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey
ALTER TABLE `Product_Variants` ADD CONSTRAINT `Product_Variants_productId_fkey` FOREIGN KEY (`productId`) REFERENCES `Products`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `Products` ADD CONSTRAINT `Products_brandId_fkey` FOREIGN KEY (`brandId`) REFERENCES `Product_brands`(`id`) ON DELETE SET NULL ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `Products` ADD CONSTRAINT `Products_categoryId_fkey` FOREIGN KEY (`categoryId`) REFERENCES `Product_categories`(`id`) ON DELETE SET NULL ON UPDATE NO ACTION;
@@ -1,10 +0,0 @@
/*
Warnings:
- You are about to drop the column `metaData` on the `Products` table. All the data in the column will be lost.
- You are about to drop the column `productType` on the `Products` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE `Products` DROP COLUMN `metaData`,
DROP COLUMN `productType`;
@@ -1,20 +0,0 @@
/*
Warnings:
- You are about to drop the `StockMovementsView` table. If the table is not empty, all the data it contains will be lost.
- You are about to drop the `Stock_View` table. If the table is not empty, all the data it contains will be lost.
- You are about to drop the `Total_Stock_View` table. If the table is not empty, all the data it contains will be lost.
- You are about to drop the `stock_movements_view` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropTable
DROP TABLE `StockMovementsView`;
-- DropTable
DROP TABLE `Stock_View`;
-- DropTable
DROP TABLE `Total_Stock_View`;
-- DropTable
DROP TABLE `stock_movements_view`;
@@ -1,13 +0,0 @@
/*
Warnings:
- The primary key for the `stock_balance` table will be changed. If it partially fails, the table could be left without primary key constraint.
- You are about to drop the column `itemId` on the `stock_balance` table. All the data in the column will be lost.
- Added the required column `ProductId` to the `stock_balance` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE `stock_balance` DROP PRIMARY KEY,
DROP COLUMN `itemId`,
ADD COLUMN `ProductId` INTEGER NOT NULL,
ADD PRIMARY KEY (`ProductId`);
@@ -1,9 +0,0 @@
/*
Warnings:
- Added the required column `avgCost` to the `Stock_Movements` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE `Stock_Movements` ADD COLUMN `avgCost` DECIMAL(10, 2) NOT NULL;
@@ -1,9 +0,0 @@
/*
Warnings:
- Added the required column `avgCost` to the `stock_balance` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE `stock_balance` ADD COLUMN `avgCost` DECIMAL(65, 30) NOT NULL;
@@ -1,39 +1,168 @@
/* -- CreateTable
Warnings: CREATE TABLE `Users` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`mobileNumber` CHAR(11) NOT NULL,
`password` VARCHAR(191) NOT NULL,
`firstName` VARCHAR(191) NOT NULL,
`lastName` VARCHAR(191) NOT NULL,
`roleId` INTEGER NOT NULL,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`deletedAt` TIMESTAMP(0) NULL,
`updatedAt` TIMESTAMP(0) NOT NULL,
- Made the column `createdAt` on table `Customers` required. This step will fail if there are existing NULL values in that column. UNIQUE INDEX `Users_mobileNumber_key`(`mobileNumber`),
- Made the column `updatedAt` on table `Customers` required. This step will fail if there are existing NULL values in that column. INDEX `Users_roleId_fkey`(`roleId`),
- Made the column `createdAt` on table `Product_Variants` required. This step will fail if there are existing NULL values in that column. PRIMARY KEY (`id`)
- Made the column `updatedAt` on table `Product_Variants` required. This step will fail if there are existing NULL values in that column. ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
- Made the column `createdAt` on table `Suppliers` required. This step will fail if there are existing NULL values in that column.
- Made the column `updatedAt` on table `Suppliers` required. This step will fail if there are existing NULL values in that column.
- Added the required column `updatedAt` to the `Users` table without a default value. This is not possible if the table is not empty.
*/ -- CreateTable
-- AlterTable CREATE TABLE `Roles` (
ALTER TABLE `Customers` MODIFY `createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0), `id` INTEGER NOT NULL AUTO_INCREMENT,
MODIFY `updatedAt` TIMESTAMP(0) NOT NULL; `name` VARCHAR(100) NOT NULL,
`description` TEXT NULL,
`permissions` JSON NULL,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`updatedAt` TIMESTAMP(0) NOT NULL,
`deletedAt` TIMESTAMP(0) NULL,
-- AlterTable PRIMARY KEY (`id`)
ALTER TABLE `Inventories` ADD COLUMN `deletedAt` TIMESTAMP(0) NULL, ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
MODIFY `createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0);
-- AlterTable -- CreateTable
ALTER TABLE `Product_Variants` MODIFY `createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0), CREATE TABLE `Product_Variants` (
MODIFY `updatedAt` TIMESTAMP(0) NOT NULL; `id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`basePrice` DECIMAL(10, 2) NOT NULL,
`salePrice` DECIMAL(10, 2) NOT NULL,
`description` TEXT NULL,
`barcode` VARCHAR(100) NULL,
`imageUrl` VARCHAR(255) NULL,
`unit` VARCHAR(10) NULL,
`quantity` DECIMAL(10, 2) NULL DEFAULT 0.00,
`alertQuantity` DECIMAL(10, 2) NULL DEFAULT 5.00,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`isFeatured` BOOLEAN NOT NULL DEFAULT false,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`updatedAt` TIMESTAMP(0) NOT NULL,
`deletedAt` TIMESTAMP(0) NULL,
`productId` INTEGER NOT NULL,
-- AlterTable UNIQUE INDEX `products_barcode_unique`(`barcode`),
ALTER TABLE `Stores` ADD COLUMN `deletedAt` TIMESTAMP(0) NULL, INDEX `Product_Variants_productId_fkey`(`productId`),
MODIFY `createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0); PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AlterTable -- CreateTable
ALTER TABLE `Suppliers` MODIFY `createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0), CREATE TABLE `Products` (
MODIFY `updatedAt` TIMESTAMP(0) NOT NULL; `id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`description` TEXT NULL,
`sku` VARCHAR(100) NULL,
`barcode` VARCHAR(100) NULL,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`updatedAt` TIMESTAMP(0) NOT NULL,
`deletedAt` TIMESTAMP(0) NULL,
`brandId` INTEGER NULL,
`categoryId` INTEGER NULL,
-- AlterTable UNIQUE INDEX `products_sku_unique`(`sku`),
ALTER TABLE `Users` ADD COLUMN `createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0), UNIQUE INDEX `products_barcode_unique`(`barcode`),
ADD COLUMN `deletedAt` TIMESTAMP(0) NULL, INDEX `Products_brandId_fkey`(`brandId`),
ADD COLUMN `updatedAt` TIMESTAMP(0) NOT NULL; INDEX `Products_categoryId_fkey`(`categoryId`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Product_brands` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`description` TEXT NULL,
`imageUrl` VARCHAR(255) NULL,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`updatedAt` TIMESTAMP(0) NOT NULL,
`deletedAt` TIMESTAMP(0) NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Product_categories` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`description` TEXT NULL,
`imageUrl` VARCHAR(255) NULL,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`updatedAt` TIMESTAMP(0) NOT NULL,
`deletedAt` TIMESTAMP(0) NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Suppliers` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`firstName` VARCHAR(255) NOT NULL,
`lastName` VARCHAR(255) NOT NULL,
`email` VARCHAR(255) NULL,
`mobileNumber` CHAR(11) NOT NULL,
`address` TEXT NULL,
`city` VARCHAR(100) NULL,
`state` VARCHAR(100) NULL,
`country` VARCHAR(100) NULL,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`updatedAt` TIMESTAMP(0) NOT NULL,
`deletedAt` TIMESTAMP(0) NULL,
UNIQUE INDEX `Suppliers_mobileNumber_key`(`mobileNumber`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Customers` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`firstName` VARCHAR(255) NOT NULL,
`lastName` VARCHAR(255) NOT NULL,
`email` VARCHAR(255) NULL,
`mobileNumber` CHAR(11) NOT NULL,
`address` TEXT NULL,
`city` VARCHAR(100) NULL,
`state` VARCHAR(100) NULL,
`country` VARCHAR(100) NULL,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`updatedAt` TIMESTAMP(0) NOT NULL,
`deletedAt` TIMESTAMP(0) NULL,
UNIQUE INDEX `Customers_mobileNumber_key`(`mobileNumber`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Inventories` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`location` VARCHAR(255) NULL,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`updatedAt` TIMESTAMP(0) NOT NULL,
`deletedAt` TIMESTAMP(0) NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Stores` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`location` VARCHAR(255) NULL,
`isActive` BOOLEAN NOT NULL DEFAULT true,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`updatedAt` TIMESTAMP(0) NOT NULL,
`deletedAt` TIMESTAMP(0) NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable -- CreateTable
CREATE TABLE `Product_Charges` ( CREATE TABLE `Product_Charges` (
@@ -51,6 +180,9 @@ CREATE TABLE `Product_Charges` (
`inventoryId` INTEGER NOT NULL, `inventoryId` INTEGER NOT NULL,
`supplierId` INTEGER NOT NULL, `supplierId` INTEGER NOT NULL,
INDEX `Product_Charges_inventoryId_fkey`(`inventoryId`),
INDEX `Product_Charges_productId_fkey`(`productId`),
INDEX `Product_Charges_supplierId_fkey`(`supplierId`),
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -67,6 +199,7 @@ CREATE TABLE `Orders` (
`customerId` INTEGER NOT NULL, `customerId` INTEGER NOT NULL,
UNIQUE INDEX `Orders_orderNumber_key`(`orderNumber`), UNIQUE INDEX `Orders_orderNumber_key`(`orderNumber`),
INDEX `Orders_customerId_fkey`(`customerId`),
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -82,6 +215,8 @@ CREATE TABLE `Purchase_Receipts` (
`inventoryId` INTEGER NOT NULL, `inventoryId` INTEGER NOT NULL,
UNIQUE INDEX `Purchase_Receipts_code_key`(`code`), UNIQUE INDEX `Purchase_Receipts_code_key`(`code`),
INDEX `Purchase_Receipts_inventoryId_fkey`(`inventoryId`),
INDEX `Purchase_Receipts_supplierId_fkey`(`supplierId`),
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -91,10 +226,13 @@ CREATE TABLE `Purchase_Receipt_Items` (
`count` DECIMAL(10, 2) NOT NULL, `count` DECIMAL(10, 2) NOT NULL,
`fee` DECIMAL(10, 2) NOT NULL, `fee` DECIMAL(10, 2) NOT NULL,
`total` DECIMAL(10, 2) NOT NULL, `total` DECIMAL(10, 2) NOT NULL,
`description` TEXT NULL,
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0), `createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`receiptId` INTEGER NOT NULL, `receiptId` INTEGER NOT NULL,
`productId` INTEGER NOT NULL, `productId` INTEGER NOT NULL,
INDEX `Purchase_Receipt_Items_productId_fkey`(`productId`),
INDEX `Purchase_Receipt_Items_receiptId_fkey`(`receiptId`),
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -109,6 +247,7 @@ CREATE TABLE `Sales_Invoices` (
`customerId` INTEGER NULL, `customerId` INTEGER NULL,
UNIQUE INDEX `Sales_Invoices_code_key`(`code`), UNIQUE INDEX `Sales_Invoices_code_key`(`code`),
INDEX `Sales_Invoices_customerId_fkey`(`customerId`),
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -122,6 +261,8 @@ CREATE TABLE `Sales_Invoice_Items` (
`invoiceId` INTEGER NOT NULL, `invoiceId` INTEGER NOT NULL,
`productId` INTEGER NOT NULL, `productId` INTEGER NOT NULL,
INDEX `Sales_Invoice_Items_invoiceId_fkey`(`invoiceId`),
INDEX `Sales_Invoice_Items_productId_fkey`(`productId`),
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -137,18 +278,22 @@ CREATE TABLE `Stock_Movements` (
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0), `createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`productId` INTEGER NOT NULL, `productId` INTEGER NOT NULL,
`inventoryId` INTEGER NOT NULL, `inventoryId` INTEGER NOT NULL,
`avgCost` DECIMAL(10, 2) NOT NULL,
INDEX `Stock_Movements_inventoryId_fkey`(`inventoryId`),
INDEX `Stock_Movements_productId_fkey`(`productId`),
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable -- CreateTable
CREATE TABLE `stock_balance` ( CREATE TABLE `Stock_Balance` (
`itemId` INTEGER NOT NULL,
`quantity` DECIMAL(65, 30) NOT NULL, `quantity` DECIMAL(65, 30) NOT NULL,
`totalCost` DECIMAL(65, 30) NOT NULL, `totalCost` DECIMAL(65, 30) NOT NULL,
`updatedAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0), `updatedAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`ProductId` INTEGER NOT NULL,
`avgCost` DECIMAL(65, 30) NOT NULL,
PRIMARY KEY (`itemId`) PRIMARY KEY (`ProductId`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable -- CreateTable
@@ -161,6 +306,8 @@ CREATE TABLE `Inventory_Transfers` (
`toInventoryId` INTEGER NOT NULL, `toInventoryId` INTEGER NOT NULL,
UNIQUE INDEX `Inventory_Transfers_code_key`(`code`), UNIQUE INDEX `Inventory_Transfers_code_key`(`code`),
INDEX `Inventory_Transfers_fromInventoryId_fkey`(`fromInventoryId`),
INDEX `Inventory_Transfers_toInventoryId_fkey`(`toInventoryId`),
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -171,22 +318,11 @@ CREATE TABLE `Inventory_Transfer_Items` (
`productId` INTEGER NOT NULL, `productId` INTEGER NOT NULL,
`transferId` INTEGER NOT NULL, `transferId` INTEGER NOT NULL,
INDEX `Inventory_Transfer_Items_productId_fkey`(`productId`),
INDEX `Inventory_Transfer_Items_transferId_fkey`(`transferId`),
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `StockMovementsView` (
`id` INTEGER NULL,
`type` VARCHAR(191) NULL,
`productId` INTEGER NULL,
`quantity` DECIMAL(65, 30) NULL,
`fee` DECIMAL(65, 30) NULL,
`totalCost` DECIMAL(65, 30) NULL,
`referenceId` INTEGER NULL,
`referenceType` VARCHAR(191) NULL,
`createdAt` DATETIME(3) NULL
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable -- CreateTable
CREATE TABLE `Stock_Adjustments` ( CREATE TABLE `Stock_Adjustments` (
`id` INTEGER NOT NULL AUTO_INCREMENT, `id` INTEGER NOT NULL AUTO_INCREMENT,
@@ -195,61 +331,47 @@ CREATE TABLE `Stock_Adjustments` (
`productId` INTEGER NOT NULL, `productId` INTEGER NOT NULL,
`inventoryId` INTEGER NOT NULL, `inventoryId` INTEGER NOT NULL,
INDEX `Stock_Adjustments_inventoryId_fkey`(`inventoryId`),
INDEX `Stock_Adjustments_productId_fkey`(`productId`),
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable -- AddForeignKey
CREATE TABLE `stock_movements_view` ( ALTER TABLE `Users` ADD CONSTRAINT `Users_roleId_fkey` FOREIGN KEY (`roleId`) REFERENCES `Roles`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
`id` INTEGER NULL,
`productId` INTEGER NULL,
`type` VARCHAR(191) NULL,
`quantity` DECIMAL(65, 30) NULL,
`fee` DECIMAL(65, 30) NULL,
`totalCost` DECIMAL(65, 30) NULL,
`referenceId` VARCHAR(191) NULL,
`referenceType` VARCHAR(191) NULL,
`createdAt` DATETIME(3) NULL,
`currentStock` DECIMAL(65, 30) NULL,
`currentAvgCost` DECIMAL(65, 30) NULL
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Stock_View` (
`productId` INTEGER NULL,
`inventoryId` INTEGER NULL,
`stock` DECIMAL(65, 30) NULL
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `Total_Stock_View` (
`productId` INTEGER NULL,
`stock` DECIMAL(65, 30) NULL
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey -- AddForeignKey
ALTER TABLE `Product_Charges` ADD CONSTRAINT `Product_Charges_productId_fkey` FOREIGN KEY (`productId`) REFERENCES `Products`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION; ALTER TABLE `Product_Variants` ADD CONSTRAINT `Product_Variants_productId_fkey` FOREIGN KEY (`productId`) REFERENCES `Products`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `Products` ADD CONSTRAINT `Products_brandId_fkey` FOREIGN KEY (`brandId`) REFERENCES `Product_brands`(`id`) ON DELETE SET NULL ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `Products` ADD CONSTRAINT `Products_categoryId_fkey` FOREIGN KEY (`categoryId`) REFERENCES `Product_categories`(`id`) ON DELETE SET NULL ON UPDATE NO ACTION;
-- AddForeignKey -- AddForeignKey
ALTER TABLE `Product_Charges` ADD CONSTRAINT `Product_Charges_inventoryId_fkey` FOREIGN KEY (`inventoryId`) REFERENCES `Inventories`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION; ALTER TABLE `Product_Charges` ADD CONSTRAINT `Product_Charges_inventoryId_fkey` FOREIGN KEY (`inventoryId`) REFERENCES `Inventories`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `Product_Charges` ADD CONSTRAINT `Product_Charges_productId_fkey` FOREIGN KEY (`productId`) REFERENCES `Products`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey -- AddForeignKey
ALTER TABLE `Product_Charges` ADD CONSTRAINT `Product_Charges_supplierId_fkey` FOREIGN KEY (`supplierId`) REFERENCES `Suppliers`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION; ALTER TABLE `Product_Charges` ADD CONSTRAINT `Product_Charges_supplierId_fkey` FOREIGN KEY (`supplierId`) REFERENCES `Suppliers`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey -- AddForeignKey
ALTER TABLE `Orders` ADD CONSTRAINT `Orders_customerId_fkey` FOREIGN KEY (`customerId`) REFERENCES `Customers`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION; ALTER TABLE `Orders` ADD CONSTRAINT `Orders_customerId_fkey` FOREIGN KEY (`customerId`) REFERENCES `Customers`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION;
-- AddForeignKey
ALTER TABLE `Purchase_Receipts` ADD CONSTRAINT `Purchase_Receipts_supplierId_fkey` FOREIGN KEY (`supplierId`) REFERENCES `Suppliers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE `Purchase_Receipts` ADD CONSTRAINT `Purchase_Receipts_inventoryId_fkey` FOREIGN KEY (`inventoryId`) REFERENCES `Inventories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE `Purchase_Receipts` ADD CONSTRAINT `Purchase_Receipts_inventoryId_fkey` FOREIGN KEY (`inventoryId`) REFERENCES `Inventories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE `Purchase_Receipt_Items` ADD CONSTRAINT `Purchase_Receipt_Items_receiptId_fkey` FOREIGN KEY (`receiptId`) REFERENCES `Purchase_Receipts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE `Purchase_Receipts` ADD CONSTRAINT `Purchase_Receipts_supplierId_fkey` FOREIGN KEY (`supplierId`) REFERENCES `Suppliers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE `Purchase_Receipt_Items` ADD CONSTRAINT `Purchase_Receipt_Items_productId_fkey` FOREIGN KEY (`productId`) REFERENCES `Products`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE `Purchase_Receipt_Items` ADD CONSTRAINT `Purchase_Receipt_Items_productId_fkey` FOREIGN KEY (`productId`) REFERENCES `Products`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Purchase_Receipt_Items` ADD CONSTRAINT `Purchase_Receipt_Items_receiptId_fkey` FOREIGN KEY (`receiptId`) REFERENCES `Purchase_Receipts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE `Sales_Invoices` ADD CONSTRAINT `Sales_Invoices_customerId_fkey` FOREIGN KEY (`customerId`) REFERENCES `Customers`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; ALTER TABLE `Sales_Invoices` ADD CONSTRAINT `Sales_Invoices_customerId_fkey` FOREIGN KEY (`customerId`) REFERENCES `Customers`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
@@ -260,10 +382,10 @@ ALTER TABLE `Sales_Invoice_Items` ADD CONSTRAINT `Sales_Invoice_Items_invoiceId_
ALTER TABLE `Sales_Invoice_Items` ADD CONSTRAINT `Sales_Invoice_Items_productId_fkey` FOREIGN KEY (`productId`) REFERENCES `Products`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE `Sales_Invoice_Items` ADD CONSTRAINT `Sales_Invoice_Items_productId_fkey` FOREIGN KEY (`productId`) REFERENCES `Products`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE `Stock_Movements` ADD CONSTRAINT `Stock_Movements_productId_fkey` FOREIGN KEY (`productId`) REFERENCES `Products`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE `Stock_Movements` ADD CONSTRAINT `Stock_Movements_inventoryId_fkey` FOREIGN KEY (`inventoryId`) REFERENCES `Inventories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE `Stock_Movements` ADD CONSTRAINT `Stock_Movements_inventoryId_fkey` FOREIGN KEY (`inventoryId`) REFERENCES `Inventories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE `Stock_Movements` ADD CONSTRAINT `Stock_Movements_productId_fkey` FOREIGN KEY (`productId`) REFERENCES `Products`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE `Inventory_Transfers` ADD CONSTRAINT `Inventory_Transfers_fromInventoryId_fkey` FOREIGN KEY (`fromInventoryId`) REFERENCES `Inventories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE `Inventory_Transfers` ADD CONSTRAINT `Inventory_Transfers_fromInventoryId_fkey` FOREIGN KEY (`fromInventoryId`) REFERENCES `Inventories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
@@ -278,7 +400,7 @@ ALTER TABLE `Inventory_Transfer_Items` ADD CONSTRAINT `Inventory_Transfer_Items_
ALTER TABLE `Inventory_Transfer_Items` ADD CONSTRAINT `Inventory_Transfer_Items_transferId_fkey` FOREIGN KEY (`transferId`) REFERENCES `Inventory_Transfers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE `Inventory_Transfer_Items` ADD CONSTRAINT `Inventory_Transfer_Items_transferId_fkey` FOREIGN KEY (`transferId`) REFERENCES `Inventory_Transfers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE `Stock_Adjustments` ADD CONSTRAINT `Stock_Adjustments_productId_fkey` FOREIGN KEY (`productId`) REFERENCES `Products`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE `Stock_Adjustments` ADD CONSTRAINT `Stock_Adjustments_inventoryId_fkey` FOREIGN KEY (`inventoryId`) REFERENCES `Inventories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey -- AddForeignKey
ALTER TABLE `Stock_Adjustments` ADD CONSTRAINT `Stock_Adjustments_inventoryId_fkey` FOREIGN KEY (`inventoryId`) REFERENCES `Inventories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE `Stock_Adjustments` ADD CONSTRAINT `Stock_Adjustments_productId_fkey` FOREIGN KEY (`productId`) REFERENCES `Products`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
+18 -11
View File
@@ -242,15 +242,16 @@ model PurchaseReceipt {
} }
model PurchaseReceiptItem { model PurchaseReceiptItem {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
count Decimal @db.Decimal(10, 2) count Decimal @db.Decimal(10, 2)
fee Decimal @db.Decimal(10, 2) fee Decimal @db.Decimal(10, 2)
total Decimal @db.Decimal(10, 2) total Decimal @db.Decimal(10, 2)
createdAt DateTime @default(now()) @db.Timestamp(0) description String? @db.Text
receiptId Int createdAt DateTime @default(now()) @db.Timestamp(0)
productId Int receiptId Int
product Product @relation("Product_PurchaseReceiptItems", fields: [productId], references: [id]) productId Int
receipt PurchaseReceipt @relation("PurchaseReceipt_Items", fields: [receiptId], references: [id]) product Product @relation("Product_PurchaseReceiptItems", fields: [productId], references: [id])
receipt PurchaseReceipt @relation("PurchaseReceipt_Items", fields: [receiptId], references: [id])
@@index([productId], map: "Purchase_Receipt_Items_productId_fkey") @@index([productId], map: "Purchase_Receipt_Items_productId_fkey")
@@index([receiptId], map: "Purchase_Receipt_Items_receiptId_fkey") @@index([receiptId], map: "Purchase_Receipt_Items_receiptId_fkey")
@@ -315,7 +316,7 @@ model StockBalance {
ProductId Int @id ProductId Int @id
avgCost Decimal avgCost Decimal
@@map("stock_balance") @@map("Stock_Balance")
} }
model InventoryTransfer { model InventoryTransfer {
@@ -374,7 +375,7 @@ view StockMovements_View {
current_stock Decimal? current_stock Decimal?
current_avg_cost Decimal? current_avg_cost Decimal?
@@map("stock_movements_view") @@map("Stock_Movements_View")
@@ignore @@ignore
} }
@@ -384,6 +385,8 @@ view inventory_overview {
avgCost Decimal avgCost Decimal
totalCost Decimal totalCost Decimal
updatedAt DateTime @default(now()) @db.Timestamp(0) updatedAt DateTime @default(now()) @db.Timestamp(0)
@@map("Inventory_Overview")
} }
view stock_cardex { view stock_cardex {
@@ -396,12 +399,16 @@ view stock_cardex {
balance_quantity Decimal? balance_quantity Decimal?
balance_avg_cost Decimal? balance_avg_cost Decimal?
createdAt DateTime @default(now()) @db.Timestamp(0) createdAt DateTime @default(now()) @db.Timestamp(0)
@@map("Stock_Cardex")
} }
view stock_view { view stock_view {
productId Int productId Int
inventoryId Int inventoryId Int
stock Decimal? @db.Decimal(32, 2) stock Decimal? @db.Decimal(32, 2)
@@map("Stock_View")
} }
enum OrderStatus { enum OrderStatus {
@@ -0,0 +1,332 @@
-- AUTO-GENERATED MYSQL TRIGGER DUMP
-- Generated at: 2025-12-10T10:03:36.966Z
-- ------------------------------------------
-- Trigger: trg_transfer_item_after_insert
-- Event: INSERT
-- Table: Inventory_Transfer_Items
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_transfer_item_after_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_transfer_item_after_insert` AFTER INSERT ON `Inventory_Transfer_Items` FOR EACH ROW begin
DECLARE fromInv INT;
DECLARE toInv INT;
SELECT fromInventoryId, toInventoryId INTO fromInv, toInv
FROM Inventory_Transfers WHERE id = NEW.transferId;
-- OUT from source
INSERT INTO Stock_Movements
(type, quantity, referenceType, referenceId, productId, inventoryId, createdAt)
VALUES
('OUT', NEW.count, 'InventoryTransfer', NEW.transferId, NEW.productId, fromInv, NOW());
-- IN to destination
INSERT INTO Stock_Movements
(type, quantity, referenceType, referenceId, productId, inventoryId, createdAt)
VALUES
('IN', NEW.count, 'InventoryTransfer', NEW.transferId, NEW.productId, toInv, NOW());
end;
-- ------------------------------------------
-- Trigger: trg_purchase_receipt_item_after_insert
-- Event: INSERT
-- Table: Purchase_Receipt_Items
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_purchase_receipt_item_after_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_purchase_receipt_item_after_insert` AFTER INSERT ON `Purchase_Receipt_Items` FOR EACH ROW begin
INSERT INTO Stock_Movements
(
type,
quantity,
fee,
totalCost,
referenceType,
referenceId,
productId,
inventoryId,
avgCost,
createdAt
)
VALUES
(
'IN',
NEW.count,
NEW.fee,
NEW.total,
'PURCHASE',
NEW.receiptId,
NEW.productId,
(SELECT inventoryId FROM Purchase_Receipts WHERE id = NEW.receiptId),
NEW.total / NEW.count,
NOW()
);
end;
-- ------------------------------------------
-- Trigger: trg_purchase_receipt_item_after_update
-- Event: UPDATE
-- Table: Purchase_Receipt_Items
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_purchase_receipt_item_after_update`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_purchase_receipt_item_after_update` AFTER UPDATE ON `Purchase_Receipt_Items` FOR EACH ROW begin
DELETE FROM Stock_Movements
WHERE referenceType = 'PURCHASE'
AND referenceId = NEW.receiptId
AND productId = NEW.productId;
INSERT INTO Stock_Movements
(
type,
quantity,
referenceType,
referenceId,
productId,
inventoryId,
createdAt
)
VALUES
(
'IN',
NEW.count,
'SALES',
NEW.id,
NEW.productId,
(SELECT inventoryId FROM Stores LIMIT 1),
NOW()
);
end;
-- ------------------------------------------
-- Trigger: trg_purchase_receipt_item_after_delete
-- Event: DELETE
-- Table: Purchase_Receipt_Items
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_purchase_receipt_item_after_delete`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_purchase_receipt_item_after_delete` AFTER DELETE ON `Purchase_Receipt_Items` FOR EACH ROW begin
DELETE FROM Stock_Movements
WHERE referenceType = 'PURCHASE'
AND referenceId = OLD.receiptId
AND productId = OLD.productId;
end;
-- ------------------------------------------
-- Trigger: trg_sales_invoice_items_before_insert
-- Event: INSERT
-- Table: Sales_Invoice_Items
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_sales_invoice_items_before_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_sales_invoice_items_before_insert` BEFORE INSERT ON `Sales_Invoice_Items` FOR EACH ROW begin
DECLARE current_stock DECIMAL(10,2);
SELECT stock INTO current_stock
FROM stock_view
WHERE productId = NEW.productId
LIMIT 1;
IF current_stock IS NULL THEN
SET current_stock = 0;
END IF;
IF NEW.count > current_stock THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Not enough stock to complete sale.';
END IF;
end;
-- ------------------------------------------
-- Trigger: trg_sales_invoice_items_after_insert
-- Event: INSERT
-- Table: Sales_Invoice_Items
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_sales_invoice_items_after_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_sales_invoice_items_after_insert` AFTER INSERT ON `Sales_Invoice_Items` FOR EACH ROW begin
INSERT INTO Stock_Movements
(
type,
quantity,
referenceType,
referenceId,
productId,
inventoryId,
createdAt
)
VALUES
(
'IN',
NEW.count,
'PURCHASE',
NEW.id,
NEW.productId,
(SELECT inventoryId FROM Sales_Invoices WHERE id = NEW.id),
NOW()
);
end;
-- ------------------------------------------
-- Trigger: trg_stock_adjustment_after_insert
-- Event: INSERT
-- Table: Stock_Adjustments
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_adjustment_after_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_adjustment_after_insert` AFTER INSERT ON `Stock_Adjustments` FOR EACH ROW begin
INSERT INTO Stock_Movements
(type, quantity, referenceType, referenceId, productId, inventoryId, createdAt)
VALUES
('ADJUST', NEW.adjustedQuantity, 'ADJUSTMENT', NEW.id, NEW.productId, NEW.inventoryId, NOW());
end;
-- ------------------------------------------
-- Trigger: trg_stock_sale_insert
-- Event: INSERT
-- Table: Stock_Movements
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_sale_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_sale_insert` AFTER INSERT ON `Stock_Movements` FOR EACH ROW BEGIN
IF NEW.referenceType = 'SALES' THEN
UPDATE stock_balance
SET
quantity = quantity - NEW.quantity,
totalCost = quantity * avgCost
WHERE productId = NEW.productId ;
END IF;
END;
-- ------------------------------------------
-- Trigger: trg_stock_purchase_insert
-- Event: INSERT
-- Table: Stock_Movements
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_purchase_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_purchase_insert` AFTER INSERT ON `Stock_Movements` FOR EACH ROW BEGIN
IF NEW.referenceType = 'PURCHASE' THEN
INSERT INTO stock_balance (productId, quantity, avgCost, totalCost)
VALUES (
NEW.productId,
NEW.quantity,
NEW.fee,
NEW.totalCost
)
ON DUPLICATE KEY UPDATE
quantity = quantity + NEW.quantity,
totalCost = totalCost + NEW.totalCost,
avgCost = totalCost / quantity;
END IF;
END;
-- ------------------------------------------
-- Trigger: trg_stock_movement_after_insert
-- Event: INSERT
-- Table: Stock_Movements
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_movement_after_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_movement_after_insert` AFTER INSERT ON `Stock_Movements` FOR EACH ROW begin
UPDATE Products pv
SET pv.quantity = (
SELECT COALESCE(SUM(
CASE
WHEN type = 'IN' THEN quantity
WHEN type = 'OUT' THEN -quantity
WHEN type = 'ADJUST' THEN quantity
END
), 0)
FROM Stock_Movements
WHERE productId = NEW.productId
)
WHERE pv.id = NEW.productId;
end;
-- ------------------------------------------
-- Trigger: trg_stock_sale_update
-- Event: UPDATE
-- Table: Stock_Movements
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_sale_update`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_sale_update` AFTER UPDATE ON `Stock_Movements` FOR EACH ROW BEGIN
IF OLD.referenceType = 'SALES' THEN
UPDATE stock_balance
SET
quantity = quantity + OLD.quantity,
totalCost = (quantity + OLD.quantity) * avgCost
WHERE productId = OLD.productId;
END IF;
IF NEW.referenceType = 'SALES' THEN
UPDATE stock_balance
SET
quantity = quantity - NEW.quantity,
totalCost = (quantity - NEW.quantity) * avgCost
WHERE productId = NEW.productId;
END IF;
END;
-- ------------------------------------------
-- Trigger: trg_stock_purchase_update
-- Event: UPDATE
-- Table: Stock_Movements
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_purchase_update`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_purchase_update` AFTER UPDATE ON `Stock_Movements` FOR EACH ROW BEGIN
IF OLD.referenceType = 'PURCHASE' THEN
UPDATE stock_balance
SET
quantity = quantity - OLD.quantity,
totalCost = totalCost - (OLD.quantity * OLD.fee)
WHERE productId = OLD.productId;
END IF;
IF NEW.referenceType = 'PURCHASE' THEN
INSERT INTO stock_balance (productId, quantity, avgCost, totalCost)
VALUES (
NEW.productId,
NEW.quantity,
NEW.fee,
NEW.totalCost
)
ON DUPLICATE KEY UPDATE
quantity = quantity + NEW.quantity,
totalCost = totalCost + NEW.totalCost,
avgCost = totalCost / quantity;
END IF;
END;
-- ------------------------------------------
-- Trigger: trg_stock_sale_delete
-- Event: DELETE
-- Table: Stock_Movements
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_sale_delete`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_sale_delete` AFTER DELETE ON `Stock_Movements` FOR EACH ROW BEGIN
IF OLD.ReferenceType = 'SALES' THEN
UPDATE stock_balance
SET
quantity = quantity + OLD.quantity,
totalCost = (quantity + OLD.quantity) * avgCost
WHERE productId = OLD.productId;
END IF;
END;
-- ------------------------------------------
-- Trigger: trg_stock_purchase_delete
-- Event: DELETE
-- Table: Stock_Movements
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_purchase_delete`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_purchase_delete` AFTER DELETE ON `Stock_Movements` FOR EACH ROW BEGIN
IF OLD.referenceType = 'PURCHASE' THEN
UPDATE stock_balance
SET
quantity = quantity - OLD.quantity,
totalCost = totalCost - (OLD.quantity * OLD.fee),
avgCost = CASE
WHEN quantity - OLD.quantity = 0 THEN 0
ELSE (totalCost - (OLD.quantity * OLD.fee)) / (quantity - OLD.quantity)
END
WHERE productId = OLD.productId;
END IF;
END;
+326
View File
@@ -0,0 +1,326 @@
-- AUTO-GENERATED MYSQL TRIGGER DUMP
-- Generated at: 2025-12-10T10:03:36.966Z
-- ------------------------------------------
-- Trigger: trg_transfer_item_after_insert
-- Event: INSERT
-- Table: Inventory_Transfer_Items
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_transfer_item_after_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_transfer_item_after_insert` AFTER INSERT ON `Inventory_Transfer_Items` FOR EACH ROW begin
DECLARE fromInv INT;
DECLARE toInv INT;
SELECT fromInventoryId, toInventoryId INTO fromInv, toInv
FROM Inventory_Transfers WHERE id = NEW.transferId;
-- OUT from source
INSERT INTO Stock_Movements
(type, quantity, referenceType, referenceId, productId, inventoryId, createdAt)
VALUES
('OUT', NEW.count, 'InventoryTransfer', NEW.transferId, NEW.productId, fromInv, NOW());
-- IN to destination
INSERT INTO Stock_Movements
(type, quantity, referenceType, referenceId, productId, inventoryId, createdAt)
VALUES
('IN', NEW.count, 'InventoryTransfer', NEW.transferId, NEW.productId, toInv, NOW());
end;
-- ------------------------------------------
-- Trigger: trg_purchase_receipt_item_after_insert
-- Event: INSERT
-- Table: Purchase_Receipt_Items
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_purchase_receipt_item_after_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_purchase_receipt_item_after_insert` AFTER INSERT ON `Purchase_Receipt_Items` FOR EACH ROW begin
INSERT INTO Stock_Movements
(
type,
quantity,
referenceType,
referenceId,
productId,
inventoryId,
createdAt
)
VALUES
(
'IN',
NEW.count,
'PURCHASE',
NEW.receiptId,
NEW.productId,
(SELECT inventoryId FROM Purchase_Receipts WHERE id = NEW.receiptId),
NOW()
);
end;
-- ------------------------------------------
-- Trigger: trg_purchase_receipt_item_after_update
-- Event: UPDATE
-- Table: Purchase_Receipt_Items
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_purchase_receipt_item_after_update`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_purchase_receipt_item_after_update` AFTER UPDATE ON `Purchase_Receipt_Items` FOR EACH ROW begin
DELETE FROM Stock_Movements
WHERE referenceType = 'PURCHASE'
AND referenceId = NEW.receiptId
AND productId = NEW.productId;
INSERT INTO Stock_Movements
(
type,
quantity,
referenceType,
referenceId,
productId,
inventoryId,
createdAt
)
VALUES
(
'IN',
NEW.count,
'SALES',
NEW.id,
NEW.productId,
(SELECT inventoryId FROM Stores LIMIT 1),
NOW()
);
end;
-- ------------------------------------------
-- Trigger: trg_purchase_receipt_item_after_delete
-- Event: DELETE
-- Table: Purchase_Receipt_Items
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_purchase_receipt_item_after_delete`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_purchase_receipt_item_after_delete` AFTER DELETE ON `Purchase_Receipt_Items` FOR EACH ROW begin
DELETE FROM Stock_Movements
WHERE referenceType = 'PURCHASE'
AND referenceId = OLD.receiptId
AND productId = OLD.productId;
end;
-- ------------------------------------------
-- Trigger: trg_sales_invoice_items_before_insert
-- Event: INSERT
-- Table: Sales_Invoice_Items
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_sales_invoice_items_before_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_sales_invoice_items_before_insert` BEFORE INSERT ON `Sales_Invoice_Items` FOR EACH ROW begin
DECLARE current_stock DECIMAL(10,2);
SELECT stock INTO current_stock
FROM stock_view
WHERE productId = NEW.productId
LIMIT 1;
IF current_stock IS NULL THEN
SET current_stock = 0;
END IF;
IF NEW.count > current_stock THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Not enough stock to complete sale.';
END IF;
end;
-- ------------------------------------------
-- Trigger: trg_sales_invoice_items_after_insert
-- Event: INSERT
-- Table: Sales_Invoice_Items
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_sales_invoice_items_after_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_sales_invoice_items_after_insert` AFTER INSERT ON `Sales_Invoice_Items` FOR EACH ROW begin
INSERT INTO Stock_Movements
(
type,
quantity,
referenceType,
referenceId,
productId,
inventoryId,
createdAt
)
VALUES
(
'IN',
NEW.count,
'PURCHASE',
NEW.id,
NEW.productId,
(SELECT inventoryId FROM Sales_Invoices WHERE id = NEW.id),
NOW()
);
end;
-- ------------------------------------------
-- Trigger: trg_stock_adjustment_after_insert
-- Event: INSERT
-- Table: Stock_Adjustments
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_adjustment_after_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_adjustment_after_insert` AFTER INSERT ON `Stock_Adjustments` FOR EACH ROW begin
INSERT INTO Stock_Movements
(type, quantity, referenceType, referenceId, productId, inventoryId, createdAt)
VALUES
('ADJUST', NEW.adjustedQuantity, 'ADJUSTMENT', NEW.id, NEW.productId, NEW.inventoryId, NOW());
end;
-- ------------------------------------------
-- Trigger: trg_stock_sale_insert
-- Event: INSERT
-- Table: Stock_Movements
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_sale_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_sale_insert` AFTER INSERT ON `Stock_Movements` FOR EACH ROW BEGIN
IF NEW.referenceType = 'SALES' THEN
UPDATE stock_balance
SET
quantity = quantity - NEW.quantity,
totalCost = quantity * avgCost
WHERE productId = NEW.productId ;
END IF;
END;
-- ------------------------------------------
-- Trigger: trg_stock_purchase_insert
-- Event: INSERT
-- Table: Stock_Movements
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_purchase_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_purchase_insert` AFTER INSERT ON `Stock_Movements` FOR EACH ROW BEGIN
IF NEW.referenceType = 'PURCHASE' THEN
INSERT INTO stock_balance (productId, quantity, avgCost, totalCost)
VALUES (
NEW.productId,
NEW.quantity,
NEW.fee,
NEW.totalCost
)
ON DUPLICATE KEY UPDATE
quantity = quantity + NEW.quantity,
totalCost = totalCost + NEW.totalCost,
avgCost = totalCost / quantity;
END IF;
END;
-- ------------------------------------------
-- Trigger: trg_stock_movement_after_insert
-- Event: INSERT
-- Table: Stock_Movements
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_movement_after_insert`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_movement_after_insert` AFTER INSERT ON `Stock_Movements` FOR EACH ROW begin
UPDATE Products pv
SET pv.quantity = (
SELECT COALESCE(SUM(
CASE
WHEN type = 'IN' THEN quantity
WHEN type = 'OUT' THEN -quantity
WHEN type = 'ADJUST' THEN quantity
END
), 0)
FROM Stock_Movements
WHERE productId = NEW.productId
)
WHERE pv.id = NEW.productId;
end;
-- ------------------------------------------
-- Trigger: trg_stock_sale_update
-- Event: UPDATE
-- Table: Stock_Movements
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_sale_update`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_sale_update` AFTER UPDATE ON `Stock_Movements` FOR EACH ROW BEGIN
IF OLD.referenceType = 'SALES' THEN
UPDATE stock_balance
SET
quantity = quantity + OLD.quantity,
totalCost = (quantity + OLD.quantity) * avgCost
WHERE productId = OLD.productId;
END IF;
IF NEW.referenceType = 'SALES' THEN
UPDATE stock_balance
SET
quantity = quantity - NEW.quantity,
totalCost = (quantity - NEW.quantity) * avgCost
WHERE productId = NEW.productId;
END IF;
END;
-- ------------------------------------------
-- Trigger: trg_stock_purchase_update
-- Event: UPDATE
-- Table: Stock_Movements
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_purchase_update`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_purchase_update` AFTER UPDATE ON `Stock_Movements` FOR EACH ROW BEGIN
IF OLD.referenceType = 'PURCHASE' THEN
UPDATE stock_balance
SET
quantity = quantity - OLD.quantity,
totalCost = totalCost - (OLD.quantity * OLD.fee)
WHERE productId = OLD.productId;
END IF;
IF NEW.referenceType = 'PURCHASE' THEN
INSERT INTO stock_balance (productId, quantity, avgCost, totalCost)
VALUES (
NEW.productId,
NEW.quantity,
NEW.fee,
NEW.totalCost
)
ON DUPLICATE KEY UPDATE
quantity = quantity + NEW.quantity,
totalCost = totalCost + NEW.totalCost,
avgCost = totalCost / quantity;
END IF;
END;
-- ------------------------------------------
-- Trigger: trg_stock_sale_delete
-- Event: DELETE
-- Table: Stock_Movements
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_sale_delete`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_sale_delete` AFTER DELETE ON `Stock_Movements` FOR EACH ROW BEGIN
IF OLD.ReferenceType = 'SALES' THEN
UPDATE stock_balance
SET
quantity = quantity + OLD.quantity,
totalCost = (quantity + OLD.quantity) * avgCost
WHERE productId = OLD.productId;
END IF;
END;
-- ------------------------------------------
-- Trigger: trg_stock_purchase_delete
-- Event: DELETE
-- Table: Stock_Movements
-- ------------------------------------------
DROP TRIGGER IF EXISTS `trg_stock_purchase_delete`;
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_purchase_delete` AFTER DELETE ON `Stock_Movements` FOR EACH ROW BEGIN
IF OLD.referenceType = 'PURCHASE' THEN
UPDATE stock_balance
SET
quantity = quantity - OLD.quantity,
totalCost = totalCost - (OLD.quantity * OLD.fee),
avgCost = CASE
WHEN quantity - OLD.quantity = 0 THEN 0
ELSE (totalCost - (OLD.quantity * OLD.fee)) / (quantity - OLD.quantity)
END
WHERE productId = OLD.productId;
END IF;
END;
+62
View File
@@ -0,0 +1,62 @@
import 'dotenv/config'
import fs from 'fs'
import mysql from 'mysql2/promise'
import path from 'path'
import { env } from 'prisma/config'
const OUTPUT_DIR = path.join(process.cwd(), 'prisma', 'triggers')
async function main() {
const conn = await mysql.createConnection({
host: env('DATABASE_HOST'),
user: env('DATABASE_USER'),
password: env('DATABASE_PASSWORD'),
database: env('DATABASE_NAME'),
port: Number(env('DATABASE_PORT')) || 3306,
})
console.log('📌 Fetching triggers...')
const [triggers] = (await conn.execute('SHOW TRIGGERS')) as [Array<any>, any]
if (triggers.length === 0) {
console.log('⚠️ No triggers found in the database.')
return
}
// Ensure directory exists
fs.mkdirSync(OUTPUT_DIR, { recursive: true })
const dumpFile = path.join(OUTPUT_DIR, `dump_triggers.sql`)
let sqlOutput = '-- AUTO-GENERATED MYSQL TRIGGER DUMP\n'
sqlOutput += '-- Generated at: ' + new Date().toISOString() + '\n\n'
for (const trg of triggers) {
const name = trg.Trigger
console.log(`📥 Extracting trigger: ${name}`)
const [rows] = await conn.execute(`SHOW CREATE TRIGGER \`${name}\``)
const createStatement = rows[0]['SQL Original Statement']
sqlOutput += `-- ------------------------------------------\n`
sqlOutput += `-- Trigger: ${name}\n`
sqlOutput += `-- Event: ${trg.Event}\n`
sqlOutput += `-- Table: ${trg.Table}\n`
sqlOutput += `-- ------------------------------------------\n`
sqlOutput += `DROP TRIGGER IF EXISTS \`${name}\`;\n`
sqlOutput += `${createStatement};\n\n`
}
fs.writeFileSync(dumpFile, sqlOutput)
console.log('✅ Triggers exported to:')
console.log(` ${dumpFile}`)
await conn.end()
}
main().catch(err => {
console.error(err)
process.exit(1)
})
+24
View File
@@ -0,0 +1,24 @@
import 'dotenv/config'
import mysql from 'mysql2/promise'
import { env } from 'prisma/config'
;(async () => {
const db = await mysql.createConnection({
host: env('DATABASE_HOST'),
user: env('DATABASE_USER'),
password: env('DATABASE_PASSWORD'),
database: env('DATABASE_NAME'),
port: Number(env('DATABASE_PORT')) || 3306,
})
const [rows] = await db.query(`
SELECT
TRIGGER_NAME,
ACTION_STATEMENT
FROM INFORMATION_SCHEMA.TRIGGERS
WHERE TRIGGER_SCHEMA = DATABASE();
`)
console.log(rows)
await db.end()
})()
File diff suppressed because one or more lines are too long
@@ -2151,6 +2151,7 @@ export const PurchaseReceiptItemScalarFieldEnum = {
count: 'count', count: 'count',
fee: 'fee', fee: 'fee',
total: 'total', total: 'total',
description: 'description',
createdAt: 'createdAt', createdAt: 'createdAt',
receiptId: 'receiptId', receiptId: 'receiptId',
productId: 'productId' productId: 'productId'
@@ -2445,6 +2446,13 @@ export const PurchaseReceiptOrderByRelevanceFieldEnum = {
export type PurchaseReceiptOrderByRelevanceFieldEnum = (typeof PurchaseReceiptOrderByRelevanceFieldEnum)[keyof typeof PurchaseReceiptOrderByRelevanceFieldEnum] export type PurchaseReceiptOrderByRelevanceFieldEnum = (typeof PurchaseReceiptOrderByRelevanceFieldEnum)[keyof typeof PurchaseReceiptOrderByRelevanceFieldEnum]
export const PurchaseReceiptItemOrderByRelevanceFieldEnum = {
description: 'description'
} as const
export type PurchaseReceiptItemOrderByRelevanceFieldEnum = (typeof PurchaseReceiptItemOrderByRelevanceFieldEnum)[keyof typeof PurchaseReceiptItemOrderByRelevanceFieldEnum]
export const SalesInvoiceOrderByRelevanceFieldEnum = { export const SalesInvoiceOrderByRelevanceFieldEnum = {
code: 'code', code: 'code',
description: 'description' description: 'description'
@@ -302,6 +302,7 @@ export const PurchaseReceiptItemScalarFieldEnum = {
count: 'count', count: 'count',
fee: 'fee', fee: 'fee',
total: 'total', total: 'total',
description: 'description',
createdAt: 'createdAt', createdAt: 'createdAt',
receiptId: 'receiptId', receiptId: 'receiptId',
productId: 'productId' productId: 'productId'
@@ -596,6 +597,13 @@ export const PurchaseReceiptOrderByRelevanceFieldEnum = {
export type PurchaseReceiptOrderByRelevanceFieldEnum = (typeof PurchaseReceiptOrderByRelevanceFieldEnum)[keyof typeof PurchaseReceiptOrderByRelevanceFieldEnum] export type PurchaseReceiptOrderByRelevanceFieldEnum = (typeof PurchaseReceiptOrderByRelevanceFieldEnum)[keyof typeof PurchaseReceiptOrderByRelevanceFieldEnum]
export const PurchaseReceiptItemOrderByRelevanceFieldEnum = {
description: 'description'
} as const
export type PurchaseReceiptItemOrderByRelevanceFieldEnum = (typeof PurchaseReceiptItemOrderByRelevanceFieldEnum)[keyof typeof PurchaseReceiptItemOrderByRelevanceFieldEnum]
export const SalesInvoiceOrderByRelevanceFieldEnum = { export const SalesInvoiceOrderByRelevanceFieldEnum = {
code: 'code', code: 'code',
description: 'description' description: 'description'
@@ -49,6 +49,7 @@ export type PurchaseReceiptItemMinAggregateOutputType = {
count: runtime.Decimal | null count: runtime.Decimal | null
fee: runtime.Decimal | null fee: runtime.Decimal | null
total: runtime.Decimal | null total: runtime.Decimal | null
description: string | null
createdAt: Date | null createdAt: Date | null
receiptId: number | null receiptId: number | null
productId: number | null productId: number | null
@@ -59,6 +60,7 @@ export type PurchaseReceiptItemMaxAggregateOutputType = {
count: runtime.Decimal | null count: runtime.Decimal | null
fee: runtime.Decimal | null fee: runtime.Decimal | null
total: runtime.Decimal | null total: runtime.Decimal | null
description: string | null
createdAt: Date | null createdAt: Date | null
receiptId: number | null receiptId: number | null
productId: number | null productId: number | null
@@ -69,6 +71,7 @@ export type PurchaseReceiptItemCountAggregateOutputType = {
count: number count: number
fee: number fee: number
total: number total: number
description: number
createdAt: number createdAt: number
receiptId: number receiptId: number
productId: number productId: number
@@ -99,6 +102,7 @@ export type PurchaseReceiptItemMinAggregateInputType = {
count?: true count?: true
fee?: true fee?: true
total?: true total?: true
description?: true
createdAt?: true createdAt?: true
receiptId?: true receiptId?: true
productId?: true productId?: true
@@ -109,6 +113,7 @@ export type PurchaseReceiptItemMaxAggregateInputType = {
count?: true count?: true
fee?: true fee?: true
total?: true total?: true
description?: true
createdAt?: true createdAt?: true
receiptId?: true receiptId?: true
productId?: true productId?: true
@@ -119,6 +124,7 @@ export type PurchaseReceiptItemCountAggregateInputType = {
count?: true count?: true
fee?: true fee?: true
total?: true total?: true
description?: true
createdAt?: true createdAt?: true
receiptId?: true receiptId?: true
productId?: true productId?: true
@@ -216,6 +222,7 @@ export type PurchaseReceiptItemGroupByOutputType = {
count: runtime.Decimal count: runtime.Decimal
fee: runtime.Decimal fee: runtime.Decimal
total: runtime.Decimal total: runtime.Decimal
description: string | null
createdAt: Date createdAt: Date
receiptId: number receiptId: number
productId: number productId: number
@@ -249,6 +256,7 @@ export type PurchaseReceiptItemWhereInput = {
count?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string count?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string
fee?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string fee?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string total?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string
description?: Prisma.StringNullableFilter<"PurchaseReceiptItem"> | string | null
createdAt?: Prisma.DateTimeFilter<"PurchaseReceiptItem"> | Date | string createdAt?: Prisma.DateTimeFilter<"PurchaseReceiptItem"> | Date | string
receiptId?: Prisma.IntFilter<"PurchaseReceiptItem"> | number receiptId?: Prisma.IntFilter<"PurchaseReceiptItem"> | number
productId?: Prisma.IntFilter<"PurchaseReceiptItem"> | number productId?: Prisma.IntFilter<"PurchaseReceiptItem"> | number
@@ -261,11 +269,13 @@ export type PurchaseReceiptItemOrderByWithRelationInput = {
count?: Prisma.SortOrder count?: Prisma.SortOrder
fee?: Prisma.SortOrder fee?: Prisma.SortOrder
total?: Prisma.SortOrder total?: Prisma.SortOrder
description?: Prisma.SortOrderInput | Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
receiptId?: Prisma.SortOrder receiptId?: Prisma.SortOrder
productId?: Prisma.SortOrder productId?: Prisma.SortOrder
product?: Prisma.ProductOrderByWithRelationInput product?: Prisma.ProductOrderByWithRelationInput
receipt?: Prisma.PurchaseReceiptOrderByWithRelationInput receipt?: Prisma.PurchaseReceiptOrderByWithRelationInput
_relevance?: Prisma.PurchaseReceiptItemOrderByRelevanceInput
} }
export type PurchaseReceiptItemWhereUniqueInput = Prisma.AtLeast<{ export type PurchaseReceiptItemWhereUniqueInput = Prisma.AtLeast<{
@@ -276,6 +286,7 @@ export type PurchaseReceiptItemWhereUniqueInput = Prisma.AtLeast<{
count?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string count?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string
fee?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string fee?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string total?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string
description?: Prisma.StringNullableFilter<"PurchaseReceiptItem"> | string | null
createdAt?: Prisma.DateTimeFilter<"PurchaseReceiptItem"> | Date | string createdAt?: Prisma.DateTimeFilter<"PurchaseReceiptItem"> | Date | string
receiptId?: Prisma.IntFilter<"PurchaseReceiptItem"> | number receiptId?: Prisma.IntFilter<"PurchaseReceiptItem"> | number
productId?: Prisma.IntFilter<"PurchaseReceiptItem"> | number productId?: Prisma.IntFilter<"PurchaseReceiptItem"> | number
@@ -288,6 +299,7 @@ export type PurchaseReceiptItemOrderByWithAggregationInput = {
count?: Prisma.SortOrder count?: Prisma.SortOrder
fee?: Prisma.SortOrder fee?: Prisma.SortOrder
total?: Prisma.SortOrder total?: Prisma.SortOrder
description?: Prisma.SortOrderInput | Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
receiptId?: Prisma.SortOrder receiptId?: Prisma.SortOrder
productId?: Prisma.SortOrder productId?: Prisma.SortOrder
@@ -306,6 +318,7 @@ export type PurchaseReceiptItemScalarWhereWithAggregatesInput = {
count?: Prisma.DecimalWithAggregatesFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string count?: Prisma.DecimalWithAggregatesFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string
fee?: Prisma.DecimalWithAggregatesFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string fee?: Prisma.DecimalWithAggregatesFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalWithAggregatesFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string total?: Prisma.DecimalWithAggregatesFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string
description?: Prisma.StringNullableWithAggregatesFilter<"PurchaseReceiptItem"> | string | null
createdAt?: Prisma.DateTimeWithAggregatesFilter<"PurchaseReceiptItem"> | Date | string createdAt?: Prisma.DateTimeWithAggregatesFilter<"PurchaseReceiptItem"> | Date | string
receiptId?: Prisma.IntWithAggregatesFilter<"PurchaseReceiptItem"> | number receiptId?: Prisma.IntWithAggregatesFilter<"PurchaseReceiptItem"> | number
productId?: Prisma.IntWithAggregatesFilter<"PurchaseReceiptItem"> | number productId?: Prisma.IntWithAggregatesFilter<"PurchaseReceiptItem"> | number
@@ -315,6 +328,7 @@ export type PurchaseReceiptItemCreateInput = {
count: runtime.Decimal | runtime.DecimalJsLike | number | string count: runtime.Decimal | runtime.DecimalJsLike | number | string
fee: runtime.Decimal | runtime.DecimalJsLike | number | string fee: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string total: runtime.Decimal | runtime.DecimalJsLike | number | string
description?: string | null
createdAt?: Date | string createdAt?: Date | string
product: Prisma.ProductCreateNestedOneWithoutPurchaseReceiptItemsInput product: Prisma.ProductCreateNestedOneWithoutPurchaseReceiptItemsInput
receipt: Prisma.PurchaseReceiptCreateNestedOneWithoutItemsInput receipt: Prisma.PurchaseReceiptCreateNestedOneWithoutItemsInput
@@ -325,6 +339,7 @@ export type PurchaseReceiptItemUncheckedCreateInput = {
count: runtime.Decimal | runtime.DecimalJsLike | number | string count: runtime.Decimal | runtime.DecimalJsLike | number | string
fee: runtime.Decimal | runtime.DecimalJsLike | number | string fee: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string total: runtime.Decimal | runtime.DecimalJsLike | number | string
description?: string | null
createdAt?: Date | string createdAt?: Date | string
receiptId: number receiptId: number
productId: number productId: number
@@ -334,6 +349,7 @@ export type PurchaseReceiptItemUpdateInput = {
count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
product?: Prisma.ProductUpdateOneRequiredWithoutPurchaseReceiptItemsNestedInput product?: Prisma.ProductUpdateOneRequiredWithoutPurchaseReceiptItemsNestedInput
receipt?: Prisma.PurchaseReceiptUpdateOneRequiredWithoutItemsNestedInput receipt?: Prisma.PurchaseReceiptUpdateOneRequiredWithoutItemsNestedInput
@@ -344,6 +360,7 @@ export type PurchaseReceiptItemUncheckedUpdateInput = {
count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
receiptId?: Prisma.IntFieldUpdateOperationsInput | number receiptId?: Prisma.IntFieldUpdateOperationsInput | number
productId?: Prisma.IntFieldUpdateOperationsInput | number productId?: Prisma.IntFieldUpdateOperationsInput | number
@@ -354,6 +371,7 @@ export type PurchaseReceiptItemCreateManyInput = {
count: runtime.Decimal | runtime.DecimalJsLike | number | string count: runtime.Decimal | runtime.DecimalJsLike | number | string
fee: runtime.Decimal | runtime.DecimalJsLike | number | string fee: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string total: runtime.Decimal | runtime.DecimalJsLike | number | string
description?: string | null
createdAt?: Date | string createdAt?: Date | string
receiptId: number receiptId: number
productId: number productId: number
@@ -363,6 +381,7 @@ export type PurchaseReceiptItemUpdateManyMutationInput = {
count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
} }
@@ -371,6 +390,7 @@ export type PurchaseReceiptItemUncheckedUpdateManyInput = {
count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
receiptId?: Prisma.IntFieldUpdateOperationsInput | number receiptId?: Prisma.IntFieldUpdateOperationsInput | number
productId?: Prisma.IntFieldUpdateOperationsInput | number productId?: Prisma.IntFieldUpdateOperationsInput | number
@@ -386,11 +406,18 @@ export type PurchaseReceiptItemOrderByRelationAggregateInput = {
_count?: Prisma.SortOrder _count?: Prisma.SortOrder
} }
export type PurchaseReceiptItemOrderByRelevanceInput = {
fields: Prisma.PurchaseReceiptItemOrderByRelevanceFieldEnum | Prisma.PurchaseReceiptItemOrderByRelevanceFieldEnum[]
sort: Prisma.SortOrder
search: string
}
export type PurchaseReceiptItemCountOrderByAggregateInput = { export type PurchaseReceiptItemCountOrderByAggregateInput = {
id?: Prisma.SortOrder id?: Prisma.SortOrder
count?: Prisma.SortOrder count?: Prisma.SortOrder
fee?: Prisma.SortOrder fee?: Prisma.SortOrder
total?: Prisma.SortOrder total?: Prisma.SortOrder
description?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
receiptId?: Prisma.SortOrder receiptId?: Prisma.SortOrder
productId?: Prisma.SortOrder productId?: Prisma.SortOrder
@@ -410,6 +437,7 @@ export type PurchaseReceiptItemMaxOrderByAggregateInput = {
count?: Prisma.SortOrder count?: Prisma.SortOrder
fee?: Prisma.SortOrder fee?: Prisma.SortOrder
total?: Prisma.SortOrder total?: Prisma.SortOrder
description?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
receiptId?: Prisma.SortOrder receiptId?: Prisma.SortOrder
productId?: Prisma.SortOrder productId?: Prisma.SortOrder
@@ -420,6 +448,7 @@ export type PurchaseReceiptItemMinOrderByAggregateInput = {
count?: Prisma.SortOrder count?: Prisma.SortOrder
fee?: Prisma.SortOrder fee?: Prisma.SortOrder
total?: Prisma.SortOrder total?: Prisma.SortOrder
description?: Prisma.SortOrder
createdAt?: Prisma.SortOrder createdAt?: Prisma.SortOrder
receiptId?: Prisma.SortOrder receiptId?: Prisma.SortOrder
productId?: Prisma.SortOrder productId?: Prisma.SortOrder
@@ -522,6 +551,7 @@ export type PurchaseReceiptItemCreateWithoutProductInput = {
count: runtime.Decimal | runtime.DecimalJsLike | number | string count: runtime.Decimal | runtime.DecimalJsLike | number | string
fee: runtime.Decimal | runtime.DecimalJsLike | number | string fee: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string total: runtime.Decimal | runtime.DecimalJsLike | number | string
description?: string | null
createdAt?: Date | string createdAt?: Date | string
receipt: Prisma.PurchaseReceiptCreateNestedOneWithoutItemsInput receipt: Prisma.PurchaseReceiptCreateNestedOneWithoutItemsInput
} }
@@ -531,6 +561,7 @@ export type PurchaseReceiptItemUncheckedCreateWithoutProductInput = {
count: runtime.Decimal | runtime.DecimalJsLike | number | string count: runtime.Decimal | runtime.DecimalJsLike | number | string
fee: runtime.Decimal | runtime.DecimalJsLike | number | string fee: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string total: runtime.Decimal | runtime.DecimalJsLike | number | string
description?: string | null
createdAt?: Date | string createdAt?: Date | string
receiptId: number receiptId: number
} }
@@ -569,6 +600,7 @@ export type PurchaseReceiptItemScalarWhereInput = {
count?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string count?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string
fee?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string fee?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string total?: Prisma.DecimalFilter<"PurchaseReceiptItem"> | runtime.Decimal | runtime.DecimalJsLike | number | string
description?: Prisma.StringNullableFilter<"PurchaseReceiptItem"> | string | null
createdAt?: Prisma.DateTimeFilter<"PurchaseReceiptItem"> | Date | string createdAt?: Prisma.DateTimeFilter<"PurchaseReceiptItem"> | Date | string
receiptId?: Prisma.IntFilter<"PurchaseReceiptItem"> | number receiptId?: Prisma.IntFilter<"PurchaseReceiptItem"> | number
productId?: Prisma.IntFilter<"PurchaseReceiptItem"> | number productId?: Prisma.IntFilter<"PurchaseReceiptItem"> | number
@@ -578,6 +610,7 @@ export type PurchaseReceiptItemCreateWithoutReceiptInput = {
count: runtime.Decimal | runtime.DecimalJsLike | number | string count: runtime.Decimal | runtime.DecimalJsLike | number | string
fee: runtime.Decimal | runtime.DecimalJsLike | number | string fee: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string total: runtime.Decimal | runtime.DecimalJsLike | number | string
description?: string | null
createdAt?: Date | string createdAt?: Date | string
product: Prisma.ProductCreateNestedOneWithoutPurchaseReceiptItemsInput product: Prisma.ProductCreateNestedOneWithoutPurchaseReceiptItemsInput
} }
@@ -587,6 +620,7 @@ export type PurchaseReceiptItemUncheckedCreateWithoutReceiptInput = {
count: runtime.Decimal | runtime.DecimalJsLike | number | string count: runtime.Decimal | runtime.DecimalJsLike | number | string
fee: runtime.Decimal | runtime.DecimalJsLike | number | string fee: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string total: runtime.Decimal | runtime.DecimalJsLike | number | string
description?: string | null
createdAt?: Date | string createdAt?: Date | string
productId: number productId: number
} }
@@ -622,6 +656,7 @@ export type PurchaseReceiptItemCreateManyProductInput = {
count: runtime.Decimal | runtime.DecimalJsLike | number | string count: runtime.Decimal | runtime.DecimalJsLike | number | string
fee: runtime.Decimal | runtime.DecimalJsLike | number | string fee: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string total: runtime.Decimal | runtime.DecimalJsLike | number | string
description?: string | null
createdAt?: Date | string createdAt?: Date | string
receiptId: number receiptId: number
} }
@@ -630,6 +665,7 @@ export type PurchaseReceiptItemUpdateWithoutProductInput = {
count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
receipt?: Prisma.PurchaseReceiptUpdateOneRequiredWithoutItemsNestedInput receipt?: Prisma.PurchaseReceiptUpdateOneRequiredWithoutItemsNestedInput
} }
@@ -639,6 +675,7 @@ export type PurchaseReceiptItemUncheckedUpdateWithoutProductInput = {
count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
receiptId?: Prisma.IntFieldUpdateOperationsInput | number receiptId?: Prisma.IntFieldUpdateOperationsInput | number
} }
@@ -648,6 +685,7 @@ export type PurchaseReceiptItemUncheckedUpdateManyWithoutProductInput = {
count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
receiptId?: Prisma.IntFieldUpdateOperationsInput | number receiptId?: Prisma.IntFieldUpdateOperationsInput | number
} }
@@ -657,6 +695,7 @@ export type PurchaseReceiptItemCreateManyReceiptInput = {
count: runtime.Decimal | runtime.DecimalJsLike | number | string count: runtime.Decimal | runtime.DecimalJsLike | number | string
fee: runtime.Decimal | runtime.DecimalJsLike | number | string fee: runtime.Decimal | runtime.DecimalJsLike | number | string
total: runtime.Decimal | runtime.DecimalJsLike | number | string total: runtime.Decimal | runtime.DecimalJsLike | number | string
description?: string | null
createdAt?: Date | string createdAt?: Date | string
productId: number productId: number
} }
@@ -665,6 +704,7 @@ export type PurchaseReceiptItemUpdateWithoutReceiptInput = {
count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
product?: Prisma.ProductUpdateOneRequiredWithoutPurchaseReceiptItemsNestedInput product?: Prisma.ProductUpdateOneRequiredWithoutPurchaseReceiptItemsNestedInput
} }
@@ -674,6 +714,7 @@ export type PurchaseReceiptItemUncheckedUpdateWithoutReceiptInput = {
count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
productId?: Prisma.IntFieldUpdateOperationsInput | number productId?: Prisma.IntFieldUpdateOperationsInput | number
} }
@@ -683,6 +724,7 @@ export type PurchaseReceiptItemUncheckedUpdateManyWithoutReceiptInput = {
count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string count?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string fee?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string total?: Prisma.DecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
productId?: Prisma.IntFieldUpdateOperationsInput | number productId?: Prisma.IntFieldUpdateOperationsInput | number
} }
@@ -694,6 +736,7 @@ export type PurchaseReceiptItemSelect<ExtArgs extends runtime.Types.Extensions.I
count?: boolean count?: boolean
fee?: boolean fee?: boolean
total?: boolean total?: boolean
description?: boolean
createdAt?: boolean createdAt?: boolean
receiptId?: boolean receiptId?: boolean
productId?: boolean productId?: boolean
@@ -708,12 +751,13 @@ export type PurchaseReceiptItemSelectScalar = {
count?: boolean count?: boolean
fee?: boolean fee?: boolean
total?: boolean total?: boolean
description?: boolean
createdAt?: boolean createdAt?: boolean
receiptId?: boolean receiptId?: boolean
productId?: boolean productId?: boolean
} }
export type PurchaseReceiptItemOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "count" | "fee" | "total" | "createdAt" | "receiptId" | "productId", ExtArgs["result"]["purchaseReceiptItem"]> export type PurchaseReceiptItemOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"id" | "count" | "fee" | "total" | "description" | "createdAt" | "receiptId" | "productId", ExtArgs["result"]["purchaseReceiptItem"]>
export type PurchaseReceiptItemInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = { export type PurchaseReceiptItemInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
product?: boolean | Prisma.ProductDefaultArgs<ExtArgs> product?: boolean | Prisma.ProductDefaultArgs<ExtArgs>
receipt?: boolean | Prisma.PurchaseReceiptDefaultArgs<ExtArgs> receipt?: boolean | Prisma.PurchaseReceiptDefaultArgs<ExtArgs>
@@ -730,6 +774,7 @@ export type $PurchaseReceiptItemPayload<ExtArgs extends runtime.Types.Extensions
count: runtime.Decimal count: runtime.Decimal
fee: runtime.Decimal fee: runtime.Decimal
total: runtime.Decimal total: runtime.Decimal
description: string | null
createdAt: Date createdAt: Date
receiptId: number receiptId: number
productId: number productId: number
@@ -1108,6 +1153,7 @@ export interface PurchaseReceiptItemFieldRefs {
readonly count: Prisma.FieldRef<"PurchaseReceiptItem", 'Decimal'> readonly count: Prisma.FieldRef<"PurchaseReceiptItem", 'Decimal'>
readonly fee: Prisma.FieldRef<"PurchaseReceiptItem", 'Decimal'> readonly fee: Prisma.FieldRef<"PurchaseReceiptItem", 'Decimal'>
readonly total: Prisma.FieldRef<"PurchaseReceiptItem", 'Decimal'> readonly total: Prisma.FieldRef<"PurchaseReceiptItem", 'Decimal'>
readonly description: Prisma.FieldRef<"PurchaseReceiptItem", 'String'>
readonly createdAt: Prisma.FieldRef<"PurchaseReceiptItem", 'DateTime'> readonly createdAt: Prisma.FieldRef<"PurchaseReceiptItem", 'DateTime'>
readonly receiptId: Prisma.FieldRef<"PurchaseReceiptItem", 'Int'> readonly receiptId: Prisma.FieldRef<"PurchaseReceiptItem", 'Int'>
readonly productId: Prisma.FieldRef<"PurchaseReceiptItem", 'Int'> readonly productId: Prisma.FieldRef<"PurchaseReceiptItem", 'Int'>
@@ -31,4 +31,9 @@ export class InventoriesController {
remove(@Param('id') id: string) { remove(@Param('id') id: string) {
return this.inventoriesService.remove(Number(id)) return this.inventoriesService.remove(Number(id))
} }
@Get(':id/stock-movements')
findStockMovements(@Param('id') id: string) {
return this.inventoriesService.findStockMovements(Number(id))
}
} }
+21 -39
View File
@@ -1,5 +1,4 @@
import { Injectable } from '@nestjs/common' import { Injectable } from '@nestjs/common'
import { ShortEntity } from '../common/interfaces/response-models'
import { ResponseMapper } from '../common/response/response-mapper' import { ResponseMapper } from '../common/response/response-mapper'
import { PrismaService } from '../prisma/prisma.service' import { PrismaService } from '../prisma/prisma.service'
@@ -12,52 +11,18 @@ export class InventoriesService {
} }
async findAll() { async findAll() {
const items = await this.prisma.inventory.findMany({ const items = await this.prisma.inventory.findMany()
include: { productCharges: { include: { product: true } } },
})
const mapped = items.map(i => { return ResponseMapper.list(items)
const productsMap: Record<number, ShortEntity> = {}
for (const pc of i.productCharges ?? []) {
if (pc.product) {
productsMap[pc.product.id] = { id: pc.product.id, name: pc.product.name }
}
}
const groupedProducts = Object.values(productsMap)
const { productCharges, ...rest } = i as any
return { ...rest, groupedProducts }
})
return ResponseMapper.list(mapped)
} }
async findOne(id: number) { async findOne(id: number) {
const item = await this.prisma.inventory.findUnique({ const item = await this.prisma.inventory.findUnique({
where: { id }, where: { id },
include: { productCharges: { include: { product: true } } }, include: { purchaseReceipts: true },
}) })
if (!item) return null if (!item) return null
const productsMap: Record<number, { id: number; name: string; count: number }> = {} return ResponseMapper.single(item)
for (const pc of item.productCharges ?? []) {
const pid = pc.productId
const pname = pc.product?.name ?? `#${pid}`
if (!productsMap[pid]) productsMap[pid] = { id: pid, name: pname, count: 0 }
productsMap[pid].count += Number(pc.count)
}
const productsWithCount = Object.values(productsMap)
const groupedProducts: ShortEntity[] = productsWithCount.map(p => ({
id: p.id,
name: p.name,
}))
const { productCharges, ...rest } = item as any
const itemWithCounts = {
...rest,
products: productsWithCount,
groupedProducts,
}
return ResponseMapper.single(itemWithCounts)
} }
async update(id: number, data: any) { async update(id: number, data: any) {
@@ -69,4 +34,21 @@ export class InventoriesService {
const item = await this.prisma.inventory.delete({ where: { id } }) const item = await this.prisma.inventory.delete({ where: { id } })
return ResponseMapper.single(item) return ResponseMapper.single(item)
} }
async findStockMovements(inventoryId: number) {
// Return a flat list of stock movements, each including its product info
const movements = await this.prisma.stockMovement.findMany({
where: { inventoryId },
include: { product: true },
})
// Map each movement to have a 'products' array (even if only one product)
const mapped = movements.map(movement => {
const { product, ...rest } = movement
return {
...rest,
products: product ? [product] : [],
}
})
return ResponseMapper.list(mapped)
}
} }
@@ -1,24 +1,25 @@
import { Type } from 'class-transformer' import { Type } from 'class-transformer'
import { IsInt, IsNumber } from 'class-validator' import { IsNotEmpty, IsNumber, Min } from 'class-validator'
export class CreatePurchaseReceiptItemDto { export class CreatePurchaseReceiptItemDto {
@Type(() => Number) @Type(() => Number)
@IsNumber() @IsNumber()
@Min(0)
count: number count: number
@Type(() => Number) @Type(() => Number)
@IsNumber() @IsNumber()
@Min(0)
fee: number fee: number
@Type(() => Number) @Type(() => Number)
@IsNumber() @IsNumber()
@Min(0)
total: number total: number
@Type(() => Number) @Type(() => Number)
@IsInt() @IsNotEmpty()
receiptId: number
@Type(() => Number)
@IsInt()
productId: number productId: number
description?: string
} }
@@ -9,15 +9,17 @@ export class PurchaseReceiptItemsService {
async create(dto: CreatePurchaseReceiptItemDto) { async create(dto: CreatePurchaseReceiptItemDto) {
const payload: any = { ...dto } const payload: any = { ...dto }
if (Object.prototype.hasOwnProperty.call(payload, 'receiptId')) {
payload.receipt = { connect: { id: Number(payload.receiptId) } }
delete payload.receiptId
}
if (Object.prototype.hasOwnProperty.call(payload, 'productId')) { if (Object.prototype.hasOwnProperty.call(payload, 'productId')) {
payload.product = { connect: { id: Number(payload.productId) } } payload.product = { connect: { id: Number(payload.productId) } }
delete payload.productId delete payload.productId
} }
if (Object.prototype.hasOwnProperty.call(payload, 'receiptId')) {
payload.receipt = { connect: { id: Number(payload.receiptId) } }
delete payload.receiptId
}
payload.fee = String(payload.fee)
payload.count = String(payload.count)
payload.total = String(payload.total)
const item = await this.prisma.purchaseReceiptItem.create({ data: payload }) const item = await this.prisma.purchaseReceiptItem.create({ data: payload })
return ResponseMapper.create(item) return ResponseMapper.create(item)
} }
@@ -1,5 +1,6 @@
import { Type } from 'class-transformer' import { Type } from 'class-transformer'
import { IsInt, IsNumber, IsOptional, IsString } from 'class-validator' import { ArrayMinSize, IsInt, IsNumber, IsOptional, IsString } from 'class-validator'
import { CreatePurchaseReceiptItemDto } from '../../purchase-receipt-items/dto/create-purchase-receipt-item.dto'
export class CreatePurchaseReceiptDto { export class CreatePurchaseReceiptDto {
@IsString() @IsString()
@@ -20,4 +21,8 @@ export class CreatePurchaseReceiptDto {
@Type(() => Number) @Type(() => Number)
@IsInt() @IsInt()
inventoryId: number inventoryId: number
@Type(() => Array)
@ArrayMinSize(1)
items: Array<Omit<CreatePurchaseReceiptItemDto, 'receiptId'>>
} }
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common' import { Injectable } from '@nestjs/common'
import { ResponseMapper } from '../common/response/response-mapper' import { ResponseMapper } from '../common/response/response-mapper'
import { Prisma } from '../generated/prisma/client'
import { PrismaService } from '../prisma/prisma.service' import { PrismaService } from '../prisma/prisma.service'
import { CreatePurchaseReceiptDto } from './dto/create-purchase-receipt.dto' import { CreatePurchaseReceiptDto } from './dto/create-purchase-receipt.dto'
@@ -8,17 +9,32 @@ export class PurchaseReceiptsService {
constructor(private prisma: PrismaService) {} constructor(private prisma: PrismaService) {}
async create(dto: CreatePurchaseReceiptDto) { async create(dto: CreatePurchaseReceiptDto) {
const payload: any = { ...dto } const data: Prisma.PurchaseReceiptCreateInput = {
if (Object.prototype.hasOwnProperty.call(payload, 'supplierId')) { code: dto.code,
payload.supplier = { connect: { id: Number(payload.supplierId) } } totalAmount: new Prisma.Decimal(dto.totalAmount),
delete payload.supplierId description: dto.description ?? null,
supplier: { connect: { id: dto.supplierId } },
inventory: { connect: { id: dto.inventoryId } },
items: dto.items?.length
? {
create: dto.items.map((item, idx) => {
const mapped = {
count: new Prisma.Decimal(item.count ?? 0),
fee: new Prisma.Decimal(item.fee ?? 0),
total: new Prisma.Decimal(item.total ?? 0),
description: item.description ?? null,
product: { connect: { id: item.productId } },
}
console.log(`[create] Step 3: Mapped item ${idx}:`, mapped)
return mapped
}),
}
: undefined,
} }
if (Object.prototype.hasOwnProperty.call(payload, 'inventoryId')) { const item = await this.prisma.purchaseReceipt.create({
payload.inventory = { connect: { id: Number(payload.inventoryId) } } data,
delete payload.inventoryId include: { items: true },
} })
const item = await this.prisma.purchaseReceipt.create({ data: payload })
return ResponseMapper.create(item) return ResponseMapper.create(item)
} }