Various bug fixs and improvements to stock SKU reconciliation

This commit is contained in:
Bobbie Hodgetts
2020-10-05 22:40:55 +01:00
parent cc2534a3e1
commit ddd2b62743
25 changed files with 1026 additions and 467 deletions

View File

@@ -13,8 +13,6 @@ namespace bnhtrade.ComTypeLib
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IProduct
{
string ReturnStringValue(string stringValue);
double ReturnDateValueAsDouble(string stringValue);
int ProductGetProductIdByCatId(int catId, ConnectionCredential sqlConnCred);
@@ -32,20 +30,12 @@ namespace bnhtrade.ComTypeLib
[ProgId("bnhtrade.Product")]
public class Product : IProduct
{
[ComVisible(false)]
[return: MarshalAs(UnmanagedType.BStr)]
public string ReturnStringValue(string stringValue)
{
return "kj;lk1";
}
[ComVisible(false)]
public double ReturnDateValueAsDouble(string stringValue)
{
DateTime theTimeNow = DateTime.UtcNow;
return theTimeNow.ToOADate();
// back in vba use the CDate(return) function to convert the double
// vba Date --> c# DateTime works without marshalling
// vba Date --> c# DateTime works without marshalling.
}
public int ProductGetProductIdByCatId(int catId, ConnectionCredential sqlConnCred)
@@ -104,10 +94,5 @@ namespace bnhtrade.ComTypeLib
Core.Product.ProductQuery.ProductUpdateAmazonEstimateFee(sqlConnCred.ConnectionString, inputTuple);
}
}
}

View File

@@ -30,6 +30,8 @@ namespace bnhtrade.ComTypeLib
void UnReconcileSkuTransaction(ConnectionCredential sqlConnCred, int skuTransactionId);
bool StockJournalConsistencyCheck(ConnectionCredential sqlConnCred, int stockId);
void SkuTransactionAdd(ConnectionCredential sqlConnCred, int quantity, string skuNumber, string transactionTypeCode, DateTime transactionDate);
}
[ComVisible(true)]
@@ -63,7 +65,7 @@ namespace bnhtrade.ComTypeLib
{
entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc);
return new Core.Logic.Stock.Reallocate(sqlConnCred.ConnectionString).StockReallocateByStockId(4, stockId, quantity, debitStatusId, creditStatusId, entryDate);
return new Core.Logic.Stock.StatusReallocate(sqlConnCred.ConnectionString).ByStockId(entryDate, 4, stockId, quantity, debitStatusId, creditStatusId);
}
public void StockJournalDelete(ConnectionCredential sqlConnCred, int stockJournalId)
@@ -128,5 +130,19 @@ namespace bnhtrade.ComTypeLib
{
return Core.Stock.StockJournal.WIP_StockJournalConsistencyCheck(sqlConnCred.ConnectionString, stockId, null);
}
public void SkuTransactionAdd(ConnectionCredential sqlConnCred, int quantity, string skuNumber, string transactionTypeCode, DateTime transactionDate)
{
var trans = new bnhtrade.Core.Model.Stock.SkuTransaction();
trans.IsProcessed = false;
trans.Quantity = (short)quantity;
//trans.Reference
trans.SkuNumber = skuNumber;
trans.SkuTransactionTypeCode = transactionTypeCode;
//trans.StockJournalId;
trans.TransactionDate = transactionDate;
new bnhtrade.Core.Logic.Stock.SkuTransactionPersistance(sqlConnCred.ConnectionString).Create(trans);
}
}
}

View File

