Feature: stock replenishment

This commit is contained in:
Bobbie Hodgetts
2024-05-09 13:23:33 +01:00
committed by GitHub
parent 91ef9acc78
commit 270eebca9a
30 changed files with 721 additions and 249 deletions

View File

@@ -15,12 +15,12 @@ namespace bnhtrade.Core.Logic.Account
readAccountCode = new Data.Database.Account.ReadAccountCode();
}
public List<Model.Account.AccountCode> GetAll()
public Dictionary<uint, Model.Account.Account> GetAll()
{
return readAccountCode.All();
}
public Model.Account.AccountCode ByAccountCode(int accountCode)
public Model.Account.Account ByAccountCode(int accountCode)
{
var list = ByAccountCode(new List<int> { accountCode });
if (list.Any())
@@ -33,14 +33,14 @@ namespace bnhtrade.Core.Logic.Account
}
}
public List<Model.Account.AccountCode> ByAccountCode(List<int> accountCodeList)
public List<Model.Account.Account> ByAccountCode(List<int> accountCodeList)
{
return readAccountCode.ByAccountCode(accountCodeList);
}
public Dictionary<int, Model.Account.AccountCode> ConvertToDictionary(List<Model.Account.AccountCode> accountCodeList)
public Dictionary<int, Model.Account.Account> ConvertToDictionary(List<Model.Account.Account> accountCodeList)
{
var returnDict = new Dictionary<int, Model.Account.AccountCode>();
var returnDict = new Dictionary<int, Model.Account.Account>();
if (accountCodeList == null)
{
@@ -49,9 +49,9 @@ namespace bnhtrade.Core.Logic.Account
foreach (var accountCode in accountCodeList)
{
if (!returnDict.ContainsKey(accountCode.AccountCodeId))
if (!returnDict.ContainsKey((int)accountCode.AccountCode))
{
returnDict.Add(accountCode.AccountCodeId, accountCode);
returnDict.Add((int)accountCode.AccountCode, accountCode);
}
}
return returnDict;

View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Logic.Amazon.Fba
{
public class Stock
{
Logic.Stock.StatusBalance read = new Logic.Stock.StatusBalance();
/// <summary>
/// Get a list of FBA SKUs to replenish from reversed stock. This using the local stock ledger and may not tally with Amazon
/// </summary>
/// <returns>SKU and the avaible stock in reserve</returns>
public List<Model.Stock.StatusBalance> GetReplenishmentList()
{
int fbaFulfillableStatusId = (int)Data.Database.Constants.StockStatus.FbaFulfillable;
int reserveStatusId = (int)Data.Database.Constants.StockStatus.ReservedGarageStock;
var fbaList = read.GetSkuQuantity(fbaFulfillableStatusId);
var myList = read.GetSkuQuantity(reserveStatusId);
foreach (var item in fbaList)
{
if (myList.ContainsKey(item.Key))
{
myList.Remove(item.Key);
}
}
var readStatusBalance = new Logic.Stock.StatusBalance();
var returnList = new List<Model.Stock.StatusBalance>();
foreach (var item in myList)
{
var skuStatusBalance = readStatusBalance.GetStatusBalance(item.Key, reserveStatusId, true);
returnList.Add(skuStatusBalance);
}
return returnList;
}
}
}

View File

@@ -66,7 +66,7 @@ namespace bnhtrade.Core.Logic.Sku.Price
statusTypeList.Add((int)Data.Database.Constants.StockStatusType.FbaInventoryActive);
statusTypeList.Add((int)Data.Database.Constants.StockStatusType.FbaShipment);
var fbaSkuStock = new Logic.Stock.GetStatusTypeBalance().BySku(statusTypeList);
var fbaSkuStock = new Logic.Stock.StatusTypeBalance().GetByStatusTypeId(statusTypeList);
// retrive SKU info
var getSku = new Logic.Sku.GetSkuInfo();

View File

@@ -26,29 +26,29 @@ namespace bnhtrade.Core.Logic.Stock
}
/// <summary>
/// Return the avaliable balance of a status at a specified date and time. Useful for checking availability before
/// moving stock/sku retrospectivly
/// Return the avaliable balance of a status, includes datetime that each stockNumber became avaiable.
/// Useful for checking availability before moving stock/sku retrospectivly
/// </summary>
/// <param name="sku">SKU number</param>
/// <param name="skuNumber">SKU number</param>
/// <param name="statusId">Status ID</param>
/// <param name="atDate">Date and time you would like to know the balance at</param>
/// <param name="includeDetails">True, inlcude SKU and StockStatus class. False, supply the SKU Number and StockStatusId instead</param>
/// <returns></returns>
public Model.Stock.StatusBalance GetBySku(string sku, int statusId)
public Model.Stock.StatusBalance GetStatusBalance(string skuNumber, int statusId, bool includeDetails = true)
{
if (string.IsNullOrWhiteSpace(sku))
if (string.IsNullOrWhiteSpace(skuNumber))
{
throw new Exception("SKU number is null, empty, or whitespace");
}
// get list of transactions for availale stock
var stockTransaction = new Data.Database.Stock.ReadStatusTransaction();
var transList = stockTransaction.BySku(statusId, sku);
var readStatusTransaction = new Data.Database.Stock.ReadStatusTransaction();
var statusTransaction = readStatusTransaction.BySku(statusId, skuNumber);
// create quantity list
List<int> qtyList = new List<int>();
for (int i = 0; i < transList.TransactionList.Count; i++)
for (int i = 0; i < statusTransaction.TransactionList.Count; i++)
{
qtyList.Add(transList.TransactionList[i].Quantity);
qtyList.Add(statusTransaction.TransactionList[i].Quantity);
}
// tally list
@@ -57,15 +57,15 @@ namespace bnhtrade.Core.Logic.Stock
{
if (qtyList[iCr] < 0)
{
int crStockNumber = transList.TransactionList[iCr].StockNumber;
DateTime crDate = transList.TransactionList[iCr].EntryDate;
int crStockNumber = statusTransaction.TransactionList[iCr].StockNumber;
DateTime crDate = statusTransaction.TransactionList[iCr].EntryDate;
// loop, in reverse, to find debits
for (int iDr = qtyList.Count - 1; iDr > -1; iDr--)
{
// find debits, last in first out (filter by date)
if (transList.TransactionList[iDr].StockNumber == crStockNumber
&& transList.TransactionList[iDr].EntryDate <= crDate
if (statusTransaction.TransactionList[iDr].StockNumber == crStockNumber
&& statusTransaction.TransactionList[iDr].EntryDate <= crDate
&& qtyList[iDr] > 0)
{
// credit fully assigned
@@ -87,22 +87,49 @@ namespace bnhtrade.Core.Logic.Stock
}
// build result list from tally results
var result = new Model.Stock.StatusBalance();
result.Sku = transList.Sku;
result.StockStatusId = transList.StockStatusId;
var entryList = new List<(DateTime EntryDate, int StockNumber, int Quantity)>();
for (int i = 0; i < qtyList.Count; i++)
{
if (qtyList[i] != 0)
{
result.AddBalanceTransaction(
transList.TransactionList[i].EntryDate,
transList.TransactionList[i].StockNumber,
(DateTime EntryDate, int StockNumber, int Quantity) entryItem = (
statusTransaction.TransactionList[i].EntryDate,
statusTransaction.TransactionList[i].StockNumber,
qtyList[i]);
entryList.Add(entryItem);
}
}
return result;
if (includeDetails)
{
// get the sku obj
var readSku = new Logic.Sku.GetSkuInfo();
readSku.IncludeConditionInfo = true;
readSku.IncludeProductInfo = true;
readSku.IncludeTaxCodeInfo = true;
var sku = readSku.BySkuNumber(statusTransaction.SkuNumber);
// get the status obj
var readStatus = new Data.Database.Stock.Status();
readStatus.StatusIds = new List<int> { statusTransaction.StockStatusId };
var status = readStatus.Read()[0];
return new Model.Stock.StatusBalance(status, sku, entryList);
}
else
{
return new Model.Stock.StatusBalance(statusTransaction.StockStatusId, statusTransaction.SkuNumber, entryList);
}
}
/// <summary>
/// Get a list of SKUs avaliable against a specified statusId
/// </summary>
/// <param name="statusId">The stock status id</param>
/// <returns>Dictionary of SKUs and the repective balance of each</returns>
public Dictionary<string, int> GetSkuQuantity(int statusId)
{
return new Data.Database.Stock.ReadStatusBalance().ByStatusId(statusId);
}
}
}

View File

@@ -58,10 +58,10 @@ namespace bnhtrade.Core.Logic.Stock
var returnList = new List<(int StockJournalId, int Quantity)>();
// get balance of status and check for avaliable quantity
var statusBalance = new Logic.Stock.StatusBalance().GetBySku(skuNumber, creditStatusId);
var statusBalance = new Logic.Stock.StatusBalance().GetStatusBalance(skuNumber, creditStatusId);
if (statusBalance.GetAvaliableQuantity(entryDate) <= 0
|| (statusBalance.CheckAvaliableQuantity(quantity, entryDate) == false && reallocatePartialQuantity == false
|| (statusBalance.IsQuantityAvaliable(quantity, entryDate) == false && reallocatePartialQuantity == false
))
{
return returnList;
@@ -70,7 +70,7 @@ namespace bnhtrade.Core.Logic.Stock
// temp code start
// until use of stockId is designed out of application
var stockIdDictionary = new Dictionary<int, int>();
foreach (var item in statusBalance.ByDateList)
foreach (var item in statusBalance.StockList)
{
if (!stockIdDictionary.ContainsKey(item.StockNumber))
{
@@ -84,7 +84,7 @@ namespace bnhtrade.Core.Logic.Stock
//make the changes
using (TransactionScope scope = new TransactionScope())
{
foreach (var item in statusBalance.ByDateList)
foreach (var item in statusBalance.StockList)
{
if (quantity > item.Quantity)
{

View File

@@ -6,11 +6,11 @@ using System.Threading.Tasks;
namespace bnhtrade.Core.Logic.Stock
{
public class GetStatusTypeBalance
public class StatusTypeBalance
{
private Core.Data.Database.Stock.ReadStatusTypeBalance dbRead;
public GetStatusTypeBalance()
public StatusTypeBalance()
{
dbRead = new Data.Database.Stock.ReadStatusTypeBalance();
}
@@ -20,7 +20,7 @@ namespace bnhtrade.Core.Logic.Stock
/// </summary>
/// <param name="StatusTypeIdList">List of Status Type Ids</param>
/// <returns>Dictionary where SKU number is key and quantity is value</returns>
public Dictionary<string, int> BySku(List<int> StatusTypeIdList)
public Dictionary<string, int> GetByStatusTypeId(List<int> StatusTypeIdList)
{
return dbRead.ReadSku(StatusTypeIdList);
}