using bnhtrade.Core.Data.Database.UnitOfWork; using bnhtrade.Core.Logic.Account; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Transactions; using static System.Formats.Asn1.AsnWriter; namespace bnhtrade.Core.Logic.Inventory { public class StockService : UnitOfWorkBase { public StockService() : base() { } internal StockService(IUnitOfWork unitOfWork) : base(unitOfWork) { } public int WIP_StockInsertPurchase(int productId, int conditionId, int accountTaxCodeId, int accountJournalId, int quantity, int statusDebitId) { DateTime stockJournalEntryDate; int stockJournalTypeId = 1; return WithUnitOfWork(uow => { stockJournalEntryDate = new AccountJournalService(uow).ReadJournalEntryDate(accountJournalId); int result = WIP_StockInsertSub( uow, productId, conditionId, accountTaxCodeId, accountJournalId, stockJournalTypeId, stockJournalEntryDate, quantity, statusDebitId); CommitIfOwned(uow); return result; }); } public int WIP_StockInsertOwnerIntroduced(decimal amount, int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId) { int accountJournalType = 3; int stockJournalType = 2; string currencyCode = "GBP"; 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.AccountJournalService(uow).JournalInsert(accountJournalType, entryDate, currencyCode, amount); // make the stock insert int stockId = WIP_StockInsertSub(uow, productId, conditionId, accountTaxCodeId, accountJournalId, stockJournalType, entryDate, quantity, debitStatusId); return stockId; } private int WIP_StockInsertSub(IUnitOfWork uow, int productId, int conditionId, int accountTaxCodeId, int accountJournalId, int stockJournalTypeId, DateTime stockJournalEntryDate, int quantity, int statusDebitId) { stockJournalEntryDate = DateTime.SpecifyKind(stockJournalEntryDate, DateTimeKind.Utc); // ensure account journal id hasn't already been added to stock table int count = uow.StockRepository.CountStockTableRecords(new List { accountJournalId }); if (count == 1) { throw new Exception("Add account journal entry already assigned to stock line."); } else if (count > 1) { throw new Exception("Houston we have a problem! An account journal entry is assigned to " + count + " stock lines."); } // ensure the debit for the account journal transaction is to an 'Asset' account type bool isIt = uow.AccountJournalRepository.IsJournalDebitAssetType(accountJournalId); if (!isIt) { throw new Exception("Supplied AccountJournal entry must debit an 'Asset' account type."); } // get statusCreditId for stock journal type int? statusCreditId = uow.StockJournalRepository.ReadTypeIdStatusCreditId(stockJournalTypeId); if (statusCreditId == null) { throw new Exception("Default credit status not set for StockJournalTypeID=" + stockJournalTypeId); } // get/set an skuId int skuId = new Logic.Inventory.SkuService(uow).GetSkuId(productId, conditionId, accountTaxCodeId, true); // add the entry to the stock table (minus stockJournalId) int stockId = uow.StockRepository.InsertNewStock(skuId, accountJournalId); // insert stock journal entry var journalPosts = new List<(int statusId, int quantity)>(); journalPosts.Add((statusDebitId, quantity)); journalPosts.Add((statusCreditId.Value, (quantity * -1))); int stockJournalId = new StockJournalService(uow).StockJournalInsert(stockJournalTypeId, stockId, journalPosts, stockJournalEntryDate, true); // update the stock table count = uow.StockRepository.UpdateStockJournalId(stockId, stockJournalId); if (count < 1) { throw new Exception("New stock insert cancelled, failed to update StockJournalID"); } return stockId; } public void WIP_StockDeletePurchase(int 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) { 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 new StockJournalService(uow).StockJournalDelete(stockJournalId); // delete stock table entry count = uow.StockRepository.DeleteStock(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 new AccountJournalService(uow).DeleteJournal(accountJournalId); } } }