@@ -9,7 +9,7 @@ namespace bnhtrade.Core.Data.Database.Account
{
public class ReadAccountCode : Connection
{
private Data.Database.WhereBuilder sqlWhere = new WhereBuilder();
private Data.Database.SqlWhereBuilder sqlWhere = new SqlWhereBuilder();
private List<Model.Account.AccountCode> resultList;
public ReadAccountCode(string sqlConnectionString) : base(sqlConnectionString)

View File

@@ -62,7 +62,7 @@ namespace bnhtrade.Core.Data.Database.Account
LEFT OUTER JOIN tblAccountChartOf ON tblAccountInvoiceLineItem.AccountChartOfID_Default = tblAccountChartOf.AccountChartOfID
WHERE ";
var whereBuilder = new WhereBuilder();
var whereBuilder = new SqlWhereBuilder();
whereBuilder.In("tblAccountInvoiceLineItem.ItemCode", itemCodeList);
sql += whereBuilder.SqlWhereString;

View File

@@ -9,11 +9,11 @@ namespace bnhtrade.Core.Data.Database.Account
{
public class ReadTaxCode : Connection
{
private Data.Database.WhereBuilder whereBuilder;
private Data.Database.SqlWhereBuilder whereBuilder;
public ReadTaxCode(string sqlConnectionString) : base(sqlConnectionString)
{
whereBuilder = new WhereBuilder();
whereBuilder = new SqlWhereBuilder();
}
private List<Model.Account.TaxCodeInfo> Execute(string sqlWhere, Dictionary<string, object> parameters)

View File

@@ -1,16 +1,17 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database
{
public class WhereBuilder
public class SqlWhereBuilder
{
private int parameterCount;
public WhereBuilder()
public SqlWhereBuilder()
{
Innit();
}
@@ -26,6 +27,14 @@ namespace bnhtrade.Core.Data.Database
parameterCount = 0;
}
public void AddParametersToSqlCommand(SqlCommand cmd)
{
foreach (var item in ParameterList)
{
cmd.Parameters.AddWithValue(item.Key, item.Value);
}
}
/// <summary>
/// Used to create a string for an SQL where condition 'In' statement
/// </summary>

View File

@@ -10,7 +10,8 @@ namespace bnhtrade.Core.Data.Database.Stock
{
public class ReadSkuTransaction : Connection
{
private Data.Database.WhereBuilder whereBuilder = new WhereBuilder();
private Data.Database.SqlWhereBuilder whereBuilder = new SqlWhereBuilder();
private List<int> transactionIdList = new List<int>();
public ReadSkuTransaction(string sqlConnectionString) : base(sqlConnectionString)
{
@@ -22,7 +23,7 @@ namespace bnhtrade.Core.Data.Database.Stock
/// </summary>
public void Init()
{
whereBuilder = new WhereBuilder();
whereBuilder = new SqlWhereBuilder();
IsReconciled = null;
StockTransactionTypeName = null;
StockTransactionTypeCode = null;
@@ -107,34 +108,44 @@ namespace bnhtrade.Core.Data.Database.Stock
INNER JOIN tblSku ON tblStockSkuTransaction.SkuID = tblSku.skuSkuID
WHERE 1=1 ";
if (IsReconciled != null)
if (transactionIdList.Any())
{
parameters.Add("@transactionIdList", this.transactionIdList);
sql += @"
AND tblStockSkuTransaction.StockSkuTransactionID IN @transactionIdList ";
}
else
{
if (IsReconciled != null)
{
sql += @"
AND tblStockSkuTransaction.IsProcessed =";
if (IsReconciled.GetValueOrDefault())
{
sql += " 1 ";
if (IsReconciled.GetValueOrDefault())
{
sql += " 1 ";
}
else
{
sql += " 0 ";
}
}
else
{
sql += " 0 ";
}
}
if (StockTransactionTypeName != null && StockTransactionTypeName.Any())
{
parameters.Add("@stockTransactionTypeName", StockTransactionTypeName);
if (StockTransactionTypeName != null && StockTransactionTypeName.Any())
{
parameters.Add("@stockTransactionTypeName", StockTransactionTypeName);
sql += @"
sql += @"
AND tblStockSkuTransactionType.TypeName IN @stockTransactionTypeName ";
}
}
if (StockTransactionTypeCode != null && StockTransactionTypeCode.Any())
{
parameters.Add("@stockTransactionTypeCode", StockTransactionTypeCode);
if (StockTransactionTypeCode != null && StockTransactionTypeCode.Any())
{
parameters.Add("@stockTransactionTypeCode", StockTransactionTypeCode);
sql += @"
sql += @"
AND tblStockSkuTransactionType.TypeCode IN @stockTransactionTypeCode ";
}
}
sql += @"
@@ -158,5 +169,23 @@ namespace bnhtrade.Core.Data.Database.Stock
return resultList;
}
/// <summary>
/// Get Stock SKU Transaction by ID
/// </summary>
/// <param name="transactionIdList"></param>
/// <returns>List of SkuTransaction</returns>
public List<Model.Stock.SkuTransaction> Read(List<int> transactionIdList)
{
var returnList = new List<Model.Stock.SkuTransaction>();
if (!transactionIdList.Any())
{
return returnList;
}
this.transactionIdList = transactionIdList;
returnList = Read();
this.transactionIdList = new List<int>();
return returnList;
}
}
}

View File

@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database.Stock
{
public class ReadStatusBalance : Connection
{
public ReadStatusBalance(string sqlConnectionString) : base(sqlConnectionString)
{
}
public int BySku(string sku, int statusId)
{
int statusBalance = new int();
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(@"
SELECT SUM(tblStockJournalPost.Quantity) AS Balance
FROM tblStockJournal INNER JOIN
tblStockJournalPost ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID INNER JOIN
tblStock ON tblStockJournal.StockID = tblStock.StockID INNER JOIN
tblSku ON tblStock.SkuID = tblSku.skuSkuID
WHERE (tblStockJournalPost.StockStatusID = @statusId) AND (tblSku.skuSkuNumber = @sku)
", conn))
{
// add parameters
cmd.Parameters.AddWithValue("@sku", sku);
cmd.Parameters.AddWithValue("@statusId", statusId);
// execute
object obj = cmd.ExecuteScalar();
if (obj == null || obj == DBNull.Value)
{
statusBalance = 0;
}
else
{
statusBalance = (int)obj;
}
}
}
return statusBalance;
}
public int ByStockNumber(int stockNumber, int statusId)
{
int statusBalance = new int();
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(@"
SELECT SUM(tblStockJournalPost.Quantity) AS Balance
FROM tblStockJournal INNER JOIN
tblStockJournalPost ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID INNER JOIN
tblStock ON tblStockJournal.StockID = tblStock.StockID
WHERE (tblStockJournalPost.StockStatusID = @statusId) AND (tblStock.StockNumber = @stockNumber)
", conn))
{
// add parameters
cmd.Parameters.AddWithValue("@stockNumber", stockNumber);
cmd.Parameters.AddWithValue("@statusId", statusId);
// execute
object obj = cmd.ExecuteScalar();
if (obj == null || obj == DBNull.Value)
{
statusBalance = 0;
}
else
{
statusBalance = (int)obj;
}
}
}
return statusBalance;
}
public int ByStockId(int stockId, int statusId)
{
int statusBalance = new int();
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(@"
SELECT
SUM(tblStockJournalPost.Quantity) AS Balance
FROM
tblStockJournal
INNER JOIN tblStockJournalPost
ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
WHERE
(tblStockJournal.StockID = @stockId )
AND (tblStockJournalPost.StockStatusID = @statusId )
", conn))
{
// add parameters
cmd.Parameters.AddWithValue("@stockId", stockId);
cmd.Parameters.AddWithValue("@statusId", statusId);
// execute
object obj = cmd.ExecuteScalar();
if (obj == null || obj == DBNull.Value)
{
statusBalance = 0;
}
else
{
statusBalance = (int)obj;
}
}
}
return statusBalance;
}
}
}

View File

@@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Dapper;
namespace bnhtrade.Core.Data.Database.Stock
{
public class ReadStatusTransaction : Connection
{
public ReadStatusTransaction(string sqlConnectionString) : base(sqlConnectionString)
{
}
/// <summary>
/// Returns a list with balance of stock avaiable by individual StockId
/// </summary>
/// <param name="skuNumber">SKU Number</param>
/// <param name="stockStatusId">Stock Status Database PK</param>
/// <returns></returns>
public List<(string SkuNumber, int StockNumber, int Balance)> BySkuNumber(string skuNumber, int stockStatusId)
{
var returnList = new List<(string SkuNumber, int StockNumber, int Balance)>();
if (string.IsNullOrWhiteSpace(skuNumber))
{
return returnList;
}
string strSQL = @"
SELECT tblSku.skuSkuNumber
,tblStock.StockNumber
,SUM(tblStockJournalPost.Quantity) AS Balance
FROM tblStockJournal
INNER JOIN tblStock ON tblStockJournal.StockID = tblStock.StockID
INNER JOIN tblStockJournalPost ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
INNER JOIN tblSku ON tblStock.SkuID = tblSku.skuSkuID
WHERE (tblStockJournalPost.StockStatusID = @stockStatusId)
AND (tblSku.skuSkuNumber = @skuNumber)
GROUP BY tblSku.skuSkuNumber
,tblStock.StockNumber
";
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(strSQL, conn))
{
// add parameters
cmd.Parameters.AddWithValue("@skuNumber", skuNumber);
cmd.Parameters.AddWithValue("@stockStatusId", stockStatusId);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
returnList.Add((
SkuNumber: reader.GetString(0),
StockNumber: reader.GetInt32(1),
Balance: reader.GetInt32(2)));
}
}
}
}
}
return returnList;
}
/// <summary>
/// Gets list of stock status debits and credits. Includes stock numbers with balance greater than or less than zero.
/// </summary>
/// <param name="stockStatusId">Required, filters results</param>
/// <param name="stockNumber">Required, filters results</param>
/// <returns>Tuple list is assending order</returns>
public Model.Stock.StatusTransaction ByStockNumber(int stockStatusId, int stockNumber)
{
var result = new Model.Stock.StatusTransaction();
result.StockStatusId = stockStatusId;
string strSQL = @"
SELECT a.StockNumber a.skuSkuNumber AS SkuNumber
FROM
(
SELECT tblSku.skuSkuNumber, tblStock.StockNumber, SUM(tblStockJournalPost.Quantity) AS Balance
FROM tblStockJournal INNER JOIN
tblStock ON tblStockJournal.StockID = tblStock.StockID INNER JOIN
tblStockJournalPost ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID INNER JOIN
tblSku ON tblStock.SkuID = tblSku.skuSkuID
WHERE (tblStockJournalPost.StockStatusID = @stockStatusId) AND (tblSku.skuSkuNumber IN @stockNumberList)
GROUP BY tblSku.skuSkuNumber, tblStock.StockNumber
) a
WHERE a.Balance <> 0
";
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(strSQL, conn))
{
var param = new Dapper.DynamicParameters();
param.Add("@stockStatusId", stockStatusId);
param.Add("@stockNumberList", stockNumber);
var dbresults = conn.Query(strSQL, param);
foreach (var item in dbresults)
{
result.Sku = item.SkuNumber;
result.AddBalanceTransaction(item.EntryDate, item.StockNumber, item.Quantity);
}
}
}
return result;
}
/// <summary>
/// Gets list of stock status debits and credits. Includes stock numbers with balance greater than or less than zero.
/// </summary>
/// <param name="stockStatusId">Required, filters results by stock status Id</param>
/// <param name="sku">Required, filters results by sku number</param>
/// <returns>Tuple list is assending order</returns>
public Model.Stock.StatusTransaction BySku(int stockStatusId, string sku)
{
var result = new Model.Stock.StatusTransaction();
result.Sku = sku;
result.StockStatusId = stockStatusId;
if (string.IsNullOrWhiteSpace(sku))
{
return result;
}
string strSQL = @"
SELECT tblStockJournal.EntryDate
,tblStockJournalPost.StockStatusID
,tblStock.StockNumber
,tblStockJournalPost.Quantity
FROM tblStockJournalPost
INNER JOIN tblStockJournal ON tblStockJournalPost.StockJournalID = tblStockJournal.StockJournalID
INNER JOIN tblStock ON tblStockJournal.StockID = tblStock.StockID
WHERE (tblStockJournalPost.StockStatusID = @stockStatusId)
AND (
tblStock.StockNumber IN (
SELECT a.StockNumber
FROM (
SELECT tblStock.StockNumber
,SUM(tblStockJournalPost.Quantity) AS Balance
FROM tblStockJournal
INNER JOIN tblStock ON tblStockJournal.StockID = tblStock.StockID
INNER JOIN tblStockJournalPost ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
INNER JOIN tblSku ON tblStock.SkuID = tblSku.skuSkuID
WHERE (tblStockJournalPost.StockStatusID = @stockStatusId)
AND (tblSku.skuSkuNumber = @sku)
GROUP BY tblSku.skuSkuNumber
,tblStock.StockNumber
) a
WHERE a.Balance <> 0
)
)
ORDER BY tblStockJournal.EntryDate
";
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(strSQL, conn))
{
var param = new Dapper.DynamicParameters();
param.Add("@stockStatusId", stockStatusId);
param.Add("@sku", sku);
var dbList = conn.Query(strSQL, param);
foreach (var item in dbList)
{
result.AddBalanceTransaction(item.EntryDate, item.StockNumber, item.Quantity);
}
}
}
return result;
}
}
}

