diff --git a/prisma/triggers/dump_triggers.sql b/prisma/triggers/dump_triggers.sql index a0e2921..afefe82 100644 --- a/prisma/triggers/dump_triggers.sql +++ b/prisma/triggers/dump_triggers.sql @@ -1,34 +1,19 @@ -- AUTO-GENERATED MYSQL TRIGGER DUMP --- Generated at: 2026-01-04T09:46:30.365Z +-- Generated at: 2026-01-04T17:29:18.092Z -- ------------------------------------------ -- index: 1 --- Trigger: trg_bank_account_transaction_after_insert --- Event: INSERT --- Table: Bank_Account_Transactions --- ------------------------------------------ -DROP TRIGGER IF EXISTS `trg_bank_account_transaction_after_insert`; -CREATE DEFINER=`pos`@`%` TRIGGER `trg_bank_account_transaction_after_insert` AFTER INSERT ON `Bank_Account_Transactions` FOR EACH ROW BEGIN - IF NEW.type = 'DEPOSIT' THEN - UPDATE Bank_Account_Balance SET balance = balance + NEW.amount WHERE bankAccountId = NEW.bankAccountId; - ELSEIF NEW.type = 'WITHDRAWAL' THEN - UPDATE Bank_Account_Balance SET balance = balance - NEW.amount WHERE bankAccountId = NEW.bankAccountId; - END IF; -END; - --- ------------------------------------------ --- index: 2 -- Trigger: trg_bank_account_transaction_after_delete -- Event: DELETE -- Table: Bank_Account_Transactions -- ------------------------------------------ DROP TRIGGER IF EXISTS `trg_bank_account_transaction_after_delete`; CREATE DEFINER=`pos`@`%` TRIGGER `trg_bank_account_transaction_after_delete` AFTER DELETE ON `Bank_Account_Transactions` FOR EACH ROW BEGIN - UPDATE Bank_Accounts SET balance = balance - OLD.amount; + UPDATE `Bank_Account_Balance` SET balance = balance - OLD.amount WHERE `bankAccountId` = OLD.bankAccountId; END; -- ------------------------------------------ --- index: 3 +-- index: 2 -- Trigger: trg_transfer_item_after_insert -- Event: INSERT -- Table: Inventory_Transfer_Items @@ -66,7 +51,7 @@ DECLARE fromInv INT; end; -- ------------------------------------------ --- index: 4 +-- index: 3 -- Trigger: trg_order_item_after_insert -- Event: INSERT -- Table: Order_Items @@ -78,7 +63,7 @@ CREATE DEFINER=`pos`@`%` TRIGGER `trg_order_item_after_insert` AFTER INSERT ON ` END; -- ------------------------------------------ --- index: 5 +-- index: 4 -- Trigger: trg_order_item_after_update -- Event: UPDATE -- Table: Order_Items @@ -91,7 +76,7 @@ CREATE DEFINER=`pos`@`%` TRIGGER `trg_order_item_after_update` AFTER UPDATE ON ` END; -- ------------------------------------------ --- index: 6 +-- index: 5 -- Trigger: trg_order_item_after_delete -- Event: DELETE -- Table: Order_Items @@ -104,7 +89,7 @@ CREATE DEFINER=`pos`@`%` TRIGGER `trg_order_item_after_delete` AFTER DELETE ON ` END; -- ------------------------------------------ --- index: 7 +-- index: 6 -- Trigger: trg_order_after_cancel -- Event: UPDATE -- Table: Orders @@ -118,7 +103,7 @@ CREATE DEFINER=`pos`@`%` TRIGGER `trg_order_after_cancel` AFTER UPDATE ON `Order END; -- ------------------------------------------ --- index: 8 +-- index: 7 -- Trigger: trg_purchase_receipt_item_after_insert -- Event: INSERT -- Table: Purchase_Receipt_Items @@ -181,222 +166,7 @@ DECLARE invId INT; END; -- ------------------------------------------ --- index: 9 --- Trigger: trg_pr_payment_before_insert --- Event: INSERT --- Table: Purchase_Receipt_Payments --- ------------------------------------------ -DROP TRIGGER IF EXISTS `trg_pr_payment_before_insert`; -CREATE DEFINER=`pos`@`%` TRIGGER `trg_pr_payment_before_insert` BEFORE INSERT ON `Purchase_Receipt_Payments` FOR EACH ROW BEGIN - - - DECLARE receiptTotal DECIMAL(14,2); - DECLARE paid DECIMAL(14,2); - - - SELECT totalAmount, paidAmount - INTO receiptTotal, paid - FROM Purchase_Receipts - WHERE id = NEW.receiptId - FOR UPDATE; - - IF NEW.type = 'PAYMENT' AND paid + NEW.amount > receiptTotal THEN - SIGNAL SQLSTATE '45000' - SET MESSAGE_TEXT = 'مجموع مبلغ پرداختی بیشتر از مبلغ فاکتور است.'; - END IF; -END; - --- ------------------------------------------ --- index: 10 --- Trigger: trg_purchase_payment_update_receipt --- Event: INSERT --- Table: Purchase_Receipt_Payments --- ------------------------------------------ -DROP TRIGGER IF EXISTS `trg_purchase_payment_update_receipt`; -CREATE DEFINER=`pos`@`%` TRIGGER `trg_purchase_payment_update_receipt` AFTER INSERT ON `Purchase_Receipt_Payments` FOR EACH ROW BEGIN - DECLARE paid DECIMAL(15,2); - DECLARE total DECIMAL(15,2); - - SELECT - COALESCE(SUM( - CASE WHEN type = 'PAYMENT' THEN amount ELSE -amount END - ),0) - INTO paid - FROM Purchase_Receipt_Payments - WHERE receiptId = NEW.receiptId; - - SELECT totalAmount INTO total - FROM Purchase_Receipts - WHERE id = NEW.receiptId; - - UPDATE Purchase_Receipts - SET - paidAmount = paid, - status = CASE - WHEN paid = 0 THEN 'UNPAID' - WHEN paid < total THEN 'PARTIALLY_PAID' - ELSE 'PAID' - END - WHERE id = NEW.receiptId; -END; - --- ------------------------------------------ --- index: 11 --- Trigger: trg_purchase_payment_after_insert --- Event: INSERT --- Table: Purchase_Receipt_Payments --- ------------------------------------------ -DROP TRIGGER IF EXISTS `trg_purchase_payment_after_insert`; -CREATE DEFINER=`pos`@`%` TRIGGER `trg_purchase_payment_after_insert` AFTER INSERT ON `Purchase_Receipt_Payments` FOR EACH ROW BEGIN - -DECLARE currentBalance DECIMAL(15, 2); - - -SELECT balance INTO currentBalance -FROM Bank_Account_Balance -WHERE - bankAccountId = NEW.bankAccountId FOR -UPDATE; - - -IF currentBalance IS NULL THEN SET currentBalance = 0; - - -INSERT INTO - Bank_Account_Balance (bankAccountId, balance, updatedAt) -VALUES (NEW.bankAccountId, 0, NOW()); - -END IF; - -IF NEW.type = 'PAYMENT' THEN -SET - currentBalance = currentBalance - NEW.amount; - -INSERT INTO - Bank_Account_Transactions ( - bankAccountId, - type, - amount, - balanceAfter, - referenceType, - referenceId - ) -VALUES ( - NEW.bankAccountId, - 'WITHDRAWAL', - NEW.amount, - currentBalance, - 'PURCHASE_PAYMENT', - NEW.id - ); - -ELSE SET currentBalance = currentBalance + NEW.amount; - -INSERT INTO - Bank_Account_Transactions ( - bankAccountId, - type, - amount, - balanceAfter, - referenceType, - referenceId - ) -VALUES ( - NEW.bankAccountId, - 'DEPOSIT', - NEW.amount, - currentBalance, - 'PURCHASE_REFUND', - NEW.id - ); - -END IF; - -UPDATE Bank_Account_Balance -SET - balance = currentBalance -WHERE - bankAccountId = NEW.bankAccountId; - -END; - --- ------------------------------------------ --- index: 12 --- Trigger: trg_pr_payment_after_insert --- Event: INSERT --- Table: Purchase_Receipt_Payments --- ------------------------------------------ -DROP TRIGGER IF EXISTS `trg_pr_payment_after_insert`; -CREATE DEFINER=`pos`@`%` TRIGGER `trg_pr_payment_after_insert` AFTER INSERT ON `Purchase_Receipt_Payments` FOR EACH ROW BEGIN - DECLARE receiptTotal DECIMAL(14,2) Default 0; - DECLARE newPaid DECIMAL(14,2) Default 0; - DECLARE _supplierId INT; - DECLARE lastBalance DECIMAL(14,2) Default 0; - - - -- Lock receipt row -SELECT COALESCE(totalAmount, 0), COALESCE(paidAmount, 0), supplierId - INTO receiptTotal, newPaid, _supplierId - FROM Purchase_Receipts - WHERE id = NEW.receiptId - FOR UPDATE; - - -- Apply payment or refund - IF NEW.type = 'PAYMENT' THEN - SET newPaid = newPaid + NEW.amount; - ELSE - SET newPaid = newPaid - NEW.amount; - END IF; - - -- Update receipt - UPDATE Purchase_Receipts - SET - paidAmount = newPaid, - status = - CASE - WHEN newPaid = 0 THEN 'UNPAID' - WHEN newPaid < receiptTotal THEN 'PARTIALLY_PAID' - ELSE 'PAID' - END - WHERE id = NEW.receiptId; - - -- Get last supplier balance - SELECT IFNULL(balance, 0) - INTO lastBalance - FROM Supplier_Ledger - WHERE supplierId = _supplierId - ORDER BY id DESC - LIMIT 1; - - - - -- Insert supplier ledger - INSERT INTO Supplier_Ledger - ( - supplierId, - debit, - credit, - balance, - sourceType, - sourceId, - createdAt - ) - VALUES - ( - _supplierId, - IF(NEW.type = 'REFUND', NEW.amount, 0), - IF(NEW.type = 'PAYMENT', NEW.amount, 0), - lastBalance - + IF(NEW.type = 'PAYMENT', NEW.amount, 0) - - IF(NEW.type = 'REFUND', NEW.amount, 0), - 'PAYMENT', - NEW.id, - NOW() - ); -END; - --- ------------------------------------------ --- index: 13 +-- index: 8 -- Trigger: trg_pr_payment_after_delete -- Event: DELETE -- Table: Purchase_Receipt_Payments @@ -431,46 +201,7 @@ CREATE DEFINER=`pos`@`%` TRIGGER `trg_pr_payment_after_delete` AFTER DELETE ON ` END; -- ------------------------------------------ --- index: 14 --- Trigger: trg_purchase_receipt_after_insert --- Event: INSERT --- Table: Purchase_Receipts --- ------------------------------------------ -DROP TRIGGER IF EXISTS `trg_purchase_receipt_after_insert`; -CREATE DEFINER=`pos`@`%` TRIGGER `trg_purchase_receipt_after_insert` AFTER INSERT ON `Purchase_Receipts` FOR EACH ROW BEGIN - DECLARE lastBalance DECIMAL(14,2) DEFAULT 0; - - SELECT COALESCE(balance, 0) - INTO lastBalance - FROM Supplier_Ledger - WHERE supplierId = NEW.supplierId - ORDER BY id DESC - LIMIT 1; - - INSERT INTO Supplier_Ledger - ( - supplierId, - debit, - credit, - balance, - sourceType, - sourceId, - createdAt - ) - VALUES - ( - NEW.supplierId, - NEW.totalAmount, - 0, - lastBalance - NEW.totalAmount, - 'PURCHASE', - NEW.id, - NOW() - ); -END; - --- ------------------------------------------ --- index: 15 +-- index: 9 -- Trigger: trg_sales_invoice_items_before_insert -- Event: INSERT -- Table: Sales_Invoice_Items @@ -503,7 +234,7 @@ CREATE DEFINER=`pos`@`%` TRIGGER `trg_sales_invoice_items_before_insert` BEFORE end; -- ------------------------------------------ --- index: 16 +-- index: 10 -- Trigger: trg_sales_invoice_items_after_insert -- Event: INSERT -- Table: Sales_Invoice_Items @@ -576,7 +307,43 @@ DECLARE pos_id INT; END; -- ------------------------------------------ --- index: 17 +-- index: 11 +-- Trigger: trg_pos_account_payment_after_insert +-- Event: INSERT +-- Table: Sales_Invoice_Payments +-- ------------------------------------------ +DROP TRIGGER IF EXISTS `trg_pos_account_payment_after_insert`; +CREATE DEFINER=`pos`@`%` TRIGGER `trg_pos_account_payment_after_insert` AFTER INSERT ON `Sales_Invoice_Payments` FOR EACH ROW BEGIN + + DECLARE _bankAccountId INT; + + IF(NEW.paymentMethod != 'CASH') THEN + SELECT cashBankAccountId INTO _bankAccountId + FROM Pos_Accounts pa + INNER JOIN Sales_Invoices si ON pa.id = si.posAccountId + WHERE si.id = NEW.invoiceId; + End IF; + + INSERT INTO Bank_Account_Transactions ( + bankAccountId, + type, + amount, + balanceAfter, + referenceType, + referenceId + ) + VALUES( + _bankAccountId, + 'DEPOSIT', + NEW.amount, + 0, + 'POS_SALE', + NEW.id + ); +END; + +-- ------------------------------------------ +-- index: 12 -- Trigger: trg_sales_invoice_payment_after_insert -- Event: INSERT -- Table: Sales_Invoice_Payments @@ -615,43 +382,77 @@ CREATE DEFINER=`pos`@`%` TRIGGER `trg_sales_invoice_payment_after_insert` AFTER END; -- ------------------------------------------ --- index: 18 --- Trigger: trg_pos_account_payment_after_insert +-- index: 13 +-- Trigger: trg_stock_sale_insert -- Event: INSERT --- Table: Sales_Invoice_Payments +-- Table: Stock_Movements -- ------------------------------------------ -DROP TRIGGER IF EXISTS `trg_pos_account_payment_after_insert`; -CREATE DEFINER=`pos`@`%` TRIGGER `trg_pos_account_payment_after_insert` AFTER INSERT ON `Sales_Invoice_Payments` FOR EACH ROW BEGIN - - DECLARE _bankAccountId INT; - - IF(NEW.paymentMethod != 'CASH') THEN - SELECT cashBankAccountId INTO _bankAccountId - FROM Pos_Accounts pa - INNER JOIN Sales_Invoices si ON pa.id = si.posAccountId - WHERE si.id = NEW.invoiceId; - End IF; +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 + +INSERT INTO + Stock_Balance ( + productId, + quantity, + avgCost, + totalCost, + inventoryId, + updatedAt + ) +VALUES ( + NEW.productId, + NEW.quantity, + NEW.unitPrice, + NEW.totalCost, + NEW.inventoryId, + NOW() + ) +ON DUPLICATE KEY UPDATE + quantity = quantity - NEW.quantity, + totalCost = totalCost - NEW.totalCost, + avgCost = totalCost / quantity; + +END IF; - INSERT INTO Bank_Account_Transactions ( - bankAccountId, - type, - amount, - balanceAfter, - referenceType, - referenceId - ) - VALUES( - _bankAccountId, - 'DEPOSIT', - NEW.amount, - 0, - 'POS_SALE', - NEW.id - ); END; -- ------------------------------------------ --- index: 19 +-- index: 14 +-- 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, + inventoryId, + updatedAt + ) +VALUES ( + NEW.productId, + NEW.quantity, + NEW.unitPrice, + NEW.totalCost, + NEW.inventoryId, + NOW() + ) +ON DUPLICATE KEY UPDATE + quantity = quantity + NEW.quantity, + totalCost = totalCost + NEW.totalCost, + avgCost = totalCost / quantity; + +END IF; + +END; + +-- ------------------------------------------ +-- index: 15 -- Trigger: trg_stock_transfer -- Event: INSERT -- Table: Stock_Movements @@ -733,73 +534,3 @@ END IF; END; --- ------------------------------------------ --- index: 20 --- 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, - inventoryId, - updatedAt - ) -VALUES ( - NEW.productId, - NEW.quantity, - NEW.unitPrice, - NEW.totalCost, - NEW.inventoryId, - NOW() - ) -ON DUPLICATE KEY UPDATE - quantity = quantity + NEW.quantity, - totalCost = totalCost + NEW.totalCost, - avgCost = totalCost / quantity; - -END IF; - -END; - --- ------------------------------------------ --- index: 21 --- 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 - -INSERT INTO - Stock_Balance ( - productId, - quantity, - avgCost, - totalCost, - inventoryId, - updatedAt - ) -VALUES ( - NEW.productId, - NEW.quantity, - NEW.unitPrice, - NEW.totalCost, - NEW.inventoryId, - NOW() - ) -ON DUPLICATE KEY UPDATE - quantity = quantity - NEW.quantity, - totalCost = totalCost - NEW.totalCost, - avgCost = totalCost / quantity; - -END IF; - -END; - diff --git a/prisma/triggers/stored_procedures.sql b/prisma/triggers/stored_procedures.sql index 18b34e8..c284da1 100644 --- a/prisma/triggers/stored_procedures.sql +++ b/prisma/triggers/stored_procedures.sql @@ -1,26 +1,31 @@ -- Stored Procedures equivalent to triggers -DELIMITER // +DELIMITER / / -- Procedure for trg_bank_account_transaction_after_insert CREATE PROCEDURE update_bank_balance(IN p_bankAccountId INT, IN p_type VARCHAR(20), IN p_amount DECIMAL(15,2)) BEGIN + START TRANSACTION; IF p_type = 'DEPOSIT' THEN UPDATE Bank_Account_Balance SET balance = balance + p_amount WHERE bankAccountId = p_bankAccountId; ELSEIF p_type = 'WITHDRAWAL' THEN UPDATE Bank_Account_Balance SET balance = balance - p_amount WHERE bankAccountId = p_bankAccountId; END IF; + COMMIT; END // -- Procedure for trg_bank_account_transaction_after_delete CREATE PROCEDURE update_bank_balance_on_delete(IN p_bankAccountId INT, IN p_amount DECIMAL(15,2)) BEGIN + START TRANSACTION; UPDATE Bank_Accounts SET balance = balance - p_amount WHERE id = p_bankAccountId; + COMMIT; END // -- Procedure for trg_transfer_item_after_insert CREATE PROCEDURE process_transfer_item(IN p_transferId INT, IN p_productId INT, IN p_count DECIMAL(10,2)) BEGIN + START TRANSACTION; DECLARE fromInv INT; DECLARE toInv INT; DECLARE _avgCost DECIMAL(10,2); @@ -47,42 +52,52 @@ BEGIN (type, quantity, unitPrice, totalCost, avgCost, referenceType, referenceId, productId, inventoryId, counterInventoryId, createdAt, remainedInStock) VALUES ('IN', p_count, _avgCost, _avgCost*p_count, _avgCost, 'INVENTORY_TRANSFER', p_transferId, p_productId, toInv, fromInv, NOW(), latestQuantityInOrigin-p_count); + COMMIT; END // -- Procedure for trg_order_item_after_insert CREATE PROCEDURE update_stock_reservation_insert(IN p_orderId INT, IN p_productId INT, IN p_quantity DECIMAL(10,2)) BEGIN + START TRANSACTION; UPDATE Stock_Reservations SET quantity = quantity + p_quantity WHERE orderId = p_orderId AND productId = p_productId; + COMMIT; END // -- Procedure for trg_order_item_after_update CREATE PROCEDURE update_stock_reservation_update(IN p_orderId INT, IN p_productId INT, IN p_old_quantity DECIMAL(10,2), IN p_new_quantity DECIMAL(10,2)) BEGIN + START TRANSACTION; UPDATE Stock_Reservations SET quantity = quantity - p_old_quantity + p_new_quantity WHERE orderId = p_orderId AND productId = p_productId; + COMMIT; END // -- Procedure for trg_order_item_after_delete CREATE PROCEDURE update_stock_reservation_delete(IN p_orderId INT, IN p_productId INT, IN p_quantity DECIMAL(10,2)) BEGIN + START TRANSACTION; UPDATE Stock_Reservations SET quantity = quantity - p_quantity WHERE orderId = p_orderId AND productId = p_productId; + COMMIT; END // -- Procedure for trg_order_after_cancel CREATE PROCEDURE cancel_order_stock(IN p_orderId INT, IN p_status VARCHAR(20)) BEGIN + START TRANSACTION; IF p_status = 'CANCELED' OR p_status = 'REJECTED' OR p_status = 'DONE' THEN UPDATE Stock_Reservations sr SET quantity = 0 WHERE sr.orderId = p_orderId; END IF; + COMMIT; END // -- Procedure for trg_purchase_receipt_item_after_insert CREATE PROCEDURE process_purchase_item(IN p_receiptId INT, IN p_productId INT, IN p_count DECIMAL(10,2), IN p_unitPrice DECIMAL(15,2), IN p_totalAmount DECIMAL(15,2)) BEGIN + START TRANSACTION; DECLARE latestQuantity DECIMAL(10, 2) DEFAULT 0; DECLARE invId INT; DECLARE suppId INT; @@ -133,11 +148,13 @@ BEGIN latestQuantity + p_count, NOW() ); + COMMIT; END // -- Procedure for trg_pr_payment_before_insert CREATE PROCEDURE validate_payment_before_insert(IN p_receiptId INT, IN p_type VARCHAR(20), IN p_amount DECIMAL(15,2)) BEGIN + START TRANSACTION; DECLARE receiptTotal DECIMAL(14,2); DECLARE paid DECIMAL(14,2); @@ -151,11 +168,13 @@ BEGIN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'مجموع مبلغ پرداختی بیشتر از مبلغ فاکتور است.'; END IF; + COMMIT; END // -- Procedure for trg_purchase_payment_update_receipt CREATE PROCEDURE update_receipt_payment(IN p_receiptId INT) BEGIN + START TRANSACTION; DECLARE paid DECIMAL(15,2); DECLARE total DECIMAL(15,2); @@ -180,11 +199,13 @@ BEGIN ELSE 'PAID' END WHERE id = p_receiptId; + COMMIT; END // -- Procedure for trg_purchase_payment_after_insert CREATE PROCEDURE process_purchase_payment(IN p_bankAccountId INT, IN p_type VARCHAR(20), IN p_amount DECIMAL(15,2), IN p_id INT) BEGIN + START TRANSACTION; DECLARE currentBalance DECIMAL(15, 2); SELECT balance INTO currentBalance @@ -214,7 +235,7 @@ BEGIN 'PURCHASE_PAYMENT', p_id ); - ELSE + ELSE SET currentBalance = currentBalance + p_amount; INSERT INTO Bank_Account_Transactions ( bankAccountId, @@ -237,11 +258,13 @@ BEGIN UPDATE Bank_Account_Balance SET balance = currentBalance WHERE bankAccountId = p_bankAccountId; + COMMIT; END // -- Procedure for trg_pr_payment_after_insert CREATE PROCEDURE update_supplier_ledger(IN p_receiptId INT, IN p_type VARCHAR(20), IN p_amount DECIMAL(15,2), IN p_id INT) BEGIN + START TRANSACTION; DECLARE receiptTotal DECIMAL(14,2) DEFAULT 0; DECLARE newPaid DECIMAL(14,2) DEFAULT 0; DECLARE _supplierId INT; @@ -304,6 +327,7 @@ BEGIN p_id, NOW() ); + COMMIT; END // -- Procedure for trg_pr_payment_after_delete @@ -486,7 +510,7 @@ END // CREATE PROCEDURE process_pos_payment(IN p_invoiceId INT, IN p_paymentMethod VARCHAR(20), IN p_amount DECIMAL(15,2), IN p_id INT) BEGIN DECLARE _bankAccountId INT; - + IF(p_paymentMethod != 'CASH') THEN SELECT cashBankAccountId INTO _bankAccountId FROM Pos_Accounts pa @@ -545,7 +569,7 @@ BEGIN updatedAt = NOW(); END IF; - IF p_type = 'OUT' THEN + IF p_type = 'OUT' THEN IF EXISTS ( SELECT 1 FROM Stock_Balance sb @@ -630,4 +654,4 @@ BEGIN avgCost = totalCost / quantity; END // -DELIMITER ; \ No newline at end of file +DELIMITER; diff --git a/src/app.module.ts b/src/app.module.ts index ef95f5b..d8cad37 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -11,7 +11,7 @@ import { BanksModule } from './modules/banks/banks.module' import { CardexModule } from './modules/cardex/cardex.module' import { InventoriesModule } from './modules/inventories/inventories.module' import { PosModule } from './modules/pos/pos.module' -import { PurchaseReceiptPaymentsModule } from './modules/purchase-receipt-payments/purchase-receipt-payments.module' +import { PurchaseReceiptsModule } from './modules/purchase-receipts/purchase-receipts.module' import { StatisticsModule } from './modules/statistics/statistics.module' import { SuppliersModule } from './modules/suppliers/suppliers.module' import { PrismaModule } from './prisma/prisma.module' @@ -19,8 +19,6 @@ import { ProductBrandsModule } from './product-brands/product-brands.module' import { ProductCategoriesModule } from './product-categories/product-categories.module' import { ProductVariantsModule } from './product-variants/product-variants.module' import { ProductsModule } from './products/products.module' -import { PurchaseReceiptItemsModule } from './purchase-receipt-items/purchase-receipt-items.module' -import { PurchaseReceiptsModule } from './purchase-receipts/purchase-receipts.module' import { RolesModule } from './roles/roles.module' import { SalesInvoiceItemsModule } from './sales-invoice-items/sales-invoice-items.module' import { SalesInvoicesModule } from './sales-invoices/sales-invoices.module' @@ -43,8 +41,6 @@ import { UsersModule } from './users/users.module' CustomersModule, InventoriesModule, PurchaseReceiptsModule, - PurchaseReceiptItemsModule, - PurchaseReceiptPaymentsModule, SalesInvoicesModule, SalesInvoiceItemsModule, InventoryTransfersModule, diff --git a/src/common/database/transaction.helper.ts b/src/common/database/transaction.helper.ts new file mode 100644 index 0000000..1eafd4d --- /dev/null +++ b/src/common/database/transaction.helper.ts @@ -0,0 +1,11 @@ +// src/common/database/transaction.helper.ts +import { PrismaService } from '../../prisma/prisma.service' + +export async function withTransaction( + prisma: PrismaService, + fn: (tx: PrismaService) => Promise, +): Promise { + return prisma.$transaction(async tx => { + return fn(tx as PrismaService) + }) +} diff --git a/src/modules/bank-accounts/bank-accounts.module.ts b/src/modules/bank-accounts/bank-accounts.module.ts index be6d59e..3ce5f18 100644 --- a/src/modules/bank-accounts/bank-accounts.module.ts +++ b/src/modules/bank-accounts/bank-accounts.module.ts @@ -2,10 +2,12 @@ import { Module } from '@nestjs/common' import { PrismaModule } from '../../prisma/prisma.module' import { BankAccountsController } from './bank-accounts.controller' import { BankAccountsService } from './bank-accounts.service' +import { BankAccountsWorkflow } from './bank-accounts.workflow' @Module({ imports: [PrismaModule], controllers: [BankAccountsController], - providers: [BankAccountsService], + providers: [BankAccountsService, BankAccountsWorkflow], + exports: [BankAccountsWorkflow], }) export class BankAccountsModule {} diff --git a/src/modules/bank-accounts/bank-accounts.service.ts b/src/modules/bank-accounts/bank-accounts.service.ts index 46e0fe6..4c60dff 100644 --- a/src/modules/bank-accounts/bank-accounts.service.ts +++ b/src/modules/bank-accounts/bank-accounts.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@nestjs/common' +import { withTransaction } from '../../common/database/transaction.helper' import { ResponseMapper } from '../../common/response/response-mapper' import { PrismaService } from '../../prisma/prisma.service' @@ -6,8 +7,16 @@ import { PrismaService } from '../../prisma/prisma.service' export class BankAccountsService { constructor(private prisma: PrismaService) {} async create(data: any) { - const item = await this.prisma.bankAccount.create({ data }) - return ResponseMapper.create(item) + return withTransaction(this.prisma, async tx => { + const item = await tx.bankAccount.create({ data }) + await tx.bankAccountBalance.create({ + data: { + bankAccountId: item.id, + balance: 0, + }, + }) + return ResponseMapper.create(item) + }) } async findAll() { diff --git a/src/modules/bank-accounts/bank-accounts.workflow.ts b/src/modules/bank-accounts/bank-accounts.workflow.ts new file mode 100644 index 0000000..0cd29be --- /dev/null +++ b/src/modules/bank-accounts/bank-accounts.workflow.ts @@ -0,0 +1,65 @@ +import { Injectable } from '@nestjs/common' +import { Prisma } from '../../generated/prisma/client' +import { AddTransactionToBankAccountDto } from './dto/add-transaction.dto' + +@Injectable() +export class BankAccountsWorkflow { + async addTransaction( + tx: Prisma.TransactionClient, + payload: AddTransactionToBankAccountDto, + ) { + const item = await tx.bankAccountBalance.findUnique({ + where: { + bankAccountId: payload.bankAccountId, + }, + }) + + const balance = item ? Number(item.balance) : 0 + + const newBalance = item + ? payload.type === 'DEPOSIT' + ? balance + payload.amount + : balance - payload.amount + : payload.type === 'DEPOSIT' + ? payload.amount + : -payload.amount + + await tx.bankAccountTransaction.create({ + data: { + bankAccount: { connect: { id: payload.bankAccountId } }, + amount: payload.amount, + type: payload.type, + balanceAfter: newBalance, + + referenceId: payload.referenceId, + referenceType: payload.referenceType, + }, + }) + + console.log('first') + + const bankAccountBalanceItem = await tx.bankAccountBalance.findUnique({ + where: { + bankAccountId: payload.bankAccountId, + }, + }) + + if (!bankAccountBalanceItem) { + return await tx.bankAccountBalance.create({ + data: { + bankAccount: { connect: { id: payload.bankAccountId } }, + balance: newBalance, + }, + }) + } + + return await tx.bankAccountBalance.update({ + where: { + bankAccountId: payload.bankAccountId, + }, + data: { + balance: newBalance, + }, + }) + } +} diff --git a/src/modules/bank-accounts/dto/add-transaction.dto.ts b/src/modules/bank-accounts/dto/add-transaction.dto.ts new file mode 100644 index 0000000..af7d314 --- /dev/null +++ b/src/modules/bank-accounts/dto/add-transaction.dto.ts @@ -0,0 +1,22 @@ +import { IsEnum, IsInt } from 'class-validator' +import { + BankAccountTransactionType, + BankTransactionRefType, +} from '../../../generated/prisma/enums' + +export class AddTransactionToBankAccountDto { + @IsInt() + bankAccountId: number + + @IsInt() + amount: number + + @IsInt() + referenceId: number + + @IsEnum(BankTransactionRefType) + referenceType: BankTransactionRefType + + @IsEnum(BankAccountTransactionType) + type: BankAccountTransactionType +} diff --git a/src/modules/purchase-receipt-payments/purchase-receipt-payments.module.ts b/src/modules/purchase-receipt-payments/purchase-receipt-payments.module.ts deleted file mode 100644 index d03ad38..0000000 --- a/src/modules/purchase-receipt-payments/purchase-receipt-payments.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Module } from '@nestjs/common' - -import { PrismaModule } from '../../prisma/prisma.module' -import { PurchaseReceiptPaymentsController } from './purchase-receipt-payments.controller' -import { PurchaseReceiptPaymentsService } from './purchase-receipt-payments.service' - -@Module({ - imports: [PrismaModule], - controllers: [PurchaseReceiptPaymentsController], - providers: [PurchaseReceiptPaymentsService], -}) -export class PurchaseReceiptPaymentsModule {} diff --git a/src/purchase-receipts/dto/create-purchase-receipt.dto.ts b/src/modules/purchase-receipts/index/dto/create-purchase-receipt.dto.ts similarity index 100% rename from src/purchase-receipts/dto/create-purchase-receipt.dto.ts rename to src/modules/purchase-receipts/index/dto/create-purchase-receipt.dto.ts diff --git a/src/purchase-receipts/dto/update-purchase-receipt.dto.ts b/src/modules/purchase-receipts/index/dto/update-purchase-receipt.dto.ts similarity index 100% rename from src/purchase-receipts/dto/update-purchase-receipt.dto.ts rename to src/modules/purchase-receipts/index/dto/update-purchase-receipt.dto.ts diff --git a/src/purchase-receipts/purchase-receipts.controller.ts b/src/modules/purchase-receipts/index/purchase-receipts.controller.ts similarity index 100% rename from src/purchase-receipts/purchase-receipts.controller.ts rename to src/modules/purchase-receipts/index/purchase-receipts.controller.ts diff --git a/src/purchase-receipts/purchase-receipts.service.ts b/src/modules/purchase-receipts/index/purchase-receipts.service.ts similarity index 74% rename from src/purchase-receipts/purchase-receipts.service.ts rename to src/modules/purchase-receipts/index/purchase-receipts.service.ts index bfd481f..7644151 100644 --- a/src/purchase-receipts/purchase-receipts.service.ts +++ b/src/modules/purchase-receipts/index/purchase-receipts.service.ts @@ -1,12 +1,17 @@ import { Injectable } from '@nestjs/common' -import { ResponseMapper } from '../common/response/response-mapper' -import { Prisma } from '../generated/prisma/client' -import { PrismaService } from '../prisma/prisma.service' +import { withTransaction } from '../../../common/database/transaction.helper' +import { ResponseMapper } from '../../../common/response/response-mapper' +import { Prisma } from '../../../generated/prisma/client' +import { PrismaService } from '../../../prisma/prisma.service' import { CreatePurchaseReceiptDto } from './dto/create-purchase-receipt.dto' +import { PurchaseReceiptWorkflow } from './purchase-receipts.workflow' @Injectable() export class PurchaseReceiptsService { - constructor(private prisma: PrismaService) {} + constructor( + private prisma: PrismaService, + private purchaseReceiptWorkflow: PurchaseReceiptWorkflow, + ) {} async create(dto: CreatePurchaseReceiptDto) { const data: Prisma.PurchaseReceiptCreateInput = { @@ -31,15 +36,24 @@ export class PurchaseReceiptsService { } : undefined, } - const item = await this.prisma.purchaseReceipt.create({ - data, - include: { items: true }, - omit: { - supplierId: true, - inventoryId: true, - }, + + return withTransaction(this.prisma, async tx => { + const item = await tx.purchaseReceipt.create({ + data, + include: { items: true }, + omit: { + supplierId: true, + inventoryId: true, + }, + }) + await this.purchaseReceiptWorkflow.onCreatePurchaseReceipt( + tx, + dto.supplierId, + dto.totalAmount, + item.id, + ) + return ResponseMapper.create(item) }) - return ResponseMapper.create(item) } async findAll() { diff --git a/src/modules/purchase-receipts/index/purchase-receipts.workflow.ts b/src/modules/purchase-receipts/index/purchase-receipts.workflow.ts new file mode 100644 index 0000000..b5780de --- /dev/null +++ b/src/modules/purchase-receipts/index/purchase-receipts.workflow.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@nestjs/common' +import { Prisma } from '../../../generated/prisma/client' +import { SupplierLedgerWorkflow } from '../../suppliers/ledger/supplier-ledger.workflow' + +@Injectable() +export class PurchaseReceiptWorkflow { + constructor(private supplierLedgerWorkflow: SupplierLedgerWorkflow) {} + + async onCreatePurchaseReceipt( + tx: Prisma.TransactionClient, + supplierId: number, + amount: number, + sourceId: number, + ) { + await this.supplierLedgerWorkflow.updateLedgerBalance( + tx, + supplierId, + amount, + sourceId, + 'PURCHASE', + ) + } +} diff --git a/src/purchase-receipt-items/dto/create-purchase-receipt-item.dto.ts b/src/modules/purchase-receipts/purchase-receipt-items/dto/create-purchase-receipt-item.dto.ts similarity index 100% rename from src/purchase-receipt-items/dto/create-purchase-receipt-item.dto.ts rename to src/modules/purchase-receipts/purchase-receipt-items/dto/create-purchase-receipt-item.dto.ts diff --git a/src/purchase-receipt-items/dto/update-purchase-receipt-item.dto.ts b/src/modules/purchase-receipts/purchase-receipt-items/dto/update-purchase-receipt-item.dto.ts similarity index 100% rename from src/purchase-receipt-items/dto/update-purchase-receipt-item.dto.ts rename to src/modules/purchase-receipts/purchase-receipt-items/dto/update-purchase-receipt-item.dto.ts diff --git a/src/purchase-receipt-items/purchase-receipt-items.controller.ts b/src/modules/purchase-receipts/purchase-receipt-items/purchase-receipt-items.controller.ts similarity index 100% rename from src/purchase-receipt-items/purchase-receipt-items.controller.ts rename to src/modules/purchase-receipts/purchase-receipt-items/purchase-receipt-items.controller.ts diff --git a/src/purchase-receipt-items/purchase-receipt-items.module.ts b/src/modules/purchase-receipts/purchase-receipt-items/purchase-receipt-items.module.ts similarity index 86% rename from src/purchase-receipt-items/purchase-receipt-items.module.ts rename to src/modules/purchase-receipts/purchase-receipt-items/purchase-receipt-items.module.ts index 82e05e8..83cd162 100644 --- a/src/purchase-receipt-items/purchase-receipt-items.module.ts +++ b/src/modules/purchase-receipts/purchase-receipt-items/purchase-receipt-items.module.ts @@ -1,5 +1,5 @@ import { Module } from '@nestjs/common' -import { PrismaModule } from '../prisma/prisma.module' +import { PrismaModule } from '../../../prisma/prisma.module' import { PurchaseReceiptItemsController } from './purchase-receipt-items.controller' import { PurchaseReceiptItemsService } from './purchase-receipt-items.service' diff --git a/src/purchase-receipt-items/purchase-receipt-items.service.ts b/src/modules/purchase-receipts/purchase-receipt-items/purchase-receipt-items.service.ts similarity index 95% rename from src/purchase-receipt-items/purchase-receipt-items.service.ts rename to src/modules/purchase-receipts/purchase-receipt-items/purchase-receipt-items.service.ts index cbdf78f..1e383a1 100644 --- a/src/purchase-receipt-items/purchase-receipt-items.service.ts +++ b/src/modules/purchase-receipts/purchase-receipt-items/purchase-receipt-items.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@nestjs/common' -import { ResponseMapper } from '../common/response/response-mapper' -import { PrismaService } from '../prisma/prisma.service' +import { ResponseMapper } from '../../../common/response/response-mapper' +import { PrismaService } from '../../../prisma/prisma.service' import { CreatePurchaseReceiptItemDto } from './dto/create-purchase-receipt-item.dto' @Injectable() diff --git a/src/modules/purchase-receipt-payments/dto/create-purchase-receipt-payment.dto.ts b/src/modules/purchase-receipts/purchase-receipt-payments/dto/create-purchase-receipt-payment.dto.ts similarity index 85% rename from src/modules/purchase-receipt-payments/dto/create-purchase-receipt-payment.dto.ts rename to src/modules/purchase-receipts/purchase-receipt-payments/dto/create-purchase-receipt-payment.dto.ts index 5c4a737..093fde9 100644 --- a/src/modules/purchase-receipt-payments/dto/create-purchase-receipt-payment.dto.ts +++ b/src/modules/purchase-receipts/purchase-receipt-payments/dto/create-purchase-receipt-payment.dto.ts @@ -1,5 +1,5 @@ import { IsEnum, IsInt, IsNumber, IsOptional, IsString } from 'class-validator' -import { PaymentMethodType, PaymentType } from '../../../generated/prisma/enums' +import { PaymentMethodType, PaymentType } from '../../../../generated/prisma/enums' export class CreatePurchaseReceiptPaymentDto { @IsNumber() diff --git a/src/modules/purchase-receipt-payments/dto/update-purchase-receipt-payment.dto.ts b/src/modules/purchase-receipts/purchase-receipt-payments/dto/update-purchase-receipt-payment.dto.ts similarity index 100% rename from src/modules/purchase-receipt-payments/dto/update-purchase-receipt-payment.dto.ts rename to src/modules/purchase-receipts/purchase-receipt-payments/dto/update-purchase-receipt-payment.dto.ts diff --git a/src/modules/purchase-receipt-payments/purchase-receipt-payments.controller.ts b/src/modules/purchase-receipts/purchase-receipt-payments/purchase-receipt-payments.controller.ts similarity index 100% rename from src/modules/purchase-receipt-payments/purchase-receipt-payments.controller.ts rename to src/modules/purchase-receipts/purchase-receipt-payments/purchase-receipt-payments.controller.ts diff --git a/src/modules/purchase-receipts/purchase-receipt-payments/purchase-receipt-payments.module.ts b/src/modules/purchase-receipts/purchase-receipt-payments/purchase-receipt-payments.module.ts new file mode 100644 index 0000000..cc5d2d8 --- /dev/null +++ b/src/modules/purchase-receipts/purchase-receipt-payments/purchase-receipt-payments.module.ts @@ -0,0 +1,15 @@ +import { Module } from '@nestjs/common' + +import { PrismaModule } from '../../../prisma/prisma.module' +import { BankAccountsModule } from '../../bank-accounts/bank-accounts.module' +import { PurchaseReceiptPaymentsController } from './purchase-receipt-payments.controller' +import { PurchaseReceiptPaymentsService } from './purchase-receipt-payments.service' +import { PurchaseReceiptPaymentsWorkflow } from './purchase-receipt-payments.workflow' + +@Module({ + imports: [PrismaModule, BankAccountsModule], + controllers: [PurchaseReceiptPaymentsController], + providers: [PurchaseReceiptPaymentsService, PurchaseReceiptPaymentsWorkflow], + exports: [PurchaseReceiptPaymentsWorkflow], +}) +export class PurchaseReceiptPaymentsModule {} diff --git a/src/modules/purchase-receipt-payments/purchase-receipt-payments.service.ts b/src/modules/purchase-receipts/purchase-receipt-payments/purchase-receipt-payments.service.ts similarity index 60% rename from src/modules/purchase-receipt-payments/purchase-receipt-payments.service.ts rename to src/modules/purchase-receipts/purchase-receipt-payments/purchase-receipt-payments.service.ts index f0a52e5..b1f713b 100644 --- a/src/modules/purchase-receipt-payments/purchase-receipt-payments.service.ts +++ b/src/modules/purchase-receipts/purchase-receipt-payments/purchase-receipt-payments.service.ts @@ -1,14 +1,29 @@ import { Injectable } from '@nestjs/common' -import { ResponseMapper } from '../../common/response/response-mapper' -import { PrismaService } from '../../prisma/prisma.service' +import { withTransaction } from '../../../common/database/transaction.helper' +import { ResponseMapper } from '../../../common/response/response-mapper' +import { PrismaService } from '../../../prisma/prisma.service' +import { CreatePurchaseReceiptPaymentDto } from './dto/create-purchase-receipt-payment.dto' +import { PurchaseReceiptPaymentsWorkflow } from './purchase-receipt-payments.workflow' @Injectable() export class PurchaseReceiptPaymentsService { - constructor(private prisma: PrismaService) {} + constructor( + private prisma: PrismaService, + private purchaseReceiptPaymentsWorkflow: PurchaseReceiptPaymentsWorkflow, + ) {} - async create(data: any) { - const item = await this.prisma.purchaseReceiptPayments.create({ data }) - return ResponseMapper.create(item) + async create(data: CreatePurchaseReceiptPaymentDto) { + return withTransaction(this.prisma, async tx => { + const item = await tx.purchaseReceiptPayments.create({ data }) + await this.purchaseReceiptPaymentsWorkflow.onAddPayment( + tx, + data.bankAccountId, + data.receiptId, + data.amount, + data.type, + ) + return ResponseMapper.create(item) + }) } async findAll() { diff --git a/src/modules/purchase-receipts/purchase-receipt-payments/purchase-receipt-payments.workflow.ts b/src/modules/purchase-receipts/purchase-receipt-payments/purchase-receipt-payments.workflow.ts new file mode 100644 index 0000000..0de3175 --- /dev/null +++ b/src/modules/purchase-receipts/purchase-receipt-payments/purchase-receipt-payments.workflow.ts @@ -0,0 +1,58 @@ +import { Injectable } from '@nestjs/common' +import { Prisma } from '../../../generated/prisma/client' +import { PaymentType } from '../../../generated/prisma/enums' +import { BankAccountsWorkflow } from '../../bank-accounts/bank-accounts.workflow' + +@Injectable() +export class PurchaseReceiptPaymentsWorkflow { + constructor(private bankAccountsWorkflow: BankAccountsWorkflow) {} + + async onAddPayment( + tx: Prisma.TransactionClient, + bankAccountId: number, + receiptId: number, + amount: number, + type: PaymentType, + ) { + const { paidAmount, totalAmount } = await tx.purchaseReceipt.findUniqueOrThrow({ + where: { id: receiptId }, + }) + + if (type === 'PAYMENT' && Number(paidAmount) + Number(amount) > Number(totalAmount)) { + throw new Error('مجموع مبلغ پرداختی بیشتر از مبلغ فاکتور است.') + } + + if (type === 'REFUND' && Number(paidAmount) - Number(amount) < 0) { + throw new Error( + 'مجموع مبلغ بازپرداختی بیشتر از مبلغ پرداخت‌ شده در این فاکتور است.', + ) + } + + await this.bankAccountsWorkflow.addTransaction(tx, { + bankAccountId: bankAccountId, + amount: amount, + type: type === 'PAYMENT' ? 'WITHDRAWAL' : 'DEPOSIT', + referenceId: receiptId, + referenceType: type === 'PAYMENT' ? 'PURCHASE_PAYMENT' : 'PURCHASE_REFUND', + }) + + const newPaidAmount = + type === 'PAYMENT' + ? Number(paidAmount) + Number(amount) + : Number(paidAmount) - Number(amount) + const newStatus = + newPaidAmount === 0 + ? 'UNPAID' + : newPaidAmount >= Number(totalAmount) + ? 'PAID' + : 'PARTIALLY_PAID' + + await tx.purchaseReceipt.update({ + where: { id: receiptId }, + data: { + paidAmount: newPaidAmount, + status: newStatus, + }, + }) + } +} diff --git a/src/modules/purchase-receipts/purchase-receipts.module.ts b/src/modules/purchase-receipts/purchase-receipts.module.ts new file mode 100644 index 0000000..96f3068 --- /dev/null +++ b/src/modules/purchase-receipts/purchase-receipts.module.ts @@ -0,0 +1,21 @@ +import { Module } from '@nestjs/common' +import { PrismaModule } from '../../prisma/prisma.module' +import { SupplierLedgerModule } from '../suppliers/ledger/supplier-ledger.module' +import { PurchaseReceiptsController } from './index/purchase-receipts.controller' +import { PurchaseReceiptsService } from './index/purchase-receipts.service' +import { PurchaseReceiptWorkflow } from './index/purchase-receipts.workflow' +import { PurchaseReceiptItemsModule } from './purchase-receipt-items/purchase-receipt-items.module' +import { PurchaseReceiptPaymentsModule } from './purchase-receipt-payments/purchase-receipt-payments.module' + +@Module({ + imports: [ + PrismaModule, + PurchaseReceiptItemsModule, + PurchaseReceiptPaymentsModule, + SupplierLedgerModule, + ], + controllers: [PurchaseReceiptsController], + providers: [PurchaseReceiptsService, PurchaseReceiptWorkflow], + exports: [PurchaseReceiptWorkflow], +}) +export class PurchaseReceiptsModule {} diff --git a/src/modules/suppliers/index/suppliers.controller.ts b/src/modules/suppliers/index/suppliers.controller.ts index 81fc9e8..9ea9ac6 100644 --- a/src/modules/suppliers/index/suppliers.controller.ts +++ b/src/modules/suppliers/index/suppliers.controller.ts @@ -22,11 +22,6 @@ export class SuppliersController { return this.suppliersService.findOne(Number(supplierId)) } - @Get(':supplierId/ledger') - getLedger(@Param('supplierId') supplierId: string) { - return this.suppliersService.getLedger(Number(supplierId)) - } - @Patch(':id') update(@Param('id') id: string, @Body() dto: UpdateSupplierDto) { return this.suppliersService.update(Number(id), dto) diff --git a/src/modules/suppliers/index/suppliers.service.ts b/src/modules/suppliers/index/suppliers.service.ts index 2a29cf0..b638246 100644 --- a/src/modules/suppliers/index/suppliers.service.ts +++ b/src/modules/suppliers/index/suppliers.service.ts @@ -37,21 +37,6 @@ export class SuppliersService { }) } - async getLedger(supplierId: number) { - const items = await this.prisma.supplierLedger.findMany({ - where: { - supplierId, - }, - omit: { - supplierId: true, - }, - orderBy: { - createdAt: 'desc', - }, - }) - return ResponseMapper.list(items) - } - async update(id: number, data: any) { const item = await this.prisma.supplier.update({ where: { id }, data }) return ResponseMapper.update(item) diff --git a/src/modules/suppliers/invoices/invoices.controller.ts b/src/modules/suppliers/invoices/invoices.controller.ts index 77d988f..da49ecf 100644 --- a/src/modules/suppliers/invoices/invoices.controller.ts +++ b/src/modules/suppliers/invoices/invoices.controller.ts @@ -21,10 +21,15 @@ export class SupplierInvoicesController { @Post(':invoiceId/pay') createPayment( + @Param('supplierId') supplierId: string, @Param('invoiceId') invoiceId: string, @Body() data: CreateReceiptPaymentDto, ) { - return this.supplierInvoicesService.createPayment(Number(invoiceId), data) + return this.supplierInvoicesService.createPayment( + Number(supplierId), + Number(invoiceId), + data, + ) } @Get(':invoiceId/payments') diff --git a/src/modules/suppliers/invoices/invoices.module.ts b/src/modules/suppliers/invoices/invoices.module.ts index b14d095..71a4fd1 100644 --- a/src/modules/suppliers/invoices/invoices.module.ts +++ b/src/modules/suppliers/invoices/invoices.module.ts @@ -1,11 +1,14 @@ import { Module } from '@nestjs/common' import { PrismaModule } from '../../../prisma/prisma.module' +import { PurchaseReceiptPaymentsModule } from '../../purchase-receipts/purchase-receipt-payments/purchase-receipt-payments.module' +import { SupplierLedgerModule } from '../ledger/supplier-ledger.module' import { SupplierInvoicesController } from './invoices.controller' import { SupplierInvoicesService } from './invoices.service' +import { SupplierInvoicesWorkflow } from './invoices.workflow' @Module({ - imports: [PrismaModule], + imports: [PrismaModule, PurchaseReceiptPaymentsModule, SupplierLedgerModule], controllers: [SupplierInvoicesController], - providers: [SupplierInvoicesService], + providers: [SupplierInvoicesService, SupplierInvoicesWorkflow], }) export class SupplierInvoicesModule {} diff --git a/src/modules/suppliers/invoices/invoices.service.ts b/src/modules/suppliers/invoices/invoices.service.ts index 3d57cc3..88750c7 100644 --- a/src/modules/suppliers/invoices/invoices.service.ts +++ b/src/modules/suppliers/invoices/invoices.service.ts @@ -1,11 +1,16 @@ import { Injectable } from '@nestjs/common' +import { withTransaction } from '../../../common/database/transaction.helper' import { ResponseMapper } from '../../../common/response/response-mapper' import { PrismaService } from '../../../prisma/prisma.service' import { CreateReceiptPaymentDto } from './dto/create-receipt-payment.dto' +import { SupplierInvoicesWorkflow } from './invoices.workflow' @Injectable() export class SupplierInvoicesService { - constructor(private prisma: PrismaService) {} + constructor( + private prisma: PrismaService, + private supplierInvoicesWorkflow: SupplierInvoicesWorkflow, + ) {} async findAll(supplierId: number) { const items = await this.prisma.purchaseReceipt.findMany({ @@ -147,32 +152,45 @@ export class SupplierInvoicesService { return ResponseMapper.list(items) } - async createPayment(invoiceId: number, data: CreateReceiptPaymentDto) { + async createPayment( + supplierId: number, + invoiceId: number, + data: CreateReceiptPaymentDto, + ) { const { bankAccountId, ...rest } = data - console.log(data) - const payment = await this.prisma.purchaseReceiptPayments.create({ - data: { - ...rest, - payedAt: new Date(data.payedAt), - receipt: { - connect: { - id: invoiceId, + return withTransaction(this.prisma, async tx => { + await this.supplierInvoicesWorkflow.onPaymentCreated( + tx, + supplierId, + data.amount, + invoiceId, + bankAccountId, + ) + + const payment = await tx.purchaseReceiptPayments.create({ + data: { + ...rest, + payedAt: new Date(data.payedAt), + receipt: { + connect: { + id: invoiceId, + }, + }, + bankAccount: { + connect: { + id: bankAccountId, + }, }, }, - bankAccount: { - connect: { - id: bankAccountId, - }, + include: { + receipt: true, }, - }, - include: { - receipt: true, - }, - omit: { - receiptId: true, - }, + omit: { + receiptId: true, + }, + }) + return ResponseMapper.create(payment) }) - return ResponseMapper.create(payment) } } diff --git a/src/modules/suppliers/invoices/invoices.workflow.ts b/src/modules/suppliers/invoices/invoices.workflow.ts new file mode 100644 index 0000000..2985314 --- /dev/null +++ b/src/modules/suppliers/invoices/invoices.workflow.ts @@ -0,0 +1,36 @@ +import { Injectable } from '@nestjs/common' +import { Prisma } from '../../../generated/prisma/client' +import { PurchaseReceiptPaymentsWorkflow } from '../../purchase-receipts/purchase-receipt-payments/purchase-receipt-payments.workflow' +import { SupplierLedgerWorkflow } from '../ledger/supplier-ledger.workflow' + +@Injectable() +export class SupplierInvoicesWorkflow { + constructor( + private supplierLedgerWorkflow: SupplierLedgerWorkflow, + private purchaseReceiptPaymentWorkflow: PurchaseReceiptPaymentsWorkflow, + ) {} + + async onPaymentCreated( + tx: Prisma.TransactionClient, + supplierId: number, + amount: number, + invoiceId: number, + bankAccountId: number, + ) { + await this.supplierLedgerWorkflow.updateLedgerBalance( + tx, + supplierId, + amount, + invoiceId, + 'PAYMENT', + ) + + await this.purchaseReceiptPaymentWorkflow.onAddPayment( + tx, + bankAccountId, + invoiceId, + amount, + 'PAYMENT', + ) + } +} diff --git a/src/modules/suppliers/ledger/supplier-ledger.controller.ts b/src/modules/suppliers/ledger/supplier-ledger.controller.ts new file mode 100644 index 0000000..ffb333a --- /dev/null +++ b/src/modules/suppliers/ledger/supplier-ledger.controller.ts @@ -0,0 +1,12 @@ +import { Controller, Get, Param } from '@nestjs/common' +import { SupplierLedgerService } from './supplier-ledger.service' + +@Controller('suppliers/:supplierId/ledger') +export class SupplierLedgerController { + constructor(private readonly supplierLedgerService: SupplierLedgerService) {} + + @Get('') + getLedger(@Param('supplierId') supplierId: string) { + return this.supplierLedgerService.findAll(Number(supplierId)) + } +} diff --git a/src/modules/suppliers/ledger/supplier-ledger.module.ts b/src/modules/suppliers/ledger/supplier-ledger.module.ts new file mode 100644 index 0000000..13692ac --- /dev/null +++ b/src/modules/suppliers/ledger/supplier-ledger.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common' +import { PrismaModule } from '../../../prisma/prisma.module' +import { SupplierLedgerController } from './supplier-ledger.controller' +import { SupplierLedgerService } from './supplier-ledger.service' +import { SupplierLedgerWorkflow } from './supplier-ledger.workflow' + +@Module({ + imports: [PrismaModule], + controllers: [SupplierLedgerController], + providers: [SupplierLedgerService, SupplierLedgerWorkflow], + exports: [SupplierLedgerWorkflow], +}) +export class SupplierLedgerModule {} diff --git a/src/modules/suppliers/ledger/supplier-ledger.service.ts b/src/modules/suppliers/ledger/supplier-ledger.service.ts new file mode 100644 index 0000000..bcb929f --- /dev/null +++ b/src/modules/suppliers/ledger/supplier-ledger.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@nestjs/common' +import { ResponseMapper } from '../../../common/response/response-mapper' +import { PrismaService } from '../../../prisma/prisma.service' + +@Injectable() +export class SupplierLedgerService { + constructor(private prisma: PrismaService) {} + + async findAll(supplierId: number) { + const items = await this.prisma.supplierLedger.findMany({ + where: { + supplierId, + }, + omit: { + supplierId: true, + }, + orderBy: { + createdAt: 'desc', + }, + }) + return ResponseMapper.list(items) + } +} diff --git a/src/modules/suppliers/ledger/supplier-ledger.workflow.ts b/src/modules/suppliers/ledger/supplier-ledger.workflow.ts new file mode 100644 index 0000000..026fdb6 --- /dev/null +++ b/src/modules/suppliers/ledger/supplier-ledger.workflow.ts @@ -0,0 +1,57 @@ +import { Injectable } from '@nestjs/common' +import { Prisma } from '../../../generated/prisma/client' +import { LedgerSourceType } from '../../../generated/prisma/enums' + +@Injectable() +export class SupplierLedgerWorkflow { + async updateLedgerBalance( + tx: Prisma.TransactionClient, + supplierId: number, + amount: number, + sourceId: number, + sourceType: LedgerSourceType, + ) { + const lastSupplierLedgerBalance = await tx.supplierLedger + .findFirstOrThrow({ + where: { supplierId }, + orderBy: { createdAt: 'desc' }, + }) + .then(sl => (sl ? sl.balance : 0)) + + let newBalance = Number(lastSupplierLedgerBalance) + let credit = 0 + let debit = 0 + let description = '' + + switch (sourceType) { + case 'PURCHASE': + newBalance += amount + credit = amount + description = `خرید به مبلغ ${amount} بابت خرید شماره ${sourceId}` + break + case 'REFUND': + case 'PAYMENT': + newBalance -= amount + debit = amount + description = `پرداخت به مبلغ ${amount} بابت پرداخت شماره ${sourceId}` + break + case 'ADJUSTMENT': + newBalance = amount + description = `اصلاح حساب به مبلغ ${amount} بابت پرداخت شماره ${sourceId}` + + break + } + + return await tx.supplierLedger.create({ + data: { + supplierId, + debit, + credit, + balance: newBalance, + sourceId, + sourceType, + description, + }, + }) + } +} diff --git a/src/modules/suppliers/suppliers.module.ts b/src/modules/suppliers/suppliers.module.ts index 5f17c23..f717480 100644 --- a/src/modules/suppliers/suppliers.module.ts +++ b/src/modules/suppliers/suppliers.module.ts @@ -3,9 +3,10 @@ import { PrismaModule } from '../../prisma/prisma.module' import { SuppliersController } from './index/suppliers.controller' import { SuppliersService } from './index/suppliers.service' import { SupplierInvoicesModule } from './invoices/invoices.module' +import { SupplierLedgerModule } from './ledger/supplier-ledger.module' @Module({ - imports: [PrismaModule, SupplierInvoicesModule], + imports: [PrismaModule, SupplierInvoicesModule, SupplierLedgerModule], controllers: [SuppliersController], providers: [SuppliersService], }) diff --git a/src/purchase-receipts/purchase-receipts.module.ts b/src/purchase-receipts/purchase-receipts.module.ts deleted file mode 100644 index bc94cbf..0000000 --- a/src/purchase-receipts/purchase-receipts.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common' -import { PrismaModule } from '../prisma/prisma.module' -import { PurchaseReceiptsController } from './purchase-receipts.controller' -import { PurchaseReceiptsService } from './purchase-receipts.service' - -@Module({ - imports: [PrismaModule], - controllers: [PurchaseReceiptsController], - providers: [PurchaseReceiptsService], -}) -export class PurchaseReceiptsModule {}