From e2af1e4f99f9d7ff53b920feee4c8ff03314d01a Mon Sep 17 00:00:00 2001 From: Bob Hodgetts Date: Wed, 9 Jul 2025 16:47:37 +0100 Subject: [PATCH] wip --- .../Implementation/StockRepository.cs | 147 ++++++++ .../Repository/Interface/IStockRepository.cs | 5 + .../Data/Database/UnitOfWork/IUnitOfWork.cs | 2 +- .../Data/Database/UnitOfWork/UnitOfWork.cs | 26 +- .../Logic/Account/JournalService.cs | 4 +- .../Logic/Inventory/StockService.cs | 355 ++++++------------ 6 files changed, 288 insertions(+), 251 deletions(-) diff --git a/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockRepository.cs b/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockRepository.cs index 4fe9bed..7743bca 100644 --- a/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockRepository.cs +++ b/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockRepository.cs @@ -1,5 +1,6 @@ using bnhtrade.Core.Data.Database.Repository.Interface; using bnhtrade.Core.Data.Database.UnitOfWork; +using Microsoft.Data.SqlClient; using System; using System.Collections.Generic; using System.Data; @@ -183,14 +184,160 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation // read // + public int? ReadStockJournalId(int stockId) + { + if (stockId <= 0) + { + throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId)); + } + + using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand) + { + cmd.Transaction = _transaction as SqlTransaction; + cmd.CommandText = @" + SELECT StockJournalID + FROM tblStock + WHERE StockID=@stockId;;"; + + cmd.Parameters.AddWithValue("@stockId", stockId); + object obj = cmd.ExecuteScalar(); + if (obj == null ) + { + throw new Exception("StockID=" + stockId + " does not exist."); + } + else if (obj == DBNull.Value) + { + return null; // no stock journal entry + } + else + { + return (int)obj; + } + } + } + + public int? ReadAccountJournalId(int stockId) + { + if (stockId <= 0) + { + throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId)); + } + using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand) + { + cmd.Transaction = _transaction as SqlTransaction; + cmd.CommandText = @" + SELECT AccountJournalID + FROM tblStock + WHERE StockID=@stockId;"; + cmd.Parameters.AddWithValue("@stockId", stockId); + object obj = cmd.ExecuteScalar(); + if (obj == null) + { + throw new Exception("StockID=" + stockId + " does not exist."); + } + else if (obj == DBNull.Value) + { + return null; // no account journal entry + } + else + { + return (int)obj; + } + } + } + // // update // + public int UpdateAccountJournalId(int stockId, int? accountJournalID) + { + if (stockId <= 0) + { + throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId)); + } + + string sql = @" + UPDATE + tblStock + SET + AccountJournalID = @accountJournalID + WHERE + StockID = @stockId;"; + + using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand) + { + cmd.CommandText = sql; + cmd.Transaction = _transaction as SqlTransaction; + cmd.Parameters.AddWithValue("@stockId", stockId); + if (accountJournalID == null) + { + cmd.Parameters.AddWithValue("@accountJournalID", DBNull.Value); + } + else + { + cmd.Parameters.AddWithValue("@accountJournalID", accountJournalID); + } + + return cmd.ExecuteNonQuery(); + } + } + + public int UpdateStockJournalId(int stockId, int? stockJournalId) + { + if (stockId <= 0) + { + throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId)); + } + + string sql = @" + UPDATE + tblStock + SET + StockJournalID = @stockJournalId + WHERE + StockID = @stockId;"; + + using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand) + { + cmd.CommandText = sql; + cmd.Transaction = _transaction as SqlTransaction; + cmd.Parameters.AddWithValue("@stockId", stockId); + if (stockJournalId == null) + { + cmd.Parameters.AddWithValue("@stockJournalId", DBNull.Value); + } + else + { + cmd.Parameters.AddWithValue("@stockJournalId", stockJournalId); + } + + return cmd.ExecuteNonQuery(); + } + } + + // // delete // + public int DeleteStockTableLine(int stockId) + { + if (stockId <= 0) + { + throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId)); + } + using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand) + { + cmd.Transaction = _transaction as SqlTransaction; + cmd.CommandText = @" + DELETE FROM tblStock + WHERE StockID=@stockId;"; + cmd.Parameters.AddWithValue("@stockId", stockId); + return cmd.ExecuteNonQuery(); + } + } + private void WIP_StockDelete(int stockId) { int accountJournalType = 0; diff --git a/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockRepository.cs b/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockRepository.cs index 8d4de77..98188a3 100644 --- a/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockRepository.cs +++ b/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockRepository.cs @@ -12,6 +12,11 @@ namespace bnhtrade.Core.Data.Database.Repository.Interface int accountJournalId, int stockJournalTypeId, DateTime stockJournalEntryDate, int quantity, int statusDebitId); int WIP_StockInsertPurchase(int productId, int conditionId, int accountTaxCodeId, int accountJournalId, int quantity, int statusDebitId); int WIP_StockInsertOwnerIntroduced(decimal amount, int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId); + int? ReadAccountJournalId(int stockId); + int? ReadStockJournalId(int stockId); + int UpdateAccountJournalId(int stockId, int? accountJournalID); + int UpdateStockJournalId(int stockId, int? stockJournalID); + int DeleteStockTableLine(int stockId); void WIP_StockDelete(int stockId); void WIP_StockDeleteSub(int stockId); void WIP_StockDeleteSubAccountJournalEntry(int stockId); diff --git a/src/bnhtrade.Core/Data/Database/UnitOfWork/IUnitOfWork.cs b/src/bnhtrade.Core/Data/Database/UnitOfWork/IUnitOfWork.cs index 8177f2e..b106762 100644 --- a/src/bnhtrade.Core/Data/Database/UnitOfWork/IUnitOfWork.cs +++ b/src/bnhtrade.Core/Data/Database/UnitOfWork/IUnitOfWork.cs @@ -17,7 +17,7 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork IAmazonSettlementRepository AmazonSettlementRepository { get; } IInvoiceRepository InvoiceRepository { get; } IPurchaseRepository PurchaseRepository { get; } - IAccountJournalRepository JournalRepository { get; } + IAccountJournalRepository AccountJournalRepository { get; } ISequenceGenerator SequenceGenerator { get; } ISkuRepository SkuRepository { get; } IStockRepository StockRepository { get; } diff --git a/src/bnhtrade.Core/Data/Database/UnitOfWork/UnitOfWork.cs b/src/bnhtrade.Core/Data/Database/UnitOfWork/UnitOfWork.cs index 0dbdbf6..12e26bb 100644 --- a/src/bnhtrade.Core/Data/Database/UnitOfWork/UnitOfWork.cs +++ b/src/bnhtrade.Core/Data/Database/UnitOfWork/UnitOfWork.cs @@ -19,13 +19,13 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork // Private field for lazy loading, add here for each repository private IAccountCodeRepository _accountCodeRepository; + private IAccountJournalRepository _accountJournalRepository; private IAccountTaxRepository _accountTaxRepository; private IAmazonSettlementRepository _amazonSettlementRepository; private ICurrencyRepository _currencyRepository; private IExportInvoiceRepository _exportInvoiceRepository; private IInvoiceRepository _invoiceRepository; private IPurchaseRepository _purchaseRepository; - private IAccountJournalRepository _journalRepository; private ISequenceGenerator _sequenceGenerator; private ISkuRepository _skuRepository; private IStockRepository _stockRepository; @@ -51,6 +51,18 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork } } + public IAccountJournalRepository AccountJournalRepository + { + get + { + if (_accountJournalRepository == null) + { + _accountJournalRepository = new AccountJournalRepository(_connection, _transaction); + } + return _accountJournalRepository; + } + } + public IAccountTaxRepository AccountTaxRepository { get @@ -123,18 +135,6 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork } } - public IAccountJournalRepository JournalRepository - { - get - { - if (_journalRepository == null) - { - _journalRepository = new AccountJournalRepository(_connection, _transaction); - } - return _journalRepository; - } - } - public ISequenceGenerator SequenceGenerator { get diff --git a/src/bnhtrade.Core/Logic/Account/JournalService.cs b/src/bnhtrade.Core/Logic/Account/JournalService.cs index a9fd445..4c6227e 100644 --- a/src/bnhtrade.Core/Logic/Account/JournalService.cs +++ b/src/bnhtrade.Core/Logic/Account/JournalService.cs @@ -24,7 +24,7 @@ namespace bnhtrade.Core.Logic.Account { return WithUnitOfWork(uow => { - int journalId = uow.JournalRepository.AccountJournalInsert(journalTypeId, entryDate, currencyCode, + int journalId = uow.AccountJournalRepository.AccountJournalInsert(journalTypeId, entryDate, currencyCode, amount, debitAccountId, creditAccountId, lockEntry); CommitIfOwned(uow); return journalId; @@ -35,7 +35,7 @@ namespace bnhtrade.Core.Logic.Account { return WithUnitOfWork(uow => { - bool result = uow.JournalRepository.DeleteJournal(accountJournalId); + bool result = uow.AccountJournalRepository.DeleteJournal(accountJournalId); CommitIfOwned(uow); return result; }); diff --git a/src/bnhtrade.Core/Logic/Inventory/StockService.cs b/src/bnhtrade.Core/Logic/Inventory/StockService.cs index eb05986..32677e4 100644 --- a/src/bnhtrade.Core/Logic/Inventory/StockService.cs +++ b/src/bnhtrade.Core/Logic/Inventory/StockService.cs @@ -15,237 +15,6 @@ namespace bnhtrade.Core.Logic.Inventory internal StockService(IUnitOfWork unitOfWork) : base(unitOfWork) { } - private int WIP_StockInsert(int accountJournalType, int stockJournalType, string currencyCode, decimal amount, - int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId) - { - return WithUnitOfWork(uow => - { - // add account journal entry - int accountJournalId = new Logic.Account.JournalService(uow).JournalInsert(accountJournalType, entryDate, currencyCode, amount); - - // make the stock insert - int stockId = uow.StockRepository.WIP_StockInsertSub(productId, conditionId, accountTaxCodeId, - accountJournalId, stockJournalType, entryDate, quantity, debitStatusId); - - CommitIfOwned(uow); - - return stockId; - - }); - } - - private void WIP_StockDelete(int stockId) - { - int stockJournalType = 0; - - WithUnitOfWork(uow => - { - // ensure stockId is owner-introduced - stockJournalType = uow.StockJournalRepository.ReadJournalTypeIdByStockId(stockId); - - // check stock journal type is not restricted - // owner inventory introduced - if (stockJournalType == 2) - { - // no dramas - } - else - { - throw new Exception("Manual delete of this stock type is not supported, use the method that created it!"); - } - - // check there is only one stock journal entry for stock item (i.e. the source entry) - int count = uow.StockJournalRepository.ReadJournalEntryCountByStockId(stockId); - - if (count > 1) - { - throw new Exception("Delete " + count + " stock journal entries (other than source entry), before peforming this operation."); - } - - // remove account journal entry - WIP_StockDeleteSubAccountJournalEntry(sqlConnectionString, stockId); - - // remove stock - WIP_StockDeleteSub(sqlConnectionString, stockId); - - scope.Complete(); - - - - - - - - - - - - - - - - - }); - } - - private void WIP_StockDeleteSub(int stockId) - { - using (TransactionScope scope = new TransactionScope()) - using (SqlConnection conn = new SqlConnection(sqlConnectionString)) - { - conn.Open(); - - // check for accountJournalId on stock table - using (SqlCommand cmd = new SqlCommand(@" - SELECT AccountJournalID - FROM tblStock - WHERE StockID=@stockId; - ", conn)) - { - cmd.Parameters.AddWithValue("@stockId", stockId); - - object obj = cmd.ExecuteScalar(); - - if (obj == null) - { - throw new Exception("StockID=" + stockId + " does not exist."); - } - else if (obj == DBNull.Value) - { - // nothing to do all is good - } - else - { - int id = (int)obj; - if (id > 0) - { - throw new Exception("StockID=" + stockId + " remove account journal entry using method that created it first."); - } - } - } - - // get stockJournalId - int stockJournalId; - using (SqlCommand cmd = new SqlCommand(@" - SELECT StockJournalID - FROM tblStock - WHERE StockID=@stockId; - ", conn)) - { - cmd.Parameters.AddWithValue("@stockId", stockId); - - try - { - stockJournalId = (int)cmd.ExecuteScalar(); - } - catch - { - throw new Exception("Could not retrive StockJournalID for StockID=" + stockId); - } - } - - // remove stockJournalId from stock table - using (SqlCommand cmd = new SqlCommand(@" - UPDATE tblStock - SET StockJournalID=NULL - WHERE StockID=@stockId; - ", conn)) - { - cmd.Parameters.AddWithValue("@stockId", stockId); - - int count = cmd.ExecuteNonQuery(); - - if (count != 2) // we need to count the LastUpdated trigger! - { - throw new Exception("Failed to remove StockJournalID from stock table StockID=" + stockId); - } - } - - // delete stock journal entry - new Core.Logic.Inventory.StockJournalService().StockJournalDelete(stockJournalId); - - // delete stock table entry - using (SqlCommand cmd = new SqlCommand(@" - DELETE FROM tblStock - WHERE StockID=@stockId; - ", conn)) - { - cmd.Parameters.AddWithValue("@stockId", stockId); - - int count = cmd.ExecuteNonQuery(); - - if (count != 1) - { - throw new Exception("StockID = " + stockId + " delete failed"); - } - else - { - scope.Complete(); - } - } - } - } - - // to be used by other methods within a transaction scope - private void WIP_StockDeleteSubAccountJournalEntry(int stockId) - { - using (SqlConnection conn = new SqlConnection(sqlConnectionString)) - { - conn.Open(); - var trans = conn.BeginTransaction(); - - // get the account journal id - int accountJournalId = 0; - using (SqlCommand cmd = new SqlCommand(@" - SELECT AccountJournalID - FROM tblStock - WHERE StockID=@stockId; - ", conn)) - { - cmd.Transaction = trans; - cmd.Parameters.AddWithValue("@stockId", stockId); - - object obj = cmd.ExecuteScalar(); - - if (obj == null) - { - throw new Exception("StockID=" + stockId + " does not exist."); - } - else if (obj == DBNull.Value) - { - throw new Exception("AccountJournalID not found for StockID=" + stockId); - } - else - { - accountJournalId = (int)obj; - } - } - - // remove entry from stock table - using (SqlCommand cmd = new SqlCommand(@" - UPDATE tblStock - SET AccountJournalID=NULL - WHERE StockID=@stockId; - ", conn)) - { - cmd.Transaction = trans; - cmd.Parameters.AddWithValue("@stockId", stockId); - - int count = cmd.ExecuteNonQuery(); - - if (count != 2) // must include last modified trigger - { - throw new Exception("Failed to set AccountJournalID to NULL on stock table for StockID=" + stockId); - } - } - - // delete account journal entry - new Data.Database.Repository.Implementation.AccountJournalRepository(conn, trans).DeleteJournal(accountJournalId); - - trans.Commit(); - } - } - public int WIP_StockInsertPurchase(int productId, int conditionId, int accountTaxCodeId, int accountJournalId, int quantity, int statusDebitId) { DateTime stockJournalEntryDate; @@ -253,7 +22,7 @@ namespace bnhtrade.Core.Logic.Inventory return WithUnitOfWork(uow => { - stockJournalEntryDate = uow.JournalRepository.ReadJournalEntryDate(accountJournalId); + stockJournalEntryDate = uow.AccountJournalRepository.ReadJournalEntryDate(accountJournalId); int result = uow.StockRepository.WIP_StockInsertSub( productId, conditionId, accountTaxCodeId, accountJournalId, stockJournalTypeId, stockJournalEntryDate, quantity, statusDebitId); CommitIfOwned(uow); @@ -267,17 +36,133 @@ namespace bnhtrade.Core.Logic.Inventory int stockJournalType = 2; string currencyCode = "GBP"; - return WIP_StockInsert(accountJournalType, stockJournalType, currencyCode, amount, quantity, productId, conditionId, accountTaxCodeId, entryDate, debitStatusId); + return WithUnitOfWork(uow => + { + int stockId = WIP_StockInsert(uow, accountJournalType, stockJournalType, currencyCode, amount, quantity, productId, conditionId, accountTaxCodeId, entryDate, debitStatusId); + CommitIfOwned(uow); + return stockId; + }); } + private int WIP_StockInsert(IUnitOfWork uow, int accountJournalType, int stockJournalType, string currencyCode, decimal amount, + int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId) + { + // add account journal entry + int accountJournalId = new Logic.Account.JournalService(uow).JournalInsert(accountJournalType, entryDate, currencyCode, amount); + + // make the stock insert + int stockId = uow.StockRepository.WIP_StockInsertSub(productId, conditionId, accountTaxCodeId, + accountJournalId, stockJournalType, entryDate, quantity, debitStatusId); + + return stockId; + } + + public void WIP_StockDeletePurchase(int stockId) { - WIP_StockDeleteSub(sqlConnectionString, stockId); + WithUnitOfWork(uow => + { + if (stockId <= 0) + { + throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId)); + } + WIP_StockDelete(uow, stockId); + CommitIfOwned(uow); + }); } public void WIP_StockDeleteOwnerIntroduced(int stockId) { - WIP_StockDelete(sqlConnectionString, stockId); + WithUnitOfWork(uow => + { + if (stockId <= 0) + { + throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId)); + } + WIP_StockDelete(uow, stockId); + CommitIfOwned(uow); + }); + } + + private void WIP_StockDelete(IUnitOfWork uow, int stockId) + { + int stockJournalType = 0; + + // ensure stockId is owner-introduced + stockJournalType = uow.StockJournalRepository.ReadJournalTypeIdByStockId(stockId); + + // check stock journal type is not restricted + // owner inventory introduced + if (stockJournalType == 2) + { + // no dramas + } + else + { + throw new Exception("Manual delete of this stock type is not supported, use the method that created it!"); + } + + // check there is only one stock journal entry for stock item (i.e. the source entry) + int count = uow.StockJournalRepository.ReadJournalEntryCountByStockId(stockId); + + if (count > 1) + { + throw new Exception("Delete " + count + " stock journal entries (other than source entry), before peforming this operation."); + } + + // remove account journal entry + WIP_StockDeleteSubAccountJournalEntry(uow, stockId); + + // remove stock + WIP_StockDeleteSub(uow, stockId); + } + + private void WIP_StockDeleteSub(IUnitOfWork uow, int stockId) + { + // check for accountJournalId on stock table + int? accountJournalId = uow.StockRepository.ReadAccountJournalId(stockId); + if (accountJournalId.HasValue) + { + throw new Exception("StockID=" + stockId + " remove account journal entry using method that created it first."); + } + + // get stockJournalId + int stockJournalId = uow.StockRepository.ReadStockJournalId(stockId) ?? throw new Exception("StockJournalID not found for StockID=" + stockId); + + // remove stockJournalId from stock table + int count = uow.StockRepository.UpdateStockJournalId(stockId, null); + if (count != 2) // we need to count the LastUpdated trigger! + { + throw new Exception("Failed to remove StockJournalID from stock table StockID=" + stockId); + } + + // delete stock journal entry + uow.StockJournalRepository.StockJournalDelete(stockJournalId); + + // delete stock table entry + count = uow.StockRepository.DeleteStockTableLine(stockId); + if (count != 1) + { + throw new Exception("StockID = " + stockId + " delete failed"); + } + } + + // to be used by other methods within a transaction scope + private void WIP_StockDeleteSubAccountJournalEntry(IUnitOfWork uow, int stockId) + { + // get the account journal id + int accountJournalId = uow.StockRepository.ReadAccountJournalId(stockId) ?? throw new Exception("AccountJournalID not found for StockID=" + stockId); + + // remove entry from stock table + int count = uow.StockRepository.UpdateAccountJournalId(stockId, null); + + if (count != 2) // must include last modified trigger + { + throw new Exception("Failed to set AccountJournalID to NULL on stock table for StockID=" + stockId); + } + + // delete account journal entry + uow.AccountJournalRepository.DeleteJournal(accountJournalId); } }