View File

@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Dapper;
using bnhtrade.Core.Data.Database;
namespace bnhtrade.Core.Data.Database.Stock
{
public class ReadStockId : Connection
{
public ReadStockId(string sqlConnectionString) : base(sqlConnectionString)
{
}
/// <summary>
/// Tempory function to retrive the database stock ID/PK from a stock number. Reliance on a stock ID will
/// eventually be desgined out of the application
/// </summary>
/// <param name="stockNumberList">List of Stock Numbers to retrive from database</param>
/// <returns>Dictiony with Stock Number as Key and Stock ID as value</returns>
public Dictionary<int, int> ByStockNumber(List<int> stockNumberList)
{
var result = new Dictionary<int, int>();
string strSQL = @"
SELECT StockNumber, StockID
FROM tblStock
WHERE ";
var whereBuilder = new Database.SqlWhereBuilder();
whereBuilder.In("StockNumber", stockNumberList, strSQL);
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(whereBuilder.SqlWhereString, conn))
{
// add parameters
whereBuilder.AddParametersToSqlCommand(cmd);
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
result.Add(reader.GetInt32(0), reader.GetInt32(1));
}
}
return result;
}
}
}
}
}

View File

@@ -1,86 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace bnhtrade.Core.Logic.Stock
{
public class Reallocate
{
private string sqlConnectionString;
public Reallocate(string sqlConnectionString)
{
this.sqlConnectionString = sqlConnectionString;
}
public int StockReallocateByStockId(int journalTypeId, int stockId, int quantity, int debitStatusId, int creditStatusId,
DateTime entryDate = default(DateTime))
{
if (entryDate == default(DateTime))
{
entryDate = DateTime.Now;
}
// create the list
var posts = new List<(int statusId, int quantity)>();
posts.Add((debitStatusId, quantity));
posts.Add((creditStatusId, (quantity * -1)));
// execute
return Core.Stock.StockJournal.StockJournalInsert(sqlConnectionString, journalTypeId, stockId, posts, entryDate, false);
}
/// <summary>
/// Feed an skuId and quantity into function and the stock will be reallocated
/// </summary>
public List<(int StockJournalId, int Quantity)> StockReallocateBySkuNumber(int journalTypeId, string skuNumber, int quantity, int debitStatusId, int creditStatusId,
bool firstInFirstOut = true, DateTime entryDate = default(DateTime), bool reallocatePartialQuantity = false)
{
var returnList = new List<(int StockJournalId, int Quantity)>();
List<Tuple<int, DateTime, int>> list = Core.Stock.StockJournal.GetStockStatusBalanceBySkuNumber(sqlConnectionString, skuNumber, creditStatusId, entryDate, firstInFirstOut);
if (list == null || !list.Any())
{
return returnList;
}
// quantity check
int avaiableQuantity = 0;
foreach (Tuple<int, DateTime, int> item in list)
{
avaiableQuantity = avaiableQuantity + item.Item3;
}
if (avaiableQuantity < quantity && reallocatePartialQuantity == false)
{
return null;
}
// make the changes
using (TransactionScope scope = new TransactionScope())
{
foreach (Tuple<int, DateTime, int> item in list)
{
if (quantity > item.Item3)
{
int tempInt = StockReallocateByStockId(journalTypeId, item.Item1, item.Item3, debitStatusId, creditStatusId, entryDate);
quantity = quantity - item.Item3;
returnList.Add((tempInt, item.Item3));
}
else
{
int tempInt = StockReallocateByStockId(journalTypeId, item.Item1, quantity, debitStatusId, creditStatusId, entryDate);
returnList.Add((tempInt, quantity));
break;
}
}
scope.Complete();
return returnList;
}
}
}
}

View File

@@ -189,6 +189,26 @@ namespace bnhtrade.Core.Logic.Stock
return resultList;
}
/// <summary>
/// Retrive SKU Transaction by ID
/// </summary>
/// <param name="SkuTransactionId">SKU Transaction ID</param>
/// <param name="retriveTransactionTypeInfo"></param>
/// <returns></returns>
public List<Model.Stock.SkuTransaction> Read(List<int> SkuTransactionId, bool retriveTransactionTypeInfo = true)
{
var dbRead = new Data.Database.Stock.ReadSkuTransaction(sqlConnectionString);
var resultList = dbRead.Read(SkuTransactionId);
if (retriveTransactionTypeInfo)
{
var dbReadType = new Logic.Stock.SkuTransactionTypePersistance(sqlConnectionString);
dbReadType.GetBySkuTransaction(resultList);
}
return resultList;
}
/// <summary>
/// Validates and then updates a Stock SKU Tranaction
/// </summary>

View File

@@ -14,7 +14,7 @@ namespace bnhtrade.Core.Logic.Stock
private Logic.Stock.SkuTransactionPersistance dbSkuTransaction;
private Logic.Stock.SkuTransactionTypePersistance dbSkuTransactionType;
private Logic.Validate.SkuTransaction validateSkuTrans;
private Logic.Stock.Reallocate stockReallocate;
private Logic.Stock.StatusReallocate stockReallocate;
private Logic.Log.LogEvent logEvent;
private string err = "Reconcile Sku Transaction Exception: ";
@@ -26,7 +26,7 @@ namespace bnhtrade.Core.Logic.Stock
dbSkuTransactionType = new SkuTransactionTypePersistance(sqlConnectionString);
readShipmentInfo = new Data.Database.AmazonShipment.ReadShipmentInfo(sqlConnectionString);
validateSkuTrans = new Validate.SkuTransaction();
stockReallocate = new Logic.Stock.Reallocate(sqlConnectionString);
stockReallocate = new Logic.Stock.StatusReallocate(sqlConnectionString);
logEvent = new Log.LogEvent();
}
@@ -194,50 +194,52 @@ namespace bnhtrade.Core.Logic.Stock
}
// make the journal entries
var list = new List<(int StockJournalId, int Quantity)>();
var journalList = new List<(int StockJournalId, int Quantity)>();
if (transList[i].SkuTransactionType.FilterStockOnDateTime)
{
list = stockReallocate.StockReallocateBySkuNumber(
journalList = stockReallocate.BySkuNumber(
transList[i].TransactionDate,
transList[i].SkuTransactionType.StockJournalTypeId,
transList[i].SkuNumber,
transList[i].Quantity,
transList[i].SkuTransactionType.DebitStockStatusId.GetValueOrDefault(),
transList[i].SkuTransactionType.CreditStockStatusId.GetValueOrDefault(),
transList[i].SkuTransactionType.FirstInFirstOut,
transList[i].TransactionDate,
false);
true);
}
else
{
list = stockReallocate.StockReallocateBySkuNumber(
journalList = stockReallocate.BySkuNumber(
DateTime.UtcNow,
transList[i].SkuTransactionType.StockJournalTypeId,
transList[i].SkuNumber,
transList[i].Quantity,
transList[i].SkuTransactionType.DebitStockStatusId.GetValueOrDefault(),
transList[i].SkuTransactionType.CreditStockStatusId.GetValueOrDefault(),
transList[i].SkuTransactionType.FirstInFirstOut,
DateTime.UtcNow,
false);
true);
}
// insufficient balance available
if (list == null || !list.Any())
if (!journalList.Any())
{
// in special case (found inventory), continue
if (transList[i].SkuTransactionType.TypeCode.Contains("<AmazonReport><_GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA_><F>"))
{
ItemsCompleted++;
ItemsRemaining--;
continue;
}
else
{
ProgressMessage = "Insurficent status/location balance to relocate stock";
ProgressMessage = "Insurficent quantity at status/location to relocate stock";
recordSkip = recordSkip + 1;
break;
}
}
// fail safe
int qtyAllocated = list.Sum(c => c.Quantity);
int qtyAllocated = journalList.Sum(c => c.Quantity);
if (qtyAllocated > transList[i].Quantity)
{
throw new Exception(
@@ -248,40 +250,41 @@ namespace bnhtrade.Core.Logic.Stock
// update sku transaction table
int qtyRemain = qtyAllocated;
var newRecordList = new List<Model.Stock.SkuTransaction>();
for (int j = 0; j <= list.Count; j++)
for (int j = 0; j < journalList.Count; j++)
{
// update existing record
if (j == 0)
{
transList[i].Quantity = (short)list[j].Quantity;
transList[i].StockJournalId = list[j].StockJournalId;
transList[i].Quantity = (short)journalList[j].Quantity;
transList[i].StockJournalId = journalList[j].StockJournalId;
transList[i].IsProcessed = true;
dbSkuTransaction.Update(transList[i]);
}
// new record
else if (j < list.Count)
else
{
var newRecord = transList[i].Clone();
newRecord.Quantity = (short)list[j].Quantity;
newRecord.Quantity = (short)journalList[j].Quantity;
newRecord.IsProcessed = true;
newRecord.StockJournalId = list[j].StockJournalId;
newRecordList.Add(newRecord);
}
// new record, unallocated quantity
else if (qtyRemain > 0)
{
var newRecord = transList[i].Clone();
newRecord.Quantity = (short)qtyRemain;
newRecord.IsProcessed = false;
newRecord.StockJournalId = journalList[j].StockJournalId;
newRecordList.Add(newRecord);
}
if (j < list.Count)
{
qtyRemain = qtyRemain - list[j].Quantity;
}
qtyRemain = qtyRemain - journalList[j].Quantity;
}
// new record for unallocated quantity
if (qtyRemain > 0)
{
var newRecord = transList[i].Clone();
newRecord.Quantity = (short)qtyRemain;
newRecord.IsProcessed = false;
newRecordList.Add(newRecord);
}
// add new transactions to table
for (int j = 0; j < newRecordList.Count; j++)
{
@@ -448,7 +451,18 @@ namespace bnhtrade.Core.Logic.Stock
public void UnReconcileTransaction(int skuTransactionId)
{
dbSkuTransaction.DeleteJournalEntry(skuTransactionId);
var trans = dbSkuTransaction.Read(new List<int> { skuTransactionId }, false).FirstOrDefault();
if (trans == null) { return; }
// test if journal entry needs deleting, or just set to isprocessed = false
if (trans.IsProcessed == true && trans.IsSetStockJournalId)
{
dbSkuTransaction.DeleteJournalEntry(skuTransactionId);
}
else if (trans.IsProcessed == true)
{
new Data.Database.Stock.UpdateSkuTransaction(sqlConnectionString).Update(skuTransactionId, false);
}
}
}
}

View File

@@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Logic.Stock
{
public class StatusBalance
{
private string sqlConnectionString;
public StatusBalance(string sqlConnectionString)
{
this.sqlConnectionString = sqlConnectionString;
}
/// <summary>
/// Return the avaliable balance of a status. Uses a more efficent sql/code. However, balance requests should
/// generally also involve a date/time (i.e. the system does allow a stock transaction in the future, therefore
/// this method may give an available quantity, but transfers before that date wouod not be possible).
/// </summary>
/// <param name="sku">SKU number</param>
/// <param name="statusId">Status ID</param>
/// <returns>Balance as quantity</returns>
private int GetAvailableBalanceBySku(string sku, int statusId)
{
return new Data.Database.Stock.ReadStatusBalance(sqlConnectionString).BySku(sku, statusId);
}
/// <summary>
/// Return the avaliable balance of a status at a specified date and time. Useful for checking availability before
/// moving stock/sku retrospectivly
/// </summary>
/// <param name="sku">SKU number</param>
/// <param name="statusId">Status ID</param>
/// <param name="atDate">Date and time you would like to know the balance at</param>
/// <returns></returns>
public Model.Stock.StatusBalance GetBySku(string sku, int statusId)
{
if (string.IsNullOrWhiteSpace(sku))
{
throw new Exception("SKU number is null, empty, or whitespace");
}
// get list of transactions for availale stock
var stockTransaction = new Data.Database.Stock.ReadStatusTransaction(sqlConnectionString);
var transList = stockTransaction.BySku(statusId, sku);
// create quantity list
List<int> qtyList = new List<int>();
for (int i = 0; i < transList.TransactionList.Count; i++)
{
qtyList.Add(transList.TransactionList[i].Quantity);
}
// tally list
// loop, in reverse, to find credits to tally with debits
for (int iCr = qtyList.Count - 1; iCr > -1; iCr--)
{
if (qtyList[iCr] < 0)
{
int crStockNumber = transList.TransactionList[iCr].StockNumber;
DateTime crDate = transList.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
&& qtyList[iDr] > 0)
{
// credit fully assigned
if ((qtyList[iCr] + qtyList[iDr]) >= 0)
{
qtyList[iDr] = qtyList[iDr] + qtyList[iCr];
qtyList[iCr] = 0;
break;
}
// credit partially assigned
else
{
qtyList[iCr] = qtyList[iDr] + qtyList[iCr];
qtyList[iDr] = 0;
}
}
}
}
}
// build result list from tally results
var result = new Model.Stock.StatusBalance();
result.Sku = transList.Sku;
result.StockStatusId = transList.StockStatusId;
for (int i = 0; i < qtyList.Count; i++)
{
if (qtyList[i] != 0)
{
result.AddBalanceTransaction(
transList.TransactionList[i].EntryDate,
transList.TransactionList[i].StockNumber,
qtyList[i]);
}
}
return result;
}
}
}

View File

@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace bnhtrade.Core.Logic.Stock
{
public class StatusReallocate
{
private string sqlConnectionString;
public StatusReallocate(string sqlConnectionString)
{
this.sqlConnectionString = sqlConnectionString;
}
/// <summary>
/// Reallocates stock between status' by Stock Id
/// </summary>
/// <param name="journalTypeId"></param>
/// <param name="stockId"></param>
/// <param name="quantity"></param>
/// <param name="debitStatusId"></param>
/// <param name="creditStatusId"></param>
/// <param name="entryDate"></param>
/// <returns>Return newly created stock journal Id</returns>
public int ByStockId(DateTime entryDate, int journalTypeId, int stockId, int quantity, int debitStatusId, int creditStatusId)
{
if (entryDate == default(DateTime))
{
entryDate = DateTime.Now;
}
// create the list
var posts = new List<(int statusId, int quantity)>();
posts.Add((debitStatusId, quantity));
posts.Add((creditStatusId, (quantity * -1)));
// execute
return Core.Stock.StockJournal.StockJournalInsert(sqlConnectionString, journalTypeId, stockId, posts, entryDate, false);
}
/// <summary>
/// Feed an SKU number and quantity into function and the stock will be reallocated
/// </summary>
/// <param name="entryDate">Date and time of the transaction</param>
/// <param name="journalTypeId">Journal Type ID</param>
/// <param name="skuNumber">Sku Number to reallocate</param>
/// <param name="quantity">Quantity to reallocate</param>
/// <param name="debitStatusId">Status to move SKU to</param>
/// <param name="creditStatusId">Status to move SKU from</param>
/// <param name="firstInFirstOut">Move stock on first in first out basis</param>
/// <param name="reallocatePartialQuantity">Reallocate patial quantity if the full quantity is not available</param>
/// <returns></returns>
public List<(int StockJournalId, int Quantity)> BySkuNumber(DateTime entryDate, int journalTypeId, string skuNumber, int quantity, int debitStatusId, int creditStatusId,
bool firstInFirstOut = true, bool reallocatePartialQuantity = false)
{
var returnList = new List<(int StockJournalId, int Quantity)>();
// get balance of status and check for avaliable quantity
var statusBalance = new Logic.Stock.StatusBalance(sqlConnectionString).GetBySku(skuNumber, creditStatusId);
if (statusBalance.GetAvaliableQuantity(entryDate) <= 0
|| (statusBalance.CheckAvaliableQuantity(quantity, entryDate) == false && reallocatePartialQuantity == false
))
{
return returnList;
}
// temp code start
// until use of stockId is designed out of application
var getStockId = new Data.Database.Stock.ReadStockId(sqlConnectionString);
var stockIdDictionary = new Dictionary<int, int>();
foreach (var item in statusBalance.ByDateList)
{
if (!stockIdDictionary.ContainsKey(item.StockNumber))
{
stockIdDictionary.Add(item.StockNumber, 0);
}
}
stockIdDictionary = getStockId.ByStockNumber(stockIdDictionary.Keys.ToList());
// temp code finish
//make the changes
using (TransactionScope scope = new TransactionScope())
{
foreach (var item in statusBalance.ByDateList)
{
if (quantity > item.Quantity)
{
int journalId = ByStockId(entryDate, journalTypeId, stockIdDictionary[item.StockNumber], item.Quantity, debitStatusId, creditStatusId);
quantity = quantity - item.Quantity;
returnList.Add((journalId, item.Quantity));
}
else
{
int journalId = ByStockId(entryDate, journalTypeId, stockIdDictionary[item.StockNumber], quantity, debitStatusId, creditStatusId);
returnList.Add((journalId, quantity));
break;
}
}
scope.Complete();
return returnList;
}
}
}
}

View File

@@ -1,17 +1,16 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Model.Stock
{
public class JournalEntry
public class JournalEntry : IValidatableObject
{
public string TypeTitle { get; set; }
public int StockId { get; set; }
public int StockNumber { get; set; }
public DateTime EntryDate { get; set; }
@@ -21,5 +20,25 @@ namespace bnhtrade.Core.Model.Stock
public DateTime LastModified { get; set; }
public bool IsLocked { get; set; }
public List<JournalEntryPost> JournalPosts { get; set; } = new List<JournalEntryPost>();
public class JournalEntryPost
{
public int JournalPostId { get; set; }
public int StockStatusId { get; set; }
[Required()]
public string StockStatus { get; set; }
[Required()]
public int Quantity { get; set; }
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Model.Stock
{
public class JournalEntryPost : IValidatableObject
{
public int JournalPostId { get; set; }
public int StockStatusId { get; set; }
[Required()]
public string StockStatus { get; set; }
[Required()]
public int Quantity { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
throw new NotImplementedException();
var resultList = new List<ValidationResult>();
if (Quantity == 0)
{
resultList.Add(new ValidationResult("Quantity must be greater than, or less than, zero"));
}
}
}
}

View File

@@ -200,10 +200,10 @@ namespace bnhtrade.Core.Model.Stock
{
result.Add(new ValidationResult("Quantity is not set"));
}
if (!IsSetSkuTransactionId)
{
result.Add(new ValidationResult("Stock Transaction Id is not set"));
}
//if (!IsSetSkuTransactionId)
//{
// result.Add(new ValidationResult("Stock Transaction Id is not set"));
//}
if (IsSetStockJournalId && (!IsSetIsProcessed || IsProcessed == false))
{
result.Add(new ValidationResult("Stock Journal Id is set, IsProcessed must be set to true"));

View File

@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Model.Stock
{
public class StatusBalance
{
public int StockStatusId { get; set; }
public string Sku { get; set; }
public List<ByDate> ByDateList { get; private set; } = new List<ByDate>();
public class ByDate
{
public DateTime EntryDate { get; set; }
public int StockNumber { get; set; }
public int Quantity { get; set; }
}
public void AddBalanceTransaction(DateTime entryDate, int stockNumber, int quantity)
{
if (entryDate == new DateTime())
{
throw new Exception("Entry date set to default value");
}
var item = new ByDate();
item.EntryDate = entryDate;
item.StockNumber = stockNumber;
item.Quantity = quantity;
if (ByDateList == null) { ByDateList = new List<ByDate>(); }
if (ByDateList.Count == 0 || ByDateList.Last().EntryDate <= item.EntryDate)
{
ByDateList.Add(item);
}
else
{
for (int i = 0; i < ByDateList.Count; i++)
{
if (entryDate <= ByDateList[i].EntryDate)
{
i++;
ByDateList.Insert(i, item);
}
}
}
}
public bool CheckAvaliableQuantity(int quantity, DateTime onDateTime)
{
if (GetAvaliableQuantity(onDateTime) < quantity)
{
return false;
}
else
{
return true;
}
}
public int GetAvaliableQuantity()
{
if (!ByDateList.Any())
{
return 0;
}
int qty = 0;
for (int i = 0; i < ByDateList.Count; i++)
{
qty += ByDateList[i].Quantity;
}
return qty;
}
public int GetAvaliableQuantity(DateTime onDateTime)
{
if (!ByDateList.Any())
{
return 0;
}
int qty = 0;
for (int i = 0; i < ByDateList.Count; i++)
{
if (ByDateList[i].EntryDate <= onDateTime)
{
qty += ByDateList[i].Quantity;
}
}
return qty;
}
}
}

View File

@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Model.Stock
{
public class StatusTransaction
{
public int StockStatusId { get; set; }
public string Sku { get; set; }
public int Balance
{
get
{
if (TransactionList.Any())
{
return TransactionList.Sum(x => x.Quantity);
}
else
{
return 0;
}
}
}
public List<Transaction> TransactionList { get; private set; } = new List<Transaction>();
public class Transaction
{
public DateTime EntryDate { get; set; }
public int StockNumber { get; set; }
public int Quantity { get; set; }
}
public void AddBalanceTransaction(DateTime entryDate, int stockNumber, int quantity)
{
if (entryDate == new DateTime())
{
throw new Exception("Entry date set to default value");
}
var item = new Transaction();
item.EntryDate = entryDate;
item.StockNumber = stockNumber;
item.Quantity = quantity;
if (TransactionList == null) { TransactionList = new List<Transaction>(); }
if (TransactionList.Count == 0 || TransactionList.Last().EntryDate <= item.EntryDate )
{
TransactionList.Add(item);
}
else
{
for (int i = 0; i < TransactionList.Count; i++)
{
if (entryDate <= TransactionList[i].EntryDate)
{
i++;
TransactionList.Insert(i, item);
}
}
}
}
}
}

View File

@@ -1665,7 +1665,7 @@ namespace bnhtrade.Core
{
public class StockCreate
{
private static int WIP_StockInsert(string sqlConnectionString, int accountJournalType, int stockJournalType, string currencyCode, decimal amount,
private int WIP_StockInsert(string sqlConnectionString, int accountJournalType, int stockJournalType, string currencyCode, decimal amount,
int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId)
{
using (TransactionScope scope = new TransactionScope())
@@ -1677,7 +1677,7 @@ namespace bnhtrade.Core
int accountJournalId = Account.AccountQuery.AccountJournalInsert(sqlConnectionString, accountJournalType, entryDate, currencyCode, amount);
// make the stock insert
int stockId = StockCreate.WIP_StockInsertSub(sqlConnectionString, productId, conditionId, accountTaxCodeId,
int stockId = WIP_StockInsertSub(sqlConnectionString, productId, conditionId, accountTaxCodeId,
accountJournalId, stockJournalType, entryDate, quantity, debitStatusId);
scope.Complete();
@@ -1685,7 +1685,7 @@ namespace bnhtrade.Core
}
}
private static int WIP_StockInsertSub(string sqlConnectionString, int productId, int conditionId, int accountTaxCodeId,
private int WIP_StockInsertSub(string sqlConnectionString, int productId, int conditionId, int accountTaxCodeId,
int accountJournalId, int stockJournalTypeId, DateTime stockJournalEntryDate, int quantity, int statusDebitId)
{
stockJournalEntryDate = DateTime.SpecifyKind(stockJournalEntryDate, DateTimeKind.Utc);
@@ -2073,8 +2073,7 @@ namespace bnhtrade.Core
stockJournalEntryDate = DateTime.SpecifyKind((DateTime)cmd.ExecuteScalar(), DateTimeKind.Utc);
}
}
return WIP_StockInsertSub(sqlConnectionString, productId, conditionId, accountTaxCodeId, accountJournalId, stockJournalTypeId, stockJournalEntryDate, quantity, statusDebitId);
return new Stock.StockCreate().WIP_StockInsertSub(sqlConnectionString, productId, conditionId, accountTaxCodeId, accountJournalId, stockJournalTypeId, stockJournalEntryDate, quantity, statusDebitId);
}
public static int WIP_StockInsertOwnerIntroduced(string sqlConnectionString, decimal amount, int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId)
@@ -2083,7 +2082,7 @@ namespace bnhtrade.Core
int stockJournalType = 2;
string currencyCode = "GBP";
return WIP_StockInsert(sqlConnectionString, accountJournalType, stockJournalType, currencyCode, amount, quantity, productId, conditionId, accountTaxCodeId, entryDate, debitStatusId);
return new Stock.StockCreate().WIP_StockInsert(sqlConnectionString, accountJournalType, stockJournalType, currencyCode, amount, quantity, productId, conditionId, accountTaxCodeId, entryDate, debitStatusId);
}
public static void WIP_StockDeletePurchase(string sqlConnectionString, int stockId)
@@ -2463,7 +2462,7 @@ namespace bnhtrade.Core
{
if (item.Value < 0 && dicStatusIsCreditOnly[item.Key] == false)
{
int quantity = Stock.StockJournal.StockStatusBalanceByStockId(conn.ConnectionString, stockId, item.Key);
int quantity = new Data.Database.Stock.ReadStatusBalance(conn.ConnectionString).ByStockId(stockId, item.Key);
if (quantity + item.Value < 0)
{
@@ -2689,132 +2688,6 @@ namespace bnhtrade.Core
return true;
}
public static int StockStatusBalanceByStockId(string sqlConnectionString, int stockId, int statusId)
{
int statusBalance = new int();
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(@"
SELECT
SUM(tblStockJournalPost.Quantity) AS Balance
FROM
tblStockJournal
INNER JOIN tblStockJournalPost
ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
WHERE
(tblStockJournal.StockID = @stockId )
AND (tblStockJournalPost.StockStatusID = @statusId )
", conn))
{
// add parameters
cmd.Parameters.AddWithValue("@stockId", stockId);
cmd.Parameters.AddWithValue("@statusId", statusId);
// execute
object obj = cmd.ExecuteScalar();
if (obj == null || obj == DBNull.Value)
{
statusBalance = 0;
}
else
{
statusBalance = (int)obj;
}
}
}
return statusBalance;
}
// Function returns a list with balance of stock avaiable by individual stockId ordered by earliest added to status (stock journal entrydate)
// beforeDate - used to filter results, useful when reallocating stock retrospectivly (i.e. avoid case were stock is
// moved out of status, ahead of it being moved into that status) -- really this should be the calling function that does this!!
public static List<Tuple<int, DateTime, int>> GetStockStatusBalanceBySkuNumber
(string sqlConnectionString, string skuNumber, int stockStatusId, DateTime? maxDateUtc = null, bool sortAgeAscending = true)
{
//build sql statement
string strSQL = @"
SELECT a.JournalDate
,a.balance
,a.stockID
FROM (
SELECT MIN(tblStockJournal.EntryDate) AS JournalDate
,SUM(tblStockJournalPost.Quantity) AS Balance
,tblStock.StockID
FROM tblStockJournal
INNER JOIN tblStock ON tblStockJournal.StockID = tblStock.StockID
INNER JOIN tblStockJournalPost ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
INNER JOIN tblSku ON tblStock.SkuID = tblSku.skuSkuID
WHERE (tblStockJournalPost.StockStatusID = @stockStatusId)
AND (tblSku.skuSkuNumber = @skuNumber)
GROUP BY tblStock.StockID
HAVING (SUM(tblStockJournalPost.Quantity) > 0)
) a ";
if (maxDateUtc != null)
{
strSQL = strSQL + @"
WHERE a.JournalDate <= @beforeDateUtc
";
}
strSQL = strSQL + @"
ORDER BY a.JournalDate;
";
try
{
using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString))
{
sqlConn.Open();
using (SqlCommand cmd = new SqlCommand(strSQL, sqlConn))
{
// add parameters
cmd.Parameters.AddWithValue("@skuNumber", skuNumber);
cmd.Parameters.AddWithValue("@stockStatusId", stockStatusId);
if (maxDateUtc != null)
{ cmd.Parameters.AddWithValue("@beforeDateUtc", maxDateUtc.Value.ToUniversalTime()); }
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
List<Tuple<int, DateTime, int>> list = new List<Tuple<int, DateTime, int>>();
int index01 = reader.GetOrdinal("StockID");
int index02 = reader.GetOrdinal("JournalDate");
int index03 = reader.GetOrdinal("Balance");
while (reader.Read())
{
int stockId = reader.GetInt32(index01);
DateTime journalDate = reader.GetDateTime(index02);
int balance = reader.GetInt32(index03);
journalDate = DateTime.SpecifyKind(journalDate, DateTimeKind.Utc);
list.Add(new Tuple<int, DateTime, int>(stockId, journalDate, balance));
}
if (sortAgeAscending == false)
{
list.Reverse();
}
return list;
}
else
{
return null;
}
}
}
}
}
catch (Exception)
{
throw;
}
}
public static int GetStockIdByStockJournalId(string sqlConnectionString, int stockJournalId)
{
try
@@ -7766,111 +7639,4 @@ namespace bnhtrade.Core
return fullPath;
}
}
public class TempFunction
{
public void UpdateSkuCost(string sqlConnectionString)
{
MiscFunction.EventLogInsert("Starting temp function UpdateSkuCost()");
int count = 0;
try
{
using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString))
{
sqlConn.Open();
using (SqlCommand cmd01 = sqlConn.CreateCommand())
{
//query for list of all sku's with stock
cmd01.CommandText = @"
SELECT sku, [mfn-fulfillable-quantity], [afn-total-quantity]
FROM tblImportFbaManageInventory
WHERE ( [mfn-fulfillable-quantity] > 0 ) OR ( [afn-total-quantity] > 0 )
";
using (SqlDataReader reader01 = cmd01.ExecuteReader())
{
// retrive index of columns for faster operation
int indexOfColumn1 = reader01.GetOrdinal("sku");
int indexOfColumn2 = reader01.GetOrdinal("mfn-fulfillable-quantity");
int indexOfColumn3 = reader01.GetOrdinal("afn-total-quantity");
while (reader01.Read())
{
count = count + 1;
Console.Write("\rProcessing record #" + count);
//assign values
string skuNumber = reader01.GetString(indexOfColumn1);
int mfnTotal;
if (reader01.IsDBNull(indexOfColumn2)) { mfnTotal = 0; }
else { mfnTotal = reader01.GetInt32(indexOfColumn2); }
int afnTotal;
if (reader01.IsDBNull(indexOfColumn3)) { afnTotal = 0; }
else { afnTotal = reader01.GetInt32(indexOfColumn3); }
int total = mfnTotal + afnTotal;
//query for average unit cost
using (SqlCommand cmd02 = new SqlCommand(@"
SELECT AVG(Q.UnitCost) AS AvgCost
FROM(
SELECT TOP (@total) UnitQuantity, n, UnitCost
FROM(tblNumbers INNER JOIN tblStock ON n <= UnitQuantity) INNER JOIN tblSku ON SkuID = skuSkuID
WHERE(skuSkuNumber = @skuNumber)
ORDER BY StockID DESC
) Q
", sqlConn))
{
cmd02.Parameters.AddWithValue("@total", total);
cmd02.Parameters.AddWithValue("@skuNumber", skuNumber);
decimal AvgCost = 0;
object obj = cmd02.ExecuteScalar();
if (obj == null || obj == DBNull.Value)
{
AvgCost = 0;
}
else
{
AvgCost = Convert.ToDecimal(obj);
}
AvgCost = Math.Round(AvgCost, 2);
//Console.WriteLine(skuNumber + " " + AvgCost);
//update sku table
using (SqlCommand cmd03 = sqlConn.CreateCommand())
{
cmd03.Parameters.AddWithValue("@skuNumber", skuNumber);
cmd03.Parameters.AddWithValue("@AvgCost", AvgCost);
cmd03.Parameters.AddWithValue("@timeStamp", DateTime.UtcNow);
Console.Write(" £" + AvgCost );
cmd03.CommandText =
"UPDATE tblSku " +
"SET skuSkuAvgCost = @AvgCost, skuSkuAvgCostUpdate = @timeStamp " +
"WHERE skuSkuNumber = @skuNumber;";
cmd03.ExecuteNonQuery();
}
}
}
}
}
Console.Write("\r");
MiscFunction.EventLogInsert("UpdateSkuCost() operation complete. " + count + " total SKU average cost(s) updated");
}
}
catch (Exception ex)
{
MiscFunction.EventLogInsert("UpdateSkuCost() operation exceltion. See 'details' for further information.", 1, ex.ToString());
Console.WriteLine(ex.ToString());
}
}
}
}

View File

@@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Test.COM
{
class COMClassLib
{
}
}

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Test.Stock
{
public class Stock
{
private string sqlConnectionString;
public Stock(string sqlConnectionString)
{
this.sqlConnectionString = sqlConnectionString;
// method you want to start here
UnreconcileSkuTrnasction(79808);
}
public void ReadStatusBalance()
{
var result = new bnhtrade.Core.Data.Database.Stock.ReadStatusTransaction(sqlConnectionString)
.ByStockNumber(12, 5839);
}
public void StatusBalance()
{
string sku = "003190-10";
int statusId = 12; // fba sold
var atDate = new DateTime(2017, 02, 01, 21, 54, 30);
DateTime.TryParse("22/12/2017 16:35:58", out atDate);
var result = new Core.Logic.Stock.StatusBalance(sqlConnectionString).GetBySku(sku, statusId);
}
public void ReadStockId()
{
List<int> idList = new List<int>();
idList.Add(123);
idList.Add(333);
idList.Add(1788);
var result = new Data.Database.Stock.ReadStockId(sqlConnectionString).ByStockNumber(idList);
}
public void SkuTransactionAdd()
{
var trans = new bnhtrade.Core.Model.Stock.SkuTransaction();
trans.IsProcessed = false;
trans.Quantity = 1;
//trans.Reference
trans.SkuNumber = "005642-41";
trans.SkuTransactionTypeCode = "ManualAdjustment005";
//trans.StockJournalId;
trans.TransactionDate = new DateTime(2020, 01, 29, 17, 00, 00);
new bnhtrade.Core.Logic.Stock.SkuTransactionPersistance(sqlConnectionString).Create(trans);
}
public void UnreconcileSkuTrnasction(int transactoinId)
{
new bnhtrade.Core.Logic.Stock.SkuTransactionReconcile(sqlConnectionString).UnReconcileTransaction(transactoinId);
}
}
}

View File

@@ -105,13 +105,17 @@
<Compile Include="Data\Database\Stock\DeleteSkuTransaction.cs" />
<Compile Include="Data\Database\Stock\ReadSkuTransaction.cs" />
<Compile Include="Data\Database\Stock\ReadSkuTransactionType.cs" />
<Compile Include="Data\Database\Stock\ReadStatusBalance.cs" />
<Compile Include="Data\Database\Stock\ReadStatusTransaction.cs" />
<Compile Include="Data\Database\Stock\ReadStockId.cs" />
<Compile Include="Data\Database\Stock\UpdateSkuTransaction.cs" />
<Compile Include="Data\Database\WhereBuilder.cs" />
<Compile Include="Data\Database\SqlWhereBuilder.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="Logic\Account\GetAccountCodeInfo.cs" />
<Compile Include="Logic\Account\GetInvoiceLineItem.cs" />
<Compile Include="Logic\Account\TaxCalculation.cs" />
<Compile Include="Logic\Account\GetTaxCodeInfo.cs" />
<Compile Include="Logic\Stock\StatusBalance.cs" />
<Compile Include="Logic\Validate\AccountCode.cs" />
<Compile Include="Logic\Validate\CurrencyCode.cs" />
<Compile Include="Logic\Validate\SalesInvoice.cs" />
@@ -120,7 +124,7 @@
<Compile Include="Logic\Export\AmazonSubmitFile.cs" />
<Compile Include="Logic\Export\AmazonSubmitFileStatus.cs" />
<Compile Include="Logic\Sku\GetSkuConditionInfo.cs" />
<Compile Include="Logic\Stock\Reallocate.cs" />
<Compile Include="Logic\Stock\StatusReallocate.cs" />
<Compile Include="Logic\Stock\SkuTransactionReconcile.cs" />
<Compile Include="Logic\Stock\SkuTransactionPersistance.cs" />
<Compile Include="Logic\Stock\SkuTransactionTypePersistance.cs" />
@@ -161,12 +165,12 @@
<Compile Include="Model\Sku\Price\SkuPriceParameter.cs" />
<Compile Include="Model\Sku\SkuConditionInfo.cs" />
<Compile Include="Model\Stock\JournalEntry.cs" />
<Compile Include="Model\Stock\JournalEntryPost.cs" />
<Compile Include="Model\Stock\SkuTransactionType.cs" />
<Compile Include="Model\Stock\SkuTransaction.cs" />
<Compile Include="Model\Stock\StatusBalance.cs" />
<Compile Include="Model\Stock\StatusTransaction.cs" />
<Compile Include="Test\Account\Account.cs" />
<Compile Include="Test\AutoExec.cs" />
<Compile Include="Test\COM\COMClassLib.cs" />
<Compile Include="Test\Export\Export.cs" />
<Compile Include="Test\Import\AmazonSettlement.cs" />
<Compile Include="Test\InboundShipmentInfo.cs" />
@@ -178,6 +182,7 @@
<Compile Include="Test\SQLLoop.cs" />
<Compile Include="Model\AmazonFba\ShipmentInfo.cs" />
<Compile Include="Model\Sku\Sku.cs" />
<Compile Include="Test\Stock\Stock.cs" />
<Compile Include="Test\_BoilerPlate\ClassFromSql.cs" />
<Compile Include="Test\_BoilerPlate\Sql.cs" />
<Compile Include="UI\Console\ProgressBar.cs" />

View File

@@ -289,7 +289,7 @@ namespace bnhtradeScheduledTasks
Console.WriteLine("<4> Test Import");
Console.WriteLine("<5> Test Logic");
Console.WriteLine("<6> Test SKU");
Console.WriteLine("<7> Test COM Class");
Console.WriteLine("<7> Test Stock");
Console.WriteLine("<8> Test xxxxxxx");
Console.WriteLine("<9> Detele Sku Transaction 'n'");
Console.WriteLine();
@@ -366,14 +366,7 @@ namespace bnhtradeScheduledTasks
{
Console.Clear();
//string conString = ConfigurationManager.ConnectionStrings["bnhtradeDbConnString"].ConnectionString;
//var builder = new SqlConnectionStringBuilder(conString);
//var cred = new bnhtrade.ComTypeLib.Credential.ConnectionCredential();
//cred.Password = builder.Password;
//cred.UserId = builder.UserID;
//var obj = new bnhtrade.ComTypeLib.Stock().ReconcileStockTransactions(cred);
new bnhtrade.Core.Test.Stock.Stock(sqlConnectionString);
Console.WriteLine("Done");
Console.WriteLine("Complete, press any key to continue...");