diff --git a/src/bnhtrade.ComTypeLib/Stock/Stock.cs b/src/bnhtrade.ComTypeLib/Stock/Stock.cs
index e9d6fe9..340afbf 100644
--- a/src/bnhtrade.ComTypeLib/Stock/Stock.cs
+++ b/src/bnhtrade.ComTypeLib/Stock/Stock.cs
@@ -70,7 +70,7 @@ namespace bnhtrade.ComTypeLib
public void StockJournalDelete(ConnectionCredential sqlConnCred, int stockJournalId)
{
- Core.Stock.StockJournal.StockJournalDelete(sqlConnCred.ConnectionString, stockJournalId);
+ new Core.Logic.Inventory.StockJournalService().StockJournalDelete(stockJournalId);
}
public object ReconcileStockTransactions(ConnectionCredential sqlConnCred)
@@ -128,7 +128,7 @@ namespace bnhtrade.ComTypeLib
public bool StockJournalConsistencyCheck(ConnectionCredential sqlConnCred, int stockId)
{
- return Core.Stock.StockJournal.WIP_StockJournalConsistencyCheck(sqlConnCred.ConnectionString, stockId, null);
+ return new Core.Logic.Inventory.StockJournalService().WIP_StockJournalConsistencyCheck(stockId, null);
}
public void SkuTransactionAdd(ConnectionCredential sqlConnCred, int quantity, string skuNumber, string transactionTypeCode, DateTime transactionDate)
diff --git a/src/bnhtrade.Core/Data/Database/Repository/Implementation/AccountJournalRepository.cs b/src/bnhtrade.Core/Data/Database/Repository/Implementation/AccountJournalRepository.cs
index ab4c3ca..167d264 100644
--- a/src/bnhtrade.Core/Data/Database/Repository/Implementation/AccountJournalRepository.cs
+++ b/src/bnhtrade.Core/Data/Database/Repository/Implementation/AccountJournalRepository.cs
@@ -383,12 +383,47 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
return returnList;
}
+ public DateTime ReadJournalEntryDate(int journalId)
+ {
+ if (journalId <= 0)
+ {
+ throw new ArgumentException("Invalid journal ID provided.", nameof(journalId));
+ }
+
+ string sql = @"
+ SELECT tblAccountJournal.EntryDate
+ FROM tblAccountJournal
+ WHERE (((tblAccountJournal.AccountJournalID)=@accountJournalId));";
+
+ using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
+ {
+ cmd.CommandText = sql;
+ cmd.Transaction = _transaction as SqlTransaction;
+
+ cmd.Parameters.AddWithValue("@accountJournalId", journalId);
+
+ object obj = cmd.ExecuteScalar();
+
+ if (obj == null)
+ {
+ throw new Exception("Journal entry not found for AccountJournalID=" + journalId);
+ }
+
+ return DateTime.SpecifyKind((DateTime)obj, DateTimeKind.Utc);
+ }
+ }
+
///
/// Test for locked journal entry
///
/// False on locked journal entry
public bool ReadJournalIsLocked(int journalId)
{
+ if (journalId <= 0)
+ {
+ throw new ArgumentException("Invalid journal ID provided.", nameof(journalId));
+ }
+
string sql = @"
SELECT
tblAccountJournal.IsLocked
diff --git a/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockJournalRepository.cs b/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockJournalRepository.cs
index 58aa142..15d7c18 100644
--- a/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockJournalRepository.cs
+++ b/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockJournalRepository.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
+using static bnhtrade.Core.Data.Database.Constants;
namespace bnhtrade.Core.Data.Database.Repository.Implementation
{
@@ -118,7 +119,7 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
// insert journal posts into database
//new Data.Database.Stock
- Core.Stock.StockJournal.StockJournalPostInsert(conn, stockId, stockJournalId, journalPosts, isNewStock);
+ StockJournalPostInsert(stockId, stockJournalId, journalPosts, isNewStock);
// consistency check
bool consistencyResult = true;
@@ -158,6 +159,30 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
// Read
//
+ public int ReadJournalTypeIdByStockId(int stockId)
+ {
+ using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
+ {
+ cmd.Transaction = _transaction as SqlTransaction;
+ cmd.CommandText = @"
+ SELECT tblStockJournal.StockJournalTypeID
+ FROM tblStock INNER JOIN
+ tblStockJournal ON tblStock.StockJournalID = tblStockJournal.StockJournalID
+ WHERE (tblStock.StockID = @stockId);";
+
+ cmd.Parameters.AddWithValue("@stockId", stockId);
+
+ object obj = cmd.ExecuteScalar();
+
+ if (obj == null || obj == DBNull.Value)
+ {
+ throw new Exception("No stock journal type found for StockID=" + stockId);
+ }
+
+ return (int)obj;
+ }
+ }
+
public int ReadStatusBalanceBySku(string sku, int statusId)
{
int statusBalance = new int();
@@ -255,6 +280,22 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
return statusBalance;
}
+ public int ReadJournalEntryCountByStockId(int stockId)
+ {
+ using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
+ {
+ cmd.Transaction = _transaction as SqlTransaction;
+ cmd.CommandText = @"
+ SELECT Count(tblStockJournal.StockJournalID) AS CountOfStockJournalID
+ FROM tblStockJournal
+ WHERE (((tblStockJournal.StockID)=@stockId));";
+
+ cmd.Parameters.AddWithValue("@stockId", stockId);
+
+ return (int)cmd.ExecuteScalar();
+ }
+ }
+
//
// update
//
diff --git a/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockRepository.cs b/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockRepository.cs
index 1014ac8..4fe9bed 100644
--- a/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockRepository.cs
+++ b/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockRepository.cs
@@ -1,12 +1,13 @@
-using bnhtrade.Core.Data.Database._BoilerPlate;
-using bnhtrade.Core.Data.Database.Repository.Interface;
-using Microsoft.Data.SqlClient;
+using bnhtrade.Core.Data.Database.Repository.Interface;
+using bnhtrade.Core.Data.Database.UnitOfWork;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using System.Transactions;
+using static System.Formats.Asn1.AsnWriter;
namespace bnhtrade.Core.Data.Database.Repository.Implementation
{
@@ -16,126 +17,424 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
{
}
- public List ReadStatus(List statusIds = null, List statusTypeIds = null)
+ //
+ // create
+ //
+
+ public int WIP_StockInsertSub(int productId, int conditionId, int accountTaxCodeId,
+ int accountJournalId, int stockJournalTypeId, DateTime stockJournalEntryDate, int quantity, int statusDebitId)
{
- var sqlBuilder = new SqlWhereBuilder();
- var returnList = new List();
+ stockJournalEntryDate = DateTime.SpecifyKind(stockJournalEntryDate, DateTimeKind.Utc);
- //build sql query
- string sql = @"
- SELECT [StockStatusID]
- ,[StatusCode]
- ,[StockStatus]
- ,[StockStatusTypeID]
- ,[Reference]
- ,[ForeignKeyID]
- ,[IsCreditOnly]
- ,[IsClosed]
- ,[RecordCreated]
- FROM [e2A].[dbo].[tblStockStatus]
- WHERE 1=1 ";
+ // ensure account journal id hasn't already been added to stock table
+ int count = 0;
- // build the where statments
- if (statusIds.Any())
+ using (SqlCommand cmd = new SqlCommand(@"
+ SELECT Count(tblStock.StockID) AS CountOfID
+ FROM tblStock
+ WHERE (((tblStock.AccountJournalID)=@accountJouranlId));
+ ", conn))
{
- sqlBuilder.In("StockStatusID", statusIds, "AND");
- }
- if (statusTypeIds.Any())
- {
- sqlBuilder.In("StockStatusTypeID", statusTypeIds, "AND");
+ cmd.Parameters.AddWithValue("@accountJouranlId", accountJournalId);
+
+ count = (int)cmd.ExecuteScalar();
}
- // append where string to the sql
- if (sqlBuilder.IsSetSqlWhereString)
+ if (count == 1)
{
- sql = sql + sqlBuilder.SqlWhereString;
+ 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.");
}
- using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
+ // ensure the debit for the account journal transaction is to an 'Asset' account type
+ using (SqlCommand cmd = new SqlCommand(@"
+ SELECT
+ Count(tblAccountJournalPost.AccountJournalPostID) AS CountOfAccountJournalPostID
+ FROM
+ (tblAccountJournalPost
+ INNER JOIN tblAccountChartOf
+ ON tblAccountJournalPost.AccountChartOfID = tblAccountChartOf.AccountChartOfID)
+ INNER JOIN tblAccountChartOfType
+ ON tblAccountChartOf.AccountChartOfTypeID = tblAccountChartOfType.AccountChartOfTypeID
+ WHERE
+ tblAccountJournalPost.AmountGbp>=0
+ AND tblAccountChartOfType.BasicType='Asset'
+ AND tblAccountJournalPost.AccountJournalID=@accountJournalId;
+ ", conn))
{
- cmd.CommandText = sql;
- cmd.Transaction = _transaction as SqlTransaction;
+ cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
- if (sqlBuilder.ParameterListIsSet)
+ if ((int)cmd.ExecuteScalar() < 1)
{
- sqlBuilder.AddParametersToSqlCommand(cmd);
- }
-
- using (SqlDataReader reader = cmd.ExecuteReader())
- {
- var typeDict = new StockRepository(_connection, _transaction).ReadStatusType();
-
- while (reader.Read())
- {
- int statusId = reader.GetInt32(0);
- int? statusCode = null;
- if (!reader.IsDBNull(1)) { statusCode = reader.GetInt32(1); }
- string stockStatus = reader.GetString(2);
- int typeId = reader.GetInt32(3);
- string reference = null;
- if (!reader.IsDBNull(4)) { reference = reader.GetString(4); }
- int? foreignKeyId = null;
- if (!reader.IsDBNull(5)) { foreignKeyId = reader.GetInt32(5); }
- bool isCreditOnly = reader.GetBoolean(6);
- bool isClosed = reader.GetBoolean(7);
- DateTime recordCreated = DateTime.SpecifyKind(reader.GetDateTime(8), DateTimeKind.Utc);
-
- var newItem = new Model.Stock.Status(statusId
- , statusCode
- , stockStatus
- , typeDict[typeId]
- , reference
- , foreignKeyId
- , isCreditOnly
- , isClosed
- , recordCreated
- );
-
- returnList.Add(newItem);
- }
+ throw new Exception("Supplied AccountJournal entry must debit an 'Asset' account type.");
}
}
- return returnList;
+
+ // get statusCreditId for stock journal type
+ int statusCreditId;
+ using (SqlCommand cmd = new SqlCommand(@"
+ SELECT
+ tblStockJournalType.StockStatusID_Credit
+ FROM
+ tblStockJournalType
+ WHERE
+ tblStockJournalType.StockJournalTypeID=@stockJournalTypeId
+ AND tblStockJournalType.StockStatusID_Credit Is Not Null;
+ ", conn))
+ {
+ cmd.Parameters.AddWithValue("@stockJournalTypeId", stockJournalTypeId);
+
+ object obj = cmd.ExecuteScalar();
+
+ if (obj == null)
+ {
+ throw new Exception("Default credit status not set for StockJournalTypeID=" + stockJournalTypeId);
+ }
+ else
+ {
+ statusCreditId = (int)obj;
+ }
+ }
+
+ // get/set an skuId
+ int skuId = new Logic.Inventory.SkuService().GetSkuId(productId, conditionId, accountTaxCodeId, true);
+
+ // add the entry to the stock table (minus stockJournalId)
+ int stockId = 0;
+ using (SqlCommand cmd = new SqlCommand(@"
+ INSERT INTO tblStock
+ (SkuID, AccountJournalID)
+ OUTPUT INSERTED.StockID
+ VALUES
+ (@skuId, @accountJournalId);
+ ", conn))
+ {
+ cmd.Parameters.AddWithValue("@skuId", skuId);
+ cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
+
+ stockId = (int)cmd.ExecuteScalar();
+ }
+
+ // insert stock journal entry
+ var journalPosts = new List<(int statusId, int quantity)>();
+ journalPosts.Add((statusDebitId, quantity));
+ journalPosts.Add((statusCreditId, (quantity * -1)));
+ int stockJournalId = Stock.StockJournal.StockJournalInsert(sqlConnectionString, stockJournalTypeId, stockId, journalPosts, stockJournalEntryDate, true);
+
+ // update the stock table
+ using (SqlCommand cmd = new SqlCommand(@"
+ UPDATE tblStock
+ SET StockJournalID=@stockJournalId
+ WHERE StockID=@stockId;
+ ", conn))
+ {
+ cmd.Parameters.AddWithValue("@stockJournalId", stockJournalId);
+ cmd.Parameters.AddWithValue("@stockId", stockId);
+
+ count = cmd.ExecuteNonQuery();
+
+ if (count < 1)
+ {
+ throw new Exception("New stock insert cancelled, failed to update StockJournalID");
+ }
+ }
+
+ scope.Complete();
+ return stockId;
}
- public Dictionary ReadStatusType()
+ public int WIP_StockInsertPurchase(int productId, int conditionId, int accountTaxCodeId, int accountJournalId, int quantity, int statusDebitId)
{
- var returnDict = new Dictionary();
+ DateTime stockJournalEntryDate;
+ int stockJournalTypeId = 1;
- // get all account info before we start
- var accountDict = new AccountCodeRepository(_connection, _transaction).ReadAccountCode();
-
- using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
+ using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
- cmd.CommandText = @"
- SELECT [StockStatusTypeID]
- ,[StatusTypeName]
- ,[ForeignKeyType]
- ,[ReferenceType]
- ,[AccountChartOfID]
- FROM [e2A].[dbo].[tblStockStatusType]";
- cmd.Transaction = _transaction as SqlTransaction;
+ conn.Open();
- using (SqlDataReader reader = cmd.ExecuteReader())
+ // retrive info from purchase invoice line/transaction
+ using (SqlCommand cmd = new SqlCommand(@"
+ SELECT tblAccountJournal.EntryDate
+ FROM tblAccountJournal
+ WHERE (((tblAccountJournal.AccountJournalID)=@accountJournalId));
+ ", conn))
{
- var accountIdDict = new Dictionary();
+ cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
- while (reader.Read())
+ stockJournalEntryDate = DateTime.SpecifyKind((DateTime)cmd.ExecuteScalar(), DateTimeKind.Utc);
+ }
+ }
+ return WIP_StockInsertSub(productId, conditionId, accountTaxCodeId, accountJournalId, stockJournalTypeId, stockJournalEntryDate, quantity, statusDebitId);
+ }
+
+ 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 WIP_StockInsert(accountJournalType, stockJournalType, currencyCode, amount, quantity, productId, conditionId, accountTaxCodeId, entryDate, debitStatusId);
+ }
+
+ //
+ // read
+ //
+
+ //
+ // update
+ //
+
+ //
+ // delete
+ //
+
+ private void WIP_StockDelete(int stockId)
+ {
+ int accountJournalType = 0;
+ int stockJournalType = 0;
+
+ // get stock and account types
+ using (TransactionScope scope = new TransactionScope())
+ using (SqlConnection conn = new SqlConnection(sqlConnectionString))
+ {
+ conn.Open();
+
+ // ensure stockId is owner-introduced
+ using (SqlCommand cmd = new SqlCommand(@"
+ SELECT
+ tblStockJournal.StockJournalTypeID, tblAccountJournal.AccountJournalTypeID
+ FROM
+ (tblStock INNER JOIN tblAccountJournal
+ ON tblStock.AccountJournalID = tblAccountJournal.AccountJournalID)
+ INNER JOIN tblStockJournal
+ ON tblStock.StockJournalID = tblStockJournal.StockJournalID
+ WHERE
+ (((tblStock.StockID)=@stockId));
+ ", conn))
+ {
+ cmd.Parameters.AddWithValue("@stockId", stockId);
+
+ using (var reader = cmd.ExecuteReader())
{
- int statusTypeId = reader.GetInt32(0);
- string name = reader.GetString(1);
- string foreignKey = null;
- if (!reader.IsDBNull(2)) { foreignKey = reader.GetString(2); }
- string reference = null;
- if (!reader.IsDBNull(3)) { reference = reader.GetString(3); }
- uint accountId = (uint)reader.GetInt32(4);
+ if (reader.Read())
+ {
+ accountJournalType = reader.GetInt32(1);
+ stockJournalType = reader.GetInt32(0);
+ }
+ else
+ {
+ throw new Exception("Integrity check failed, cancelling StockDeleteOwnerIntroduced");
+ }
+ }
+ }
- var statusType = new Model.Stock.StatusType(statusTypeId, name, foreignKey, reference, accountDict[(int)accountId]);
- returnDict.Add(statusTypeId, statusType);
+ // 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
+ using (SqlCommand cmd = new SqlCommand(@"
+ SELECT Count(tblStockJournal.StockJournalID) AS CountOfStockJournalID
+ FROM tblStockJournal
+ WHERE (((tblStockJournal.StockID)=@stockId));
+ ", conn))
+ {
+ cmd.Parameters.AddWithValue("@stockId", stockId);
+
+ int count = (int)cmd.ExecuteScalar();
+
+ 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();
}
}
}
- return returnDict;
+ }
+
+ // 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 void WIP_StockDeletePurchase(int stockId)
+ {
+ WIP_StockDeleteSub(sqlConnectionString, stockId);
+ }
+
+ public void WIP_StockDeleteOwnerIntroduced(int stockId)
+ {
+ WIP_StockDelete(sqlConnectionString, stockId);
}
}
}
diff --git a/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockStatusRepository.cs b/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockStatusRepository.cs
new file mode 100644
index 0000000..246f0ca
--- /dev/null
+++ b/src/bnhtrade.Core/Data/Database/Repository/Implementation/StockStatusRepository.cs
@@ -0,0 +1,141 @@
+using bnhtrade.Core.Data.Database._BoilerPlate;
+using bnhtrade.Core.Data.Database.Repository.Interface;
+using Microsoft.Data.SqlClient;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace bnhtrade.Core.Data.Database.Repository.Implementation
+{
+ internal class StockStatusRepository : _Base, IStockStatusRepository
+ {
+ public StockStatusRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
+ {
+ }
+
+ public List ReadStatus(List statusIds = null, List statusTypeIds = null)
+ {
+ var sqlBuilder = new SqlWhereBuilder();
+ var returnList = new List();
+
+ //build sql query
+ string sql = @"
+ SELECT [StockStatusID]
+ ,[StatusCode]
+ ,[StockStatus]
+ ,[StockStatusTypeID]
+ ,[Reference]
+ ,[ForeignKeyID]
+ ,[IsCreditOnly]
+ ,[IsClosed]
+ ,[RecordCreated]
+ FROM [e2A].[dbo].[tblStockStatus]
+ WHERE 1=1 ";
+
+ // build the where statments
+ if (statusIds.Any())
+ {
+ sqlBuilder.In("StockStatusID", statusIds, "AND");
+ }
+ if (statusTypeIds.Any())
+ {
+ sqlBuilder.In("StockStatusTypeID", statusTypeIds, "AND");
+ }
+
+ // append where string to the sql
+ if (sqlBuilder.IsSetSqlWhereString)
+ {
+ sql = sql + sqlBuilder.SqlWhereString;
+ }
+
+ using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
+ {
+ cmd.CommandText = sql;
+ cmd.Transaction = _transaction as SqlTransaction;
+
+ if (sqlBuilder.ParameterListIsSet)
+ {
+ sqlBuilder.AddParametersToSqlCommand(cmd);
+ }
+
+ using (SqlDataReader reader = cmd.ExecuteReader())
+ {
+ var typeDict = new StockStatusRepository(_connection, _transaction).ReadStatusType();
+
+ while (reader.Read())
+ {
+ int statusId = reader.GetInt32(0);
+ int? statusCode = null;
+ if (!reader.IsDBNull(1)) { statusCode = reader.GetInt32(1); }
+ string stockStatus = reader.GetString(2);
+ int typeId = reader.GetInt32(3);
+ string reference = null;
+ if (!reader.IsDBNull(4)) { reference = reader.GetString(4); }
+ int? foreignKeyId = null;
+ if (!reader.IsDBNull(5)) { foreignKeyId = reader.GetInt32(5); }
+ bool isCreditOnly = reader.GetBoolean(6);
+ bool isClosed = reader.GetBoolean(7);
+ DateTime recordCreated = DateTime.SpecifyKind(reader.GetDateTime(8), DateTimeKind.Utc);
+
+ var newItem = new Model.Stock.Status(statusId
+ , statusCode
+ , stockStatus
+ , typeDict[typeId]
+ , reference
+ , foreignKeyId
+ , isCreditOnly
+ , isClosed
+ , recordCreated
+ );
+
+ returnList.Add(newItem);
+ }
+ }
+ }
+ return returnList;
+ }
+
+ public Dictionary ReadStatusType()
+ {
+ var returnDict = new Dictionary();
+
+ // get all account info before we start
+ var accountDict = new AccountCodeRepository(_connection, _transaction).ReadAccountCode();
+
+ using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
+ {
+ cmd.CommandText = @"
+ SELECT [StockStatusTypeID]
+ ,[StatusTypeName]
+ ,[ForeignKeyType]
+ ,[ReferenceType]
+ ,[AccountChartOfID]
+ FROM [e2A].[dbo].[tblStockStatusType]";
+ cmd.Transaction = _transaction as SqlTransaction;
+
+ using (SqlDataReader reader = cmd.ExecuteReader())
+ {
+ var accountIdDict = new Dictionary();
+
+ while (reader.Read())
+ {
+ int statusTypeId = reader.GetInt32(0);
+ string name = reader.GetString(1);
+ string foreignKey = null;
+ if (!reader.IsDBNull(2)) { foreignKey = reader.GetString(2); }
+ string reference = null;
+ if (!reader.IsDBNull(3)) { reference = reader.GetString(3); }
+ uint accountId = (uint)reader.GetInt32(4);
+
+ var statusType = new Model.Stock.StatusType(statusTypeId, name, foreignKey, reference, accountDict[(int)accountId]);
+ returnDict.Add(statusTypeId, statusType);
+ }
+ }
+ }
+ return returnDict;
+ }
+ }
+}
diff --git a/src/bnhtrade.Core/Data/Database/Repository/Interface/IAccountJournalRepository.cs b/src/bnhtrade.Core/Data/Database/Repository/Interface/IAccountJournalRepository.cs
index 6de9735..4d74003 100644
--- a/src/bnhtrade.Core/Data/Database/Repository/Interface/IAccountJournalRepository.cs
+++ b/src/bnhtrade.Core/Data/Database/Repository/Interface/IAccountJournalRepository.cs
@@ -11,6 +11,7 @@ namespace bnhtrade.Core.Data.Database.Repository.Interface
int AccountJournalInsert(int journalTypeId, DateTime entryDate, string currencyCode, decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false);
bool AccountJournalPostInsert(int journalId, DateTime entryDate, string currencyCode, decimal amount, int debitAccountId = 0, int creditAccountId = 0);
Dictionary ReadJournal(List journalIdList);
+ DateTime ReadJournalEntryDate(int journalId);
bool ReadJournalIsLocked(int journalId);
Dictionary ReadJournalType(List journalTypeIds = null, List typeTitles = null);
bool DeleteJournal(int accountJournalId);
diff --git a/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockJournalRepository.cs b/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockJournalRepository.cs
index 54e4296..b629dbe 100644
--- a/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockJournalRepository.cs
+++ b/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockJournalRepository.cs
@@ -8,9 +8,11 @@ namespace bnhtrade.Core.Data.Database.Repository.Interface
{
internal interface IStockJournalRepository
{
+ int ReadJournalTypeIdByStockId(int stockId);
int ReadStatusBalanceBySku(string sku, int statusId);
int ReadStatusBalanceByStockNumber(int stockNumber, int statusId);
int ReadStatusBalanceByStockId(int stockId, int statusId);
+ int ReadJournalEntryCountByStockId(int stockId);
Dictionary ReadStatusBalanceByStatusId(int statusId);
void StockJournalDelete(int stockJournalId);
void StockJournalPostInsert(int stockId, int stockJournalId, List<(int statusId, int quantity)> journalPosts, bool isNewStock = false);
diff --git a/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockRepository.cs b/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockRepository.cs
index 0ff9470..8d4de77 100644
--- a/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockRepository.cs
+++ b/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockRepository.cs
@@ -8,7 +8,14 @@ namespace bnhtrade.Core.Data.Database.Repository.Interface
{
internal interface IStockRepository
{
- List ReadStatus(List statusIds = null, List statusTypeIds = null);
- Dictionary ReadStatusType();
+ int WIP_StockInsertSub(int productId, int conditionId, int accountTaxCodeId,
+ 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);
+ void WIP_StockDelete(int stockId);
+ void WIP_StockDeleteSub(int stockId);
+ void WIP_StockDeleteSubAccountJournalEntry(int stockId);
+ void WIP_StockDeletePurchase(int stockId);
+ void WIP_StockDeleteOwnerIntroduced(int stockId);
}
}
diff --git a/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockStatusRepository.cs b/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockStatusRepository.cs
new file mode 100644
index 0000000..7f06bcd
--- /dev/null
+++ b/src/bnhtrade.Core/Data/Database/Repository/Interface/IStockStatusRepository.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace bnhtrade.Core.Data.Database.Repository.Interface
+{
+ internal interface IStockStatusRepository
+ {
+ List ReadStatus(List statusIds = null, List statusTypeIds = null);
+ Dictionary ReadStatusType();
+ }
+}
diff --git a/src/bnhtrade.Core/Data/Database/UnitOfWork/IUnitOfWork.cs b/src/bnhtrade.Core/Data/Database/UnitOfWork/IUnitOfWork.cs
index 4f5dd05..8177f2e 100644
--- a/src/bnhtrade.Core/Data/Database/UnitOfWork/IUnitOfWork.cs
+++ b/src/bnhtrade.Core/Data/Database/UnitOfWork/IUnitOfWork.cs
@@ -20,8 +20,9 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
IAccountJournalRepository JournalRepository { get; }
ISequenceGenerator SequenceGenerator { get; }
ISkuRepository SkuRepository { get; }
- IStockJournalRepository StockJournalRepository { get; }
IStockRepository StockRepository { get; }
+ IStockJournalRepository StockJournalRepository { get; }
+ IStockStatusRepository StockStatusRepository { get; }
// Methods to manage the transaction
void Commit();
diff --git a/src/bnhtrade.Core/Data/Database/UnitOfWork/UnitOfWork.cs b/src/bnhtrade.Core/Data/Database/UnitOfWork/UnitOfWork.cs
index 9cbf4cf..0dbdbf6 100644
--- a/src/bnhtrade.Core/Data/Database/UnitOfWork/UnitOfWork.cs
+++ b/src/bnhtrade.Core/Data/Database/UnitOfWork/UnitOfWork.cs
@@ -28,8 +28,9 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
private IAccountJournalRepository _journalRepository;
private ISequenceGenerator _sequenceGenerator;
private ISkuRepository _skuRepository;
- private IStockJournalRepository _stockJournalRespository;
private IStockRepository _stockRepository;
+ private IStockJournalRepository _stockJournalRespository;
+ private IStockStatusRepository _stockStatusRepository;
internal UnitOfWork()
{
@@ -158,6 +159,18 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
}
}
+ public IStockRepository StockRepository
+ {
+ get
+ {
+ if (_stockRepository == null)
+ {
+ _stockRepository = new StockRepository(_connection, _transaction);
+ }
+ return _stockRepository;
+ }
+ }
+
public IStockJournalRepository StockJournalRepository
{
get
@@ -170,15 +183,15 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
}
}
- public IStockRepository StockRepository
+ public IStockStatusRepository StockStatusRepository
{
get
{
- if (_stockRepository == null)
+ if (_stockStatusRepository == null)
{
- _stockRepository = new StockRepository(_connection, _transaction);
+ _stockStatusRepository = new StockStatusRepository(_connection, _transaction);
}
- return _stockRepository;
+ return _stockStatusRepository;
}
}
diff --git a/src/bnhtrade.Core/Logic/Inventory/StockJournalService.cs b/src/bnhtrade.Core/Logic/Inventory/StockJournalService.cs
index cb974cf..1e34602 100644
--- a/src/bnhtrade.Core/Logic/Inventory/StockJournalService.cs
+++ b/src/bnhtrade.Core/Logic/Inventory/StockJournalService.cs
@@ -21,15 +21,14 @@ namespace bnhtrade.Core.Logic.Inventory
{
throw new ArgumentException("Stock journal ID must be greater than zero", nameof(stockJournalId));
}
- bool result = uow.StockJournalRepository.DeleteStockJournal(stockJournalId);
+ uow.StockJournalRepository.StockJournalDelete(stockJournalId);
CommitIfOwned(uow);
- if (!result)
- {
- throw new InvalidOperationException($"Failed to delete stock journal with ID {stockJournalId}");
- }
});
}
+ // can be used before commiting an sql insert, update or delete to the stock journal to ensure a status does not fall below 0
+ // (unless the status is enabled to do so)
+ // set empty list or statusIdEffected to null to check entier stock entries for consistency
public bool WIP_StockJournalConsistencyCheck(int stockId, List statusIdEffected = null)
{
return WithUnitOfWork(uow =>
diff --git a/src/bnhtrade.Core/Logic/Inventory/StockService.cs b/src/bnhtrade.Core/Logic/Inventory/StockService.cs
index c20588f..eb05986 100644
--- a/src/bnhtrade.Core/Logic/Inventory/StockService.cs
+++ b/src/bnhtrade.Core/Logic/Inventory/StockService.cs
@@ -18,187 +18,30 @@ namespace bnhtrade.Core.Logic.Inventory
private int WIP_StockInsert(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())
- using (SqlConnection conn = new SqlConnection(sqlConnectionString))
+ return WithUnitOfWork(uow =>
{
- conn.Open();
-
// add account journal entry
- int accountJournalId = new Logic.Account.JournalService().JournalInsert(accountJournalType, entryDate, currencyCode, amount);
+ int accountJournalId = new Logic.Account.JournalService(uow).JournalInsert(accountJournalType, entryDate, currencyCode, amount);
// make the stock insert
- int stockId = WIP_StockInsertSub(sqlConnectionString, productId, conditionId, accountTaxCodeId,
+ int stockId = uow.StockRepository.WIP_StockInsertSub(productId, conditionId, accountTaxCodeId,
accountJournalId, stockJournalType, entryDate, quantity, debitStatusId);
- scope.Complete();
+ CommitIfOwned(uow);
+
return stockId;
- }
- }
- private int WIP_StockInsertSub(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 = 0;
-
- using (SqlCommand cmd = new SqlCommand(@"
- SELECT Count(tblStock.StockID) AS CountOfID
- FROM tblStock
- WHERE (((tblStock.AccountJournalID)=@accountJouranlId));
- ", conn))
- {
- cmd.Parameters.AddWithValue("@accountJouranlId", accountJournalId);
-
- count = (int)cmd.ExecuteScalar();
- }
-
- 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
- using (SqlCommand cmd = new SqlCommand(@"
- SELECT
- Count(tblAccountJournalPost.AccountJournalPostID) AS CountOfAccountJournalPostID
- FROM
- (tblAccountJournalPost
- INNER JOIN tblAccountChartOf
- ON tblAccountJournalPost.AccountChartOfID = tblAccountChartOf.AccountChartOfID)
- INNER JOIN tblAccountChartOfType
- ON tblAccountChartOf.AccountChartOfTypeID = tblAccountChartOfType.AccountChartOfTypeID
- WHERE
- tblAccountJournalPost.AmountGbp>=0
- AND tblAccountChartOfType.BasicType='Asset'
- AND tblAccountJournalPost.AccountJournalID=@accountJournalId;
- ", conn))
- {
- cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
-
- if ((int)cmd.ExecuteScalar() < 1)
- {
- throw new Exception("Supplied AccountJournal entry must debit an 'Asset' account type.");
- }
- }
-
- // get statusCreditId for stock journal type
- int statusCreditId;
- using (SqlCommand cmd = new SqlCommand(@"
- SELECT
- tblStockJournalType.StockStatusID_Credit
- FROM
- tblStockJournalType
- WHERE
- tblStockJournalType.StockJournalTypeID=@stockJournalTypeId
- AND tblStockJournalType.StockStatusID_Credit Is Not Null;
- ", conn))
- {
- cmd.Parameters.AddWithValue("@stockJournalTypeId", stockJournalTypeId);
-
- object obj = cmd.ExecuteScalar();
-
- if (obj == null)
- {
- throw new Exception("Default credit status not set for StockJournalTypeID=" + stockJournalTypeId);
- }
- else
- {
- statusCreditId = (int)obj;
- }
- }
-
- // get/set an skuId
- int skuId = new Logic.Inventory.SkuService().GetSkuId(productId, conditionId, accountTaxCodeId, true);
-
- // add the entry to the stock table (minus stockJournalId)
- int stockId = 0;
- using (SqlCommand cmd = new SqlCommand(@"
- INSERT INTO tblStock
- (SkuID, AccountJournalID)
- OUTPUT INSERTED.StockID
- VALUES
- (@skuId, @accountJournalId);
- ", conn))
- {
- cmd.Parameters.AddWithValue("@skuId", skuId);
- cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
-
- stockId = (int)cmd.ExecuteScalar();
- }
-
- // insert stock journal entry
- var journalPosts = new List<(int statusId, int quantity)>();
- journalPosts.Add((statusDebitId, quantity));
- journalPosts.Add((statusCreditId, (quantity * -1)));
- int stockJournalId = Stock.StockJournal.StockJournalInsert(sqlConnectionString, stockJournalTypeId, stockId, journalPosts, stockJournalEntryDate, true);
-
- // update the stock table
- using (SqlCommand cmd = new SqlCommand(@"
- UPDATE tblStock
- SET StockJournalID=@stockJournalId
- WHERE StockID=@stockId;
- ", conn))
- {
- cmd.Parameters.AddWithValue("@stockJournalId", stockJournalId);
- cmd.Parameters.AddWithValue("@stockId", stockId);
-
- count = cmd.ExecuteNonQuery();
-
- if (count < 1)
- {
- throw new Exception("New stock insert cancelled, failed to update StockJournalID");
- }
- }
-
- scope.Complete();
- return stockId;
+ });
}
private void WIP_StockDelete(int stockId)
{
- int accountJournalType = 0;
int stockJournalType = 0;
- // get stock and account types
- using (TransactionScope scope = new TransactionScope())
- using (SqlConnection conn = new SqlConnection(sqlConnectionString))
+ WithUnitOfWork(uow =>
{
- conn.Open();
-
// ensure stockId is owner-introduced
- using (SqlCommand cmd = new SqlCommand(@"
- SELECT
- tblStockJournal.StockJournalTypeID, tblAccountJournal.AccountJournalTypeID
- FROM
- (tblStock INNER JOIN tblAccountJournal
- ON tblStock.AccountJournalID = tblAccountJournal.AccountJournalID)
- INNER JOIN tblStockJournal
- ON tblStock.StockJournalID = tblStockJournal.StockJournalID
- WHERE
- (((tblStock.StockID)=@stockId));
- ", conn))
- {
- cmd.Parameters.AddWithValue("@stockId", stockId);
-
- using (var reader = cmd.ExecuteReader())
- {
- if (reader.Read())
- {
- accountJournalType = reader.GetInt32(1);
- stockJournalType = reader.GetInt32(0);
- }
- else
- {
- throw new Exception("Integrity check failed, cancelling StockDeleteOwnerIntroduced");
- }
- }
- }
+ stockJournalType = uow.StockJournalRepository.ReadJournalTypeIdByStockId(stockId);
// check stock journal type is not restricted
// owner inventory introduced
@@ -211,21 +54,12 @@ namespace bnhtrade.Core.Logic.Inventory
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
- using (SqlCommand cmd = new SqlCommand(@"
- SELECT Count(tblStockJournal.StockJournalID) AS CountOfStockJournalID
- FROM tblStockJournal
- WHERE (((tblStockJournal.StockID)=@stockId));
- ", conn))
+ // 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)
{
- cmd.Parameters.AddWithValue("@stockId", stockId);
-
- int count = (int)cmd.ExecuteScalar();
-
- if (count > 1)
- {
- throw new Exception("Delete " + count + " stock journal entries (other than source entry), before peforming this operation.");
- }
+ throw new Exception("Delete " + count + " stock journal entries (other than source entry), before peforming this operation.");
}
// remove account journal entry
@@ -235,7 +69,23 @@ namespace bnhtrade.Core.Logic.Inventory
WIP_StockDeleteSub(sqlConnectionString, stockId);
scope.Complete();
- }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ });
}
private void WIP_StockDeleteSub(int stockId)
@@ -312,7 +162,7 @@ namespace bnhtrade.Core.Logic.Inventory
}
// delete stock journal entry
- Core.Stock.StockJournal.StockJournalDelete(sqlConnectionString, stockJournalId);
+ new Core.Logic.Inventory.StockJournalService().StockJournalDelete(stockJournalId);
// delete stock table entry
using (SqlCommand cmd = new SqlCommand(@"
@@ -401,23 +251,14 @@ namespace bnhtrade.Core.Logic.Inventory
DateTime stockJournalEntryDate;
int stockJournalTypeId = 1;
- using (SqlConnection conn = new SqlConnection(sqlConnectionString))
+ return WithUnitOfWork(uow =>
{
- conn.Open();
-
- // retrive info from purchase invoice line/transaction
- using (SqlCommand cmd = new SqlCommand(@"
- SELECT tblAccountJournal.EntryDate
- FROM tblAccountJournal
- WHERE (((tblAccountJournal.AccountJournalID)=@accountJournalId));
- ", conn))
- {
- cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
-
- stockJournalEntryDate = DateTime.SpecifyKind((DateTime)cmd.ExecuteScalar(), DateTimeKind.Utc);
- }
- }
- return WIP_StockInsertSub(productId, conditionId, accountTaxCodeId, accountJournalId, stockJournalTypeId, stockJournalEntryDate, quantity, statusDebitId);
+ stockJournalEntryDate = uow.JournalRepository.ReadJournalEntryDate(accountJournalId);
+ int result = uow.StockRepository.WIP_StockInsertSub(
+ 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)
diff --git a/src/bnhtrade.Core/Logic/Stock/StatusBalance.cs b/src/bnhtrade.Core/Logic/Stock/StatusBalance.cs
index 34c7330..8d41852 100644
--- a/src/bnhtrade.Core/Logic/Stock/StatusBalance.cs
+++ b/src/bnhtrade.Core/Logic/Stock/StatusBalance.cs
@@ -100,7 +100,7 @@ namespace bnhtrade.Core.Logic.Stock
var sku = readSku.BySkuNumber(statusTransaction.SkuNumber);
// get the status obj
- var status = uow.StockRepository.ReadStatus(new List { statusTransaction.StockStatusId })[0];
+ var status = uow.StockStatusRepository.ReadStatus(new List { statusTransaction.StockStatusId })[0];
return new Model.Stock.StatusBalance(status, sku, entryList);
}
diff --git a/src/bnhtrade.Core/Program.cs b/src/bnhtrade.Core/Program.cs
index 60f95b5..b6960bf 100644
--- a/src/bnhtrade.Core/Program.cs
+++ b/src/bnhtrade.Core/Program.cs
@@ -233,532 +233,6 @@ namespace bnhtrade.Core
}
}
- namespace Stock
- {
- public class StockJournal : UnitOfWorkBase
- {
- public static void StockJournalDelete(string sqlConnectionString, int stockJournalId)
- {
- using (TransactionScope scope = new TransactionScope())
- using (SqlConnection conn = new SqlConnection(sqlConnectionString))
- {
- conn.Open();
-
- // get date for journal entry
- DateTime entryDate;
- int stockId;
- using (SqlCommand cmd = new SqlCommand(@"
- SELECT tblStockJournal.EntryDate, StockID
- FROM tblStockJournal
- WHERE (((tblStockJournal.StockJournalID)=@stockJournalId));
- ", conn))
- {
- // add parameters
- cmd.Parameters.AddWithValue("@stockJournalId", stockJournalId);
-
- using (var reader = cmd.ExecuteReader())
- {
- if (reader.Read())
- {
- entryDate = DateTime.SpecifyKind(reader.GetDateTime(0), DateTimeKind.Utc);
- stockId = reader.GetInt32(1);
- }
- else
- {
- throw new Exception("StockJournalID=" + stockJournalId + " does not exist!");
- }
- }
-
- }
-
- // is consistancy check required
- bool consistancyCheck;
- // build list of debits that are to be deleted
- var debitList = new List();
- using (SqlCommand cmd = new SqlCommand(@"
- SELECT tblStockJournalPost.StockStatusID
- FROM tblStockJournalPost
- WHERE (((tblStockJournalPost.StockJournalID)=@stockJournalId) AND ((tblStockJournalPost.Quantity)>0));
- ", conn))
- {
- // add parameters
- cmd.Parameters.AddWithValue("@stockJournalId", stockJournalId);
-
- using (var reader = cmd.ExecuteReader())
- {
- if (reader.HasRows)
- {
- while (reader.Read())
- {
- debitList.Add(reader.GetInt32(0));
- }
- }
- else
- {
- throw new Exception("StockJournalID=" + stockJournalId + " has no debits with quantity greater than zero!");
- }
- }
- }
-
- // check no credits for stockId & debit combination have been made since delete entry
- string stringSql = @"
- SELECT
- tblStockJournal.EntryDate
- FROM
- tblStockJournal
- INNER JOIN tblStockJournalPost
- ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
- WHERE
- tblStockJournal.StockID=@stockId
- AND tblStockJournalPost.Quantity<0
- AND EntryDate>=@entryDate
- AND (";
-
- bool firstDone = false;
- foreach (var item in debitList)
- {
- if (firstDone)
- {
- stringSql = stringSql + " OR ";
- }
- stringSql = stringSql + "tblStockJournalPost.StockStatusID=" + item;
- firstDone = true;
- }
- stringSql = stringSql + ");";
-
- using (SqlCommand cmd = new SqlCommand(stringSql, conn))
- {
- cmd.Parameters.AddWithValue("@stockId", stockId);
- cmd.Parameters.AddWithValue("@entryDate", entryDate.ToUniversalTime());
-
- using (var reader = cmd.ExecuteReader())
- {
- if (reader.HasRows)
- {
- consistancyCheck = true;
- }
- else
- {
- consistancyCheck = false;
- }
- }
- }
-
- // delete the posts
- StockJournalPostDelete(conn, stockJournalId);
-
- // delete journal entry
- using (SqlCommand cmd = new SqlCommand(@"
- DELETE FROM tblStockJournal
- WHERE StockJournalID=@stockJournalId;
- ", conn))
- {
- // add parameters
- cmd.Parameters.AddWithValue("@stockJournalId", stockJournalId);
-
- int count = cmd.ExecuteNonQuery();
-
- if (count != 1)
- {
- throw new Exception("Failed to delete stock journal header.");
- }
- }
-
- // consistanct check
- bool consistencyResult = true;
- if (consistancyCheck)
- {
- // run check
- consistencyResult = Stock.StockJournal.WIP_StockJournalConsistencyCheck(sqlConnectionString, stockId, debitList);
- }
-
- if (consistencyResult)
- {
- // commit
- scope.Complete();
- }
- else
- {
- throw new Exception("Unable to delete stock journal entry, consistancy check failed.");
- }
- }
- }
-
- private static void StockJournalPostInsert(SqlConnection conn, int stockId, int stockJournalId,
- List<(int statusId, int quantity)> journalPosts, bool isNewStock = false)
- {
- //checks
- if (journalPosts.Count > 2)
- {
- // I have purposely made the code to accept split transaction incase of future requirements, however, db design is simpler this way.
- throw new Exception("Stock journal does not currently support split transactions (greater than two posts)." + journalPosts.Count + " number posts attempted.");
- }
- else if (journalPosts.Count < 2)
- {
- // list not long enough
- throw new Exception("Stock journal entry requires minium of two posts, entry of " + journalPosts.Count + " number posts attempted.");
- }
-
- if (journalPosts.Sum(item => item.quantity) != 0)
- {
- // credits and debits do not match
- throw new Exception("Sum of credits and debits do not resolve to zero.");
- }
-
- // group credits and debits by status
- var dicStatusQty = new Dictionary();
- foreach (var post in journalPosts)
- {
- if (dicStatusQty.ContainsKey(post.statusId) == false)
- {
- dicStatusQty.Add(post.statusId, post.quantity);
- }
- else
- {
- dicStatusQty[post.statusId] = dicStatusQty[post.statusId] + post.quantity;
- }
- }
-
- // get isCreditOnly for each status
- var dicStatusIsCreditOnly = new Dictionary();
- foreach (var item in dicStatusQty)
- {
- using (SqlCommand cmd = new SqlCommand(@"
- SELECT IsCreditOnly FROM tblStockStatus WHERE StockStatusID=@statusId;
- ", conn))
- {
- cmd.Parameters.AddWithValue("@statusId", item.Key);
-
- dicStatusIsCreditOnly.Add(item.Key, (bool)cmd.ExecuteScalar());
- }
- }
-
- // check there is only one IsCreditOnly in list and it is allowed in this instance
- int isCreditOnlyCount = 0;
- foreach (var item in dicStatusIsCreditOnly)
- {
- if (item.Value)
- {
- isCreditOnlyCount = isCreditOnlyCount + 1;
- }
- }
- if (isNewStock == false && isCreditOnlyCount > 0)
- {
- throw new Exception("Attempted credit or debit to 'Is Credit Only' status not allowed, in this instance.");
- }
- if (isNewStock == true && isCreditOnlyCount != 1)
- {
- throw new Exception("StockID=" + stockId + ", each stock line must have only have one IsCreditOnly=True status assigned to it.");
- }
-
- // ensure debit (or zero credit) isn't made to credit only status
- // need to do this check via original post list (i.e. journalPosts)
- foreach (var post in journalPosts)
- {
- // debit check
- if (post.quantity >= 0)
- {
- if (dicStatusIsCreditOnly[post.statusId] == true)
- {
- throw new Exception("Cannot make debit, or zero quantity credit, to credit only status. StatusID=" + post.statusId);
- }
- }
- }
-
- // balance check for any credits (that are not isCreditOnly=true)
- foreach (var item in dicStatusQty)
- {
- if (item.Value < 0 && dicStatusIsCreditOnly[item.Key] == false)
- {
- int quantity = new Data.Database.Stock.ReadStatusBalance().ReadStatusBalanceByStockId(stockId, item.Key);
-
- if (quantity + item.Value < 0)
- {
- throw new Exception("Credit status balance check failed. Available balance " + quantity + ", attempted credit " + item.Value * -1 + ".");
- }
- }
- }
-
- // get this far...
- // insert journal posts into database
- foreach (var post in journalPosts)
- {
- using (SqlCommand cmd = new SqlCommand(@"
- INSERT INTO tblStockJournalPost ( StockJournalID, StockStatusID, Quantity )
- VALUES ( @StockJournalId, @stockStatudId, @quantity );
- ", conn))
- {
- cmd.Parameters.AddWithValue("@StockJournalId", stockJournalId);
- cmd.Parameters.AddWithValue("@stockStatudId", post.statusId);
- cmd.Parameters.AddWithValue("@quantity", post.quantity);
-
- // execute
- cmd.ExecuteNonQuery();
- }
- }
- }
-
- private static void StockJournalPostDelete(SqlConnection conn, int stockJournalId)
- {
- using (SqlCommand cmd = new SqlCommand(@"
- DELETE FROM tblStockJournalPost
- WHERE StockJournalID=@stockJournalId
- ", conn))
- {
- cmd.Parameters.AddWithValue("@StockJournalId", stockJournalId);
-
- // execute
- cmd.ExecuteNonQuery();
-
- // the calling method must compete any transaction-scope on the connection
- }
- }
-
- // can be used before commiting an sql insert, update or delete to the stock journal to ensure a status does not fall below 0
- // (unless the status is enabled to do so)
- // set empty list or statusIdEffected to null to check entier stock entries for consistency
- public static bool WIP_StockJournalConsistencyCheck(string sqlConnectionString, int stockId, List statusIdEffected = null)
- {
- if (statusIdEffected == null)
- {
- statusIdEffected = new List();
- }
-
-
- using (SqlConnection conn = new SqlConnection(sqlConnectionString))
- {
- conn.Open();
-
- // if no list supplied, build list of all used status' for stockId
- if (statusIdEffected.Count == 0)
- {
- using (SqlCommand cmd = new SqlCommand(@"
- SELECT
- tblStockJournalPost.StockStatusID
- FROM
- tblStockJournal
- INNER JOIN tblStockJournalPost
- ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
- WHERE
- tblStockJournal.StockID=@stockId
- GROUP BY
- tblStockJournalPost.StockStatusID;
- ", conn))
- {
- cmd.Parameters.AddWithValue("@stockId", stockId);
-
- using (var reader = cmd.ExecuteReader())
- {
- if (reader.HasRows)
- {
- while (reader.Read())
- {
- statusIdEffected.Add(reader.GetInt32(0));
- }
- }
- else
- {
- throw new Exception("No stock journal entries exist for StockID=" + stockId);
- }
- }
- }
- }
-
- // build the sql string to build creditCreate bool
- var dicStatusCreditOnly = new Dictionary();
- string sqlString = @"
- SELECT
- tblStockStatus.StockStatusID, tblStockStatus.IsCreditOnly
- FROM
- tblStockStatus ";
-
- for (var i = 0; i < statusIdEffected.Count; i++)
- {
- if (i == 0)
- {
- sqlString = sqlString + " WHERE tblStockStatus.StockStatusID=" + statusIdEffected[i];
- }
- else
- {
- sqlString = sqlString + " OR tblStockStatus.StockStatusID=" + statusIdEffected[i];
- }
-
- //if (i == (statusIdEffected.Count - 1))
- //{
- // sqlString = sqlString + ";";
- //}
- }
- sqlString = sqlString + " GROUP BY tblStockStatus.StockStatusID, tblStockStatus.IsCreditOnly;";
-
- // run query & build dictionaries
- using (SqlCommand cmd = new SqlCommand(sqlString, conn))
- {
- cmd.Parameters.AddWithValue("@stockId", stockId);
-
- using (SqlDataReader reader = cmd.ExecuteReader())
- {
- if (reader.Read())
- {
- dicStatusCreditOnly.Add(reader.GetInt32(0), reader.GetBoolean(1));
-
- while (reader.Read())
- {
- dicStatusCreditOnly.Add(reader.GetInt32(0), reader.GetBoolean(1));
- }
- }
- else
- {
- throw new Exception("Error, no journal entries found for StockID=" + stockId);
- }
- }
- }
-
- // check integrity of supplied statusIds
- foreach (int statusId in statusIdEffected)
- {
- if (!dicStatusCreditOnly.ContainsKey(statusId))
- {
- throw new Exception("Supplied StatusId (" + statusId + ") doesn't exist for StockId=" + stockId);
- }
- }
-
- // loop through each statudId and check integrity, if createdEnabled=false
- foreach (int statudId in statusIdEffected)
- {
- if (dicStatusCreditOnly[statudId] == false)
- {
- using (SqlCommand cmd = new SqlCommand(@"
- SELECT
- tblStockJournal.EntryDate, tblStockJournalPost.Quantity
- FROM
- tblStockJournal
- INNER JOIN tblStockJournalPost
- ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
- WHERE
- tblStockJournal.StockID=@stockId
- AND tblStockJournalPost.StockStatusID=@statudId
- ORDER BY
- tblStockJournal.EntryDate;
- ", conn))
- {
- cmd.Parameters.AddWithValue("@stockId", stockId);
- cmd.Parameters.AddWithValue("@statudId", statudId);
-
- using (SqlDataReader reader = cmd.ExecuteReader())
- {
- // read first line into variables
- reader.Read();
- int quantity = reader.GetInt32(1);
- DateTime entryDate = DateTime.SpecifyKind(reader.GetDateTime(0), DateTimeKind.Utc);
-
- while (true)
- {
- // compare to next values
- if (reader.Read())
- {
- DateTime nextEntryDate = DateTime.SpecifyKind(reader.GetDateTime(0), DateTimeKind.Utc);
- // don't check quantites for transactions on same date
- if (entryDate == nextEntryDate)
- {
- entryDate = nextEntryDate;
- quantity = quantity + reader.GetInt32(1);
- }
- // check if dates are different
- else
- {
- if (quantity < 0)
- {
- return false;
- }
- else
- {
- entryDate = nextEntryDate;
- quantity = quantity + reader.GetInt32(1);
- }
- }
- }
- // end if no records, check quantity
- else
- {
- if (quantity < 0)
- {
- return false;
- }
- break;
- }
- }
- }
- }
- }
- }
- }
- // get this far, all good
- return true;
- }
-
- public static int StockTransactionTypeIdInsert(string sqlConnectionString, int stockJournalTypeId, string typeCode, bool transScopeSuppress = true)
- {
- int transactionTypeId;
- var scopeOption = new TransactionScopeOption();
- if (transScopeSuppress)
- {
- scopeOption = TransactionScopeOption.Suppress;
- }
- else
- {
- scopeOption = TransactionScopeOption.Required;
- }
-
- using (TransactionScope scope = new TransactionScope(scopeOption))
- using (SqlConnection conn = new SqlConnection(sqlConnectionString))
- {
- conn.Open();
- //check to see if type already exists, return id of that if it does
- using (SqlCommand cmd = new SqlCommand(@"
- SELECT
- tblStockSkuTransactionType.StockSkuTransactionTypeID
- FROM
- tblStockSkuTransactionType
- WHERE
- tblStockSkuTransactionType.StockJournalTypeID=@stockJournalTypeId
- AND tblStockSkuTransactionType.TypeCode=@typeCode;
- ", conn))
- {
- cmd.Parameters.AddWithValue("@typeCode", typeCode);
- cmd.Parameters.AddWithValue("@stockJournalTypeId", stockJournalTypeId);
-
- object obj = cmd.ExecuteScalar();
-
- if (!(obj == null || obj == DBNull.Value))
- {
- return (int)obj;
- }
- }
-
- // insert new and retrive new value
- using (SqlCommand cmd = new SqlCommand(@"
- INSERT INTO tblStockSkuTransactionType
- ( TypeName, StockJournalTypeID, TypeCode )
- OUTPUT
- INSERTED.StockSkuTransactionTypeID
- VALUES
- ( @typeName, @stockJournalTypeId, @typeCode );
- ", conn))
- {
- cmd.Parameters.AddWithValue("@typeName", typeCode);
- cmd.Parameters.AddWithValue("@typeCode", typeCode);
- cmd.Parameters.AddWithValue("@stockJournalTypeId", stockJournalTypeId);
-
- transactionTypeId = (int)cmd.ExecuteScalar();
- }
-
- scope.Complete();
- }
- return transactionTypeId;
- }
- }
- }
-
public class MiscFunction
{
public static string TraceMessage(