Files
bnhtrade/src/bnhtrade.Core/Logic/Inventory/StockService.cs
2025-07-10 19:07:09 +01:00

223 lines
9.2 KiB
C#

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<int> { 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);
}
}
}