mirror of
https://github.com/stokebob/bnhtrade.git
synced 2026-03-22 15:57:16 +00:00
wip, this turned into a maaaaaahooosive job
This commit is contained in:
@@ -35,13 +35,13 @@ namespace bnhtrade.ComTypeLib
|
|||||||
public int AccountJournalInsert(ConnectionCredential sqlConnCred, int journalTypeId, DateTime entryDate,
|
public int AccountJournalInsert(ConnectionCredential sqlConnCred, int journalTypeId, DateTime entryDate,
|
||||||
string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false)
|
string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false)
|
||||||
{
|
{
|
||||||
return new Core.Logic.Account.Journal().AccountJournalInsert(journalTypeId, entryDate,
|
return new Core.Logic.Account.JournalService().JournalInsert(journalTypeId, entryDate,
|
||||||
currencyCode, amount, debitAccountId, creditAccountId, lockEntry);
|
currencyCode, amount, debitAccountId, creditAccountId, lockEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AccountJournalDelete(ConnectionCredential sqlConnCred, int accountJournalId)
|
public bool AccountJournalDelete(ConnectionCredential sqlConnCred, int accountJournalId)
|
||||||
{
|
{
|
||||||
return new Core.Logic.Account.Journal().AccountJournalDelete(accountJournalId);
|
return new Core.Logic.Account.JournalService().JournalDelete(accountJournalId);
|
||||||
}
|
}
|
||||||
|
|
||||||
[return: MarshalAs(UnmanagedType.Currency)]
|
[return: MarshalAs(UnmanagedType.Currency)]
|
||||||
|
|||||||
@@ -35,32 +35,30 @@ namespace bnhtrade.ComTypeLib.Purchase
|
|||||||
string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amountNet,
|
string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amountNet,
|
||||||
DateTime entryDate)
|
DateTime entryDate)
|
||||||
{
|
{
|
||||||
Core.Purchase.PurchaseQuery.WIP_PurchaseLineTransactionNetInsert(sqlConnCred.ConnectionString,
|
new Core.Logic.Purchase.PurchaseService().WIP_PurchaseLineTransactionNetInsert(purchaseLineId, currencyCode, amountNet, entryDate);
|
||||||
purchaseLineId, currencyCode, amountNet, entryDate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PurchaseLineTransactionNetUpdate(ConnectionCredential sqlConnCred, int accountJouranlId,
|
public void PurchaseLineTransactionNetUpdate(ConnectionCredential sqlConnCred, int accountJouranlId,
|
||||||
string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amountNet, int debitAccountId)
|
string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amountNet, int debitAccountId)
|
||||||
{
|
{
|
||||||
Core.Purchase.PurchaseQuery.WIP_PurchaseLineTransactionNetUpdate(sqlConnCred.ConnectionString,
|
new Core.Logic.Purchase.PurchaseService().WIP_PurchaseLineTransactionNetUpdate(accountJouranlId, currencyCode, amountNet, debitAccountId);
|
||||||
accountJouranlId, currencyCode, amountNet, debitAccountId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PurchaseLineTransactionDelete(ConnectionCredential sqlConnCred, int purchaseLineId, int accountJournalId)
|
public void PurchaseLineTransactionDelete(ConnectionCredential sqlConnCred, int purchaseLineId, int accountJournalId)
|
||||||
{
|
{
|
||||||
Core.Purchase.PurchaseQuery.WIP_PurchaseLineTransactionDelete(sqlConnCred.ConnectionString, purchaseLineId, accountJournalId);
|
new Core.Logic.Purchase.PurchaseService().WIP_PurchaseLineTransactionDelete(purchaseLineId, accountJournalId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int PurchaseLineTransactionStockInsert(ConnectionCredential sqlConnCred, int accountJournalId,
|
public int PurchaseLineTransactionStockInsert(ConnectionCredential sqlConnCred, int accountJournalId,
|
||||||
string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amount, int quantity, int productId, int conditionId,
|
string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amount, int quantity, int productId, int conditionId,
|
||||||
int accountTaxCodeId, int stockDebitStatusId)
|
int accountTaxCodeId, int stockDebitStatusId)
|
||||||
{
|
{
|
||||||
return Core.Stock.StockCreate.WIP_StockInsertPurchase(sqlConnCred.ConnectionString, productId, conditionId, accountTaxCodeId, accountJournalId, quantity, stockDebitStatusId);
|
return new Core.Logic.Inventory.StockService().WIP_StockInsertPurchase(productId, conditionId, accountTaxCodeId, accountJournalId, quantity, stockDebitStatusId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PurchaseLineTransactionStockDelete(ConnectionCredential sqlConnCred, int stockId)
|
public void PurchaseLineTransactionStockDelete(ConnectionCredential sqlConnCred, int stockId)
|
||||||
{
|
{
|
||||||
Core.Stock.StockCreate.WIP_StockDeletePurchase(sqlConnCred.ConnectionString, stockId);
|
new Core.Logic.Inventory.StockService().WIP_StockDeletePurchase(stockId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,22 +43,22 @@ namespace bnhtrade.ComTypeLib
|
|||||||
{
|
{
|
||||||
public int StockInsertPurchase(ConnectionCredential sqlConnCred, int productId, int conditionId, int accountTaxCodeId, int accountJournalId, int quantity, int statusDebitId)
|
public int StockInsertPurchase(ConnectionCredential sqlConnCred, int productId, int conditionId, int accountTaxCodeId, int accountJournalId, int quantity, int statusDebitId)
|
||||||
{
|
{
|
||||||
return Core.Stock.StockCreate.WIP_StockInsertPurchase(sqlConnCred.ConnectionString, productId, conditionId, accountTaxCodeId, accountJournalId, quantity, statusDebitId);
|
return new Core.Logic.Inventory.StockService().WIP_StockInsertPurchase(productId, conditionId, accountTaxCodeId, accountJournalId, quantity, statusDebitId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int StockInsertOwnerIntroduced(ConnectionCredential sqlConnCred, [MarshalAs(UnmanagedType.Currency)] decimal amount, int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId)
|
public int StockInsertOwnerIntroduced(ConnectionCredential sqlConnCred, [MarshalAs(UnmanagedType.Currency)] decimal amount, int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId)
|
||||||
{
|
{
|
||||||
return Core.Stock.StockCreate.WIP_StockInsertOwnerIntroduced(sqlConnCred.ConnectionString, amount, quantity, productId, conditionId, accountTaxCodeId, entryDate, debitStatusId);
|
return new Core.Logic.Inventory.StockService().WIP_StockInsertOwnerIntroduced(amount, quantity, productId, conditionId, accountTaxCodeId, entryDate, debitStatusId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StockDeletePurchase(ConnectionCredential sqlConnCred, int stockId)
|
public void StockDeletePurchase(ConnectionCredential sqlConnCred, int stockId)
|
||||||
{
|
{
|
||||||
Core.Stock.StockCreate.WIP_StockDeletePurchase(sqlConnCred.ConnectionString, stockId);
|
new Core.Logic.Inventory.StockService().WIP_StockDeletePurchase(stockId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StockDeleteOwnerIntroduced(ConnectionCredential sqlConnCred, int stockId)
|
public void StockDeleteOwnerIntroduced(ConnectionCredential sqlConnCred, int stockId)
|
||||||
{
|
{
|
||||||
Core.Stock.StockCreate.WIP_StockDeleteOwnerIntroduced(sqlConnCred.ConnectionString, stockId);
|
new Core.Logic.Inventory.StockService().WIP_StockDeleteOwnerIntroduced(stockId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int StockReallocate(ConnectionCredential sqlConnCred, int stockId, int quantity, int debitStatusId, int creditStatusId, DateTime entryDate)
|
public int StockReallocate(ConnectionCredential sqlConnCred, int stockId, int quantity, int debitStatusId, int creditStatusId, DateTime entryDate)
|
||||||
|
|||||||
@@ -1,208 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data.SqlClient;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Transactions;
|
|
||||||
|
|
||||||
namespace bnhtrade.Core.Data.Database.Account
|
|
||||||
{
|
|
||||||
internal class CreateJournal : Connection
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Old code needs sorting
|
|
||||||
/// </summary>
|
|
||||||
public int AccountJournalInsert(int journalTypeId, DateTime entryDate, string currencyCode,
|
|
||||||
decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false)
|
|
||||||
{
|
|
||||||
int defaultDebit = 0;
|
|
||||||
int defaultCredit = 0;
|
|
||||||
|
|
||||||
// ensure date is UTC
|
|
||||||
entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc);
|
|
||||||
|
|
||||||
// debit and credit locks are checked in journal post method
|
|
||||||
using (TransactionScope scope = new TransactionScope())
|
|
||||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
// insert the journal entry
|
|
||||||
int journalId;
|
|
||||||
|
|
||||||
using (SqlCommand cmd = new SqlCommand(@"
|
|
||||||
INSERT INTO tblAccountJournal
|
|
||||||
(AccountJournalTypeID, EntryDate, IsLocked)
|
|
||||||
OUTPUT INSERTED.AccountJournalID
|
|
||||||
VALUES
|
|
||||||
(@journalTypeId, @entryDate, @lockEntry)
|
|
||||||
", conn))
|
|
||||||
{
|
|
||||||
// add parameters
|
|
||||||
cmd.Parameters.AddWithValue("@journalTypeId", journalTypeId);
|
|
||||||
cmd.Parameters.AddWithValue("@entryDate", entryDate.ToUniversalTime());
|
|
||||||
cmd.Parameters.AddWithValue("@lockEntry", lockEntry);
|
|
||||||
|
|
||||||
//execute
|
|
||||||
journalId = (int)cmd.ExecuteScalar();
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert journal entries
|
|
||||||
//bool postResult = AccountJournalPostInsert(sqlConnectionString, journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId);
|
|
||||||
bool postResult = AccountJournalPostInsert(journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId);
|
|
||||||
|
|
||||||
scope.Complete();
|
|
||||||
return journalId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Old code needs sorting
|
|
||||||
/// </summary>
|
|
||||||
internal bool AccountJournalPostInsert(int journalId, DateTime entryDate,
|
|
||||||
string currencyCode, decimal amount, int debitAccountId = 0, int creditAccountId = 0)
|
|
||||||
{
|
|
||||||
int defaultDebit;
|
|
||||||
int defaultCredit;
|
|
||||||
entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc);
|
|
||||||
|
|
||||||
using (TransactionScope scope = new TransactionScope())
|
|
||||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
// ensure their are no other entries
|
|
||||||
using (SqlCommand cmd = new SqlCommand(@"
|
|
||||||
SELECT
|
|
||||||
Count(tblAccountJournalPost.AccountJournalPostID) AS CountOfAccountJournalPostID
|
|
||||||
FROM
|
|
||||||
tblAccountJournalPost
|
|
||||||
WHERE
|
|
||||||
(((tblAccountJournalPost.AccountJournalID)=@AccountJournalID));
|
|
||||||
", conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@AccountJournalID", journalId);
|
|
||||||
|
|
||||||
int count = (int)cmd.ExecuteScalar();
|
|
||||||
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
throw new Exception("Unable the insert journal posts, post already present AccountJournalID=" + journalId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//checks
|
|
||||||
using (SqlCommand cmd = new SqlCommand(@"
|
|
||||||
SELECT
|
|
||||||
tblAccountJournalType.ChartOfAccountID_Debit, tblAccountJournalType.ChartOfAccountID_Credit
|
|
||||||
FROM
|
|
||||||
tblAccountJournal
|
|
||||||
INNER JOIN tblAccountJournalType
|
|
||||||
ON tblAccountJournal.AccountJournalTypeID = tblAccountJournalType.AccountJournalTypeID
|
|
||||||
WHERE
|
|
||||||
(((tblAccountJournal.AccountJournalID)=@journalId));
|
|
||||||
", conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@journalId", journalId);
|
|
||||||
|
|
||||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
|
||||||
{
|
|
||||||
if (reader.Read())
|
|
||||||
{
|
|
||||||
// debit check
|
|
||||||
if (reader.IsDBNull(0))
|
|
||||||
{
|
|
||||||
if (debitAccountId == 0)
|
|
||||||
{
|
|
||||||
throw new Exception("Debit Account ID required, default not set for journal type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
defaultDebit = reader.GetInt32(0);
|
|
||||||
if (debitAccountId == 0)
|
|
||||||
{
|
|
||||||
debitAccountId = defaultDebit;
|
|
||||||
}
|
|
||||||
else if (debitAccountId != defaultDebit)
|
|
||||||
{
|
|
||||||
throw new Exception("Debit Account ID supplied does not match default set for journal type");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
// credit check
|
|
||||||
if (reader.IsDBNull(1))
|
|
||||||
{
|
|
||||||
if (creditAccountId == 0)
|
|
||||||
{
|
|
||||||
throw new Exception("Credit Account ID required, default not set for journal type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
defaultCredit = reader.GetInt32(1);
|
|
||||||
if (creditAccountId == 0)
|
|
||||||
{
|
|
||||||
creditAccountId = defaultCredit;
|
|
||||||
}
|
|
||||||
else if (creditAccountId != defaultCredit)
|
|
||||||
{
|
|
||||||
throw new Exception("Credit Account ID supplied does not match default set for journal type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception("AccountJournalID '" + journalId + "' does not exist.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// currency conversion
|
|
||||||
if (currencyCode != "GBP")
|
|
||||||
{
|
|
||||||
amount = new Logic.Account.CurrencyService().CurrencyConvertToGbp(currencyCode, amount, entryDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure decimal is rounded
|
|
||||||
amount = Math.Round(amount, 2);
|
|
||||||
|
|
||||||
// insert debit post
|
|
||||||
using (SqlCommand cmd = new SqlCommand(@"
|
|
||||||
INSERT INTO tblAccountJournalPost
|
|
||||||
(AccountJournalID, AccountChartOfID, AmountGbp)
|
|
||||||
VALUES
|
|
||||||
(@AccountJournalId, @AccountChartOfId, @AmountGbp)
|
|
||||||
", conn))
|
|
||||||
{
|
|
||||||
// add parameters
|
|
||||||
cmd.Parameters.AddWithValue("@AccountJournalId", journalId);
|
|
||||||
cmd.Parameters.AddWithValue("@AccountChartOfId", debitAccountId);
|
|
||||||
cmd.Parameters.AddWithValue("@AmountGbp", amount);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert credit post
|
|
||||||
using (SqlCommand cmd = new SqlCommand(@"
|
|
||||||
INSERT INTO tblAccountJournalPost
|
|
||||||
(AccountJournalID, AccountChartOfID, AmountGbp)
|
|
||||||
VALUES
|
|
||||||
(@AccountJournalId, @AccountChartOfId, @AmountGbp)
|
|
||||||
", conn))
|
|
||||||
{
|
|
||||||
// add parameters
|
|
||||||
cmd.Parameters.AddWithValue("@AccountJournalId", journalId);
|
|
||||||
cmd.Parameters.AddWithValue("@AccountChartOfId", creditAccountId);
|
|
||||||
cmd.Parameters.AddWithValue("@AmountGbp", (amount * -1));
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.Complete();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data.SqlClient;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Transactions;
|
|
||||||
|
|
||||||
namespace bnhtrade.Core.Data.Database.Account
|
|
||||||
{
|
|
||||||
internal class UpdateJournal : Connection
|
|
||||||
{
|
|
||||||
public bool AccountJournalPostUpdate(int journalId, string currencyCode, decimal amount, int debitAccountId = 0, int creditAccountId = 0)
|
|
||||||
{
|
|
||||||
using (TransactionScope scope = new TransactionScope())
|
|
||||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
// retrive journal entry date
|
|
||||||
DateTime entryDate;
|
|
||||||
using (SqlCommand cmd = new SqlCommand(@"
|
|
||||||
SELECT
|
|
||||||
tblAccountJournal.EntryDate
|
|
||||||
FROM
|
|
||||||
tblAccountJournal
|
|
||||||
WHERE
|
|
||||||
(((tblAccountJournal.AccountJournalID)=@accountJournalId));
|
|
||||||
", conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@accountJournalId", journalId);
|
|
||||||
|
|
||||||
entryDate = DateTime.SpecifyKind((DateTime)cmd.ExecuteScalar(), DateTimeKind.Utc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete the original posts
|
|
||||||
using (SqlCommand cmd = new SqlCommand(@"
|
|
||||||
DELETE FROM
|
|
||||||
tblAccountJournalPost
|
|
||||||
WHERE
|
|
||||||
(((tblAccountJournalPost.AccountJournalID)=@accountJournalId));
|
|
||||||
", conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@accountJournalId", journalId);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
//insert new posts
|
|
||||||
//bool postResult = AccountJournalPostInsert(sqlConnectionString, journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId);
|
|
||||||
bool postResult = new Data.Database.Account.CreateJournal().AccountJournalPostInsert(journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId);
|
|
||||||
|
|
||||||
// update modified date on journal
|
|
||||||
using (SqlCommand cmd = new SqlCommand(@"
|
|
||||||
UPDATE
|
|
||||||
tblAccountJournal
|
|
||||||
SET
|
|
||||||
tblAccountJournal.LastModified=@utcNow
|
|
||||||
WHERE
|
|
||||||
(((tblAccountJournal.AccountJournalID)=@accountJournalId));
|
|
||||||
", conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@accountJournalId", journalId);
|
|
||||||
cmd.Parameters.AddWithValue("@utcNow", DateTime.UtcNow);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.Complete();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,12 +11,209 @@ using System.Transactions;
|
|||||||
|
|
||||||
namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||||
{
|
{
|
||||||
internal class JournalRepository : _Base, IJournalRepository
|
internal class AccountJournalRepository : _Base, IAccountJournalRepository
|
||||||
{
|
{
|
||||||
public JournalRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
|
public AccountJournalRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// create
|
||||||
|
//
|
||||||
|
public int AccountJournalInsert(int journalTypeId, DateTime entryDate, string currencyCode, decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false)
|
||||||
|
{
|
||||||
|
int defaultDebit = 0;
|
||||||
|
int defaultCredit = 0;
|
||||||
|
|
||||||
|
// ensure date is UTC
|
||||||
|
entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc);
|
||||||
|
|
||||||
|
// debit and credit locks are checked in journal post method
|
||||||
|
using (TransactionScope scope = new TransactionScope())
|
||||||
|
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||||
|
{
|
||||||
|
conn.Open();
|
||||||
|
|
||||||
|
// insert the journal entry
|
||||||
|
int journalId;
|
||||||
|
|
||||||
|
using (SqlCommand cmd = new SqlCommand(@"
|
||||||
|
INSERT INTO tblAccountJournal
|
||||||
|
(AccountJournalTypeID, EntryDate, IsLocked)
|
||||||
|
OUTPUT INSERTED.AccountJournalID
|
||||||
|
VALUES
|
||||||
|
(@journalTypeId, @entryDate, @lockEntry)
|
||||||
|
", conn))
|
||||||
|
{
|
||||||
|
// add parameters
|
||||||
|
cmd.Parameters.AddWithValue("@journalTypeId", journalTypeId);
|
||||||
|
cmd.Parameters.AddWithValue("@entryDate", entryDate.ToUniversalTime());
|
||||||
|
cmd.Parameters.AddWithValue("@lockEntry", lockEntry);
|
||||||
|
|
||||||
|
//execute
|
||||||
|
journalId = (int)cmd.ExecuteScalar();
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert journal entries
|
||||||
|
//bool postResult = AccountJournalPostInsert(sqlConnectionString, journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId);
|
||||||
|
bool postResult = AccountJournalPostInsert(journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId);
|
||||||
|
|
||||||
|
scope.Complete();
|
||||||
|
return journalId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Old code needs sorting
|
||||||
|
/// </summary>
|
||||||
|
internal bool AccountJournalPostInsert(int journalId, DateTime entryDate, string currencyCode, decimal amount, int debitAccountId = 0, int creditAccountId = 0)
|
||||||
|
{
|
||||||
|
int defaultDebit;
|
||||||
|
int defaultCredit;
|
||||||
|
entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc);
|
||||||
|
|
||||||
|
using (TransactionScope scope = new TransactionScope())
|
||||||
|
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||||
|
{
|
||||||
|
conn.Open();
|
||||||
|
|
||||||
|
// ensure their are no other entries
|
||||||
|
using (SqlCommand cmd = new SqlCommand(@"
|
||||||
|
SELECT
|
||||||
|
Count(tblAccountJournalPost.AccountJournalPostID) AS CountOfAccountJournalPostID
|
||||||
|
FROM
|
||||||
|
tblAccountJournalPost
|
||||||
|
WHERE
|
||||||
|
(((tblAccountJournalPost.AccountJournalID)=@AccountJournalID));
|
||||||
|
", conn))
|
||||||
|
{
|
||||||
|
cmd.Parameters.AddWithValue("@AccountJournalID", journalId);
|
||||||
|
|
||||||
|
int count = (int)cmd.ExecuteScalar();
|
||||||
|
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
throw new Exception("Unable the insert journal posts, post already present AccountJournalID=" + journalId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//checks
|
||||||
|
using (SqlCommand cmd = new SqlCommand(@"
|
||||||
|
SELECT
|
||||||
|
tblAccountJournalType.ChartOfAccountID_Debit, tblAccountJournalType.ChartOfAccountID_Credit
|
||||||
|
FROM
|
||||||
|
tblAccountJournal
|
||||||
|
INNER JOIN tblAccountJournalType
|
||||||
|
ON tblAccountJournal.AccountJournalTypeID = tblAccountJournalType.AccountJournalTypeID
|
||||||
|
WHERE
|
||||||
|
(((tblAccountJournal.AccountJournalID)=@journalId));
|
||||||
|
", conn))
|
||||||
|
{
|
||||||
|
cmd.Parameters.AddWithValue("@journalId", journalId);
|
||||||
|
|
||||||
|
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
if (reader.Read())
|
||||||
|
{
|
||||||
|
// debit check
|
||||||
|
if (reader.IsDBNull(0))
|
||||||
|
{
|
||||||
|
if (debitAccountId == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("Debit Account ID required, default not set for journal type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
defaultDebit = reader.GetInt32(0);
|
||||||
|
if (debitAccountId == 0)
|
||||||
|
{
|
||||||
|
debitAccountId = defaultDebit;
|
||||||
|
}
|
||||||
|
else if (debitAccountId != defaultDebit)
|
||||||
|
{
|
||||||
|
throw new Exception("Debit Account ID supplied does not match default set for journal type");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// credit check
|
||||||
|
if (reader.IsDBNull(1))
|
||||||
|
{
|
||||||
|
if (creditAccountId == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("Credit Account ID required, default not set for journal type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
defaultCredit = reader.GetInt32(1);
|
||||||
|
if (creditAccountId == 0)
|
||||||
|
{
|
||||||
|
creditAccountId = defaultCredit;
|
||||||
|
}
|
||||||
|
else if (creditAccountId != defaultCredit)
|
||||||
|
{
|
||||||
|
throw new Exception("Credit Account ID supplied does not match default set for journal type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("AccountJournalID '" + journalId + "' does not exist.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// currency conversion
|
||||||
|
if (currencyCode != "GBP")
|
||||||
|
{
|
||||||
|
amount = new Logic.Account.CurrencyService().CurrencyConvertToGbp(currencyCode, amount, entryDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure decimal is rounded
|
||||||
|
amount = Math.Round(amount, 2);
|
||||||
|
|
||||||
|
// insert debit post
|
||||||
|
using (SqlCommand cmd = new SqlCommand(@"
|
||||||
|
INSERT INTO tblAccountJournalPost
|
||||||
|
(AccountJournalID, AccountChartOfID, AmountGbp)
|
||||||
|
VALUES
|
||||||
|
(@AccountJournalId, @AccountChartOfId, @AmountGbp)
|
||||||
|
", conn))
|
||||||
|
{
|
||||||
|
// add parameters
|
||||||
|
cmd.Parameters.AddWithValue("@AccountJournalId", journalId);
|
||||||
|
cmd.Parameters.AddWithValue("@AccountChartOfId", debitAccountId);
|
||||||
|
cmd.Parameters.AddWithValue("@AmountGbp", amount);
|
||||||
|
|
||||||
|
cmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert credit post
|
||||||
|
using (SqlCommand cmd = new SqlCommand(@"
|
||||||
|
INSERT INTO tblAccountJournalPost
|
||||||
|
(AccountJournalID, AccountChartOfID, AmountGbp)
|
||||||
|
VALUES
|
||||||
|
(@AccountJournalId, @AccountChartOfId, @AmountGbp)
|
||||||
|
", conn))
|
||||||
|
{
|
||||||
|
// add parameters
|
||||||
|
cmd.Parameters.AddWithValue("@AccountJournalId", journalId);
|
||||||
|
cmd.Parameters.AddWithValue("@AccountChartOfId", creditAccountId);
|
||||||
|
cmd.Parameters.AddWithValue("@AmountGbp", (amount * -1));
|
||||||
|
|
||||||
|
cmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.Complete();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// read
|
||||||
|
//
|
||||||
|
|
||||||
public Dictionary<int, Core.Model.Account.Journal> ReadJournal(List<int> journalIdList)
|
public Dictionary<int, Core.Model.Account.Journal> ReadJournal(List<int> journalIdList)
|
||||||
{
|
{
|
||||||
var sqlBuilder = new SqlWhereBuilder();
|
var sqlBuilder = new SqlWhereBuilder();
|
||||||
@@ -146,7 +343,7 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get journalTypes from db
|
// get journalTypes from db
|
||||||
var journalTypeDict = new JournalRepository(_connection, _transaction).ReadJournalType(journalTypeIdList);
|
var journalTypeDict = new AccountJournalRepository(_connection, _transaction).ReadJournalType(journalTypeIdList);
|
||||||
|
|
||||||
// get accounts from db
|
// get accounts from db
|
||||||
var accountDict = new AccountCodeRepository(_connection, _transaction).ReadAccountCode(accountIdList);
|
var accountDict = new AccountCodeRepository(_connection, _transaction).ReadAccountCode(accountIdList);
|
||||||
@@ -325,6 +522,74 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
|||||||
return returnList;
|
return returnList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// update
|
||||||
|
//
|
||||||
|
|
||||||
|
public bool AccountJournalPostUpdate(int journalId, string currencyCode, decimal amount, int debitAccountId = 0, int creditAccountId = 0)
|
||||||
|
{
|
||||||
|
// retrive journal entry date
|
||||||
|
DateTime entryDate;
|
||||||
|
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = @"
|
||||||
|
SELECT
|
||||||
|
tblAccountJournal.EntryDate
|
||||||
|
FROM
|
||||||
|
tblAccountJournal
|
||||||
|
WHERE
|
||||||
|
(((tblAccountJournal.AccountJournalID)=@accountJournalId));";
|
||||||
|
|
||||||
|
cmd.Parameters.AddWithValue("@accountJournalId", journalId);
|
||||||
|
|
||||||
|
entryDate = DateTime.SpecifyKind((DateTime)cmd.ExecuteScalar(), DateTimeKind.Utc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete the original posts
|
||||||
|
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = @"
|
||||||
|
DELETE FROM
|
||||||
|
tblAccountJournalPost
|
||||||
|
WHERE
|
||||||
|
(((tblAccountJournalPost.AccountJournalID)=@accountJournalId));";
|
||||||
|
|
||||||
|
cmd.Parameters.AddWithValue("@accountJournalId", journalId);
|
||||||
|
|
||||||
|
cmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
//insert new posts
|
||||||
|
bool postResult = AccountJournalPostInsert(journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId);
|
||||||
|
|
||||||
|
// update modified date on journal
|
||||||
|
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = @"
|
||||||
|
UPDATE
|
||||||
|
tblAccountJournal
|
||||||
|
SET
|
||||||
|
tblAccountJournal.LastModified=@utcNow
|
||||||
|
WHERE
|
||||||
|
(((tblAccountJournal.AccountJournalID)=@accountJournalId));";
|
||||||
|
|
||||||
|
cmd.Parameters.AddWithValue("@accountJournalId", journalId);
|
||||||
|
cmd.Parameters.AddWithValue("@utcNow", DateTime.UtcNow);
|
||||||
|
|
||||||
|
cmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// delete
|
||||||
|
//
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Old code needs sorting
|
/// Old code needs sorting
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
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;
|
||||||
|
using System.Transactions;
|
||||||
|
|
||||||
|
namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||||
|
{
|
||||||
|
internal class PurchaseRepository : _Base, IPurchaseRepository
|
||||||
|
{
|
||||||
|
private static int accountJournalTypeIdNet = 1;
|
||||||
|
private static int accountJournalTypeIdTax = 2;
|
||||||
|
private static int stockJournalTypeId = 1;
|
||||||
|
private static int creditAccountId = 59;
|
||||||
|
private static int creditStatusId = 13;
|
||||||
|
private static int defaultAccountId = 138;
|
||||||
|
|
||||||
|
public PurchaseRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WIP_PurchaseLineTransactionNetInsert(int purchaseLineId, string currencyCode, decimal amountNet, DateTime entryDate, int debitAccountId = 0)
|
||||||
|
{
|
||||||
|
// default to 'Inventory, Receivable/Processing'
|
||||||
|
if (debitAccountId < 1)
|
||||||
|
{
|
||||||
|
debitAccountId = defaultAccountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create account journal entry
|
||||||
|
int journalId = new Data.Database.Repository.Implementation.AccountJournalRepository(_connection, _transaction).
|
||||||
|
AccountJournalInsert(accountJournalTypeIdNet, entryDate, currencyCode, amountNet, debitAccountId);
|
||||||
|
|
||||||
|
// add transaction to purchase line transaction table
|
||||||
|
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = @"
|
||||||
|
INSERT INTO
|
||||||
|
tblPurchaseLineTransaction
|
||||||
|
( PurchaseLineID, AccountJournalID )
|
||||||
|
VALUES
|
||||||
|
( @purchaseLineID, @accountJournalID );";
|
||||||
|
|
||||||
|
cmd.Parameters.AddWithValue("@purchaseLineID", purchaseLineId);
|
||||||
|
cmd.Parameters.AddWithValue("@accountJournalID", journalId);
|
||||||
|
|
||||||
|
int count = cmd.ExecuteNonQuery();
|
||||||
|
|
||||||
|
if (count != 1)
|
||||||
|
{
|
||||||
|
throw new Exception("Failed to insert record to tblPurchaseLineTransaction table");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WIP_PurchaseLineTransactionNetUpdate(int accountJouranlId, string currencyCode, decimal amountNet, int debitAccountId)
|
||||||
|
{
|
||||||
|
// stock accountId check
|
||||||
|
if (debitAccountId == 86)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = @"
|
||||||
|
SELECT Count(tblStock.StockID) AS CountOfStockID
|
||||||
|
FROM tblStock
|
||||||
|
WHERE (((tblStock.AccountJournalID)=@accountJouranlId));
|
||||||
|
";
|
||||||
|
cmd.Parameters.AddWithValue("@accountJouranlId", accountJouranlId);
|
||||||
|
|
||||||
|
count = (int)cmd.ExecuteScalar();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("Add account journal entry to stock before attempting this operation.");
|
||||||
|
}
|
||||||
|
else if (count > 1)
|
||||||
|
{
|
||||||
|
throw new Exception("Houston we have a problem! An account journal entry is assigned to " + count + " stock lines.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make the update
|
||||||
|
bool result = new Data.Database.Repository.Implementation.AccountJournalRepository(_connection, _transaction).
|
||||||
|
AccountJournalPostUpdate(accountJouranlId, currencyCode, amountNet, debitAccountId, creditAccountId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete after testing....
|
||||||
|
|
||||||
|
//public void WIP_PurchaseLineTransactionStockDelete(string sqlConnectionString, int accountJournalId, int stockId)
|
||||||
|
//{
|
||||||
|
// using (TransactionScope scope = new TransactionScope())
|
||||||
|
// using (SqlConnection conn = new SqlConnection(sqlConnectionString))
|
||||||
|
// {
|
||||||
|
// conn.Open();
|
||||||
|
|
||||||
|
// // get stock cost
|
||||||
|
// (int quantity, decimal totalCost) result = Stock.StockJournal.StockGetTotalQuantityAndCost(sqlConnectionString, stockId);
|
||||||
|
// decimal amount = result.totalCost;
|
||||||
|
|
||||||
|
// // delete accountJournalId from stock table
|
||||||
|
// using (SqlCommand cmd = new SqlCommand(@"
|
||||||
|
// UPDATE tblStock
|
||||||
|
// SET AccountJournalID=Null
|
||||||
|
// WHERE StockID=@stockId AND AccountJournalID=@accountJournalId;
|
||||||
|
// ", conn))
|
||||||
|
// {
|
||||||
|
// cmd.Parameters.AddWithValue("@stockId", stockId);
|
||||||
|
// cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
|
||||||
|
|
||||||
|
// int count = cmd.ExecuteNonQuery();
|
||||||
|
|
||||||
|
// if (count != 1)
|
||||||
|
// {
|
||||||
|
// throw new Exception("Integrity check failure! StockID=" + stockId + ", AccountJournalID=" + accountJournalId +
|
||||||
|
// " combination not found on stock table.");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // reset the account journal to default
|
||||||
|
// Account.AccountQuery.AccountJournalPostUpdate(sqlConnectionString, accountJournalId, "GBP", amount, defaultAccountId, creditAccountId);
|
||||||
|
|
||||||
|
// // delete the stock entry
|
||||||
|
// Stock.StockCreate.WIP_StockDeleteSub(sqlConnectionString, stockId);
|
||||||
|
|
||||||
|
// scope.Complete();
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
public void WIP_PurchaseLineTransactionDelete(int purchaseLineId, int accountJournalId)
|
||||||
|
{
|
||||||
|
// check accountJournalId does not exist in stock table
|
||||||
|
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = @"
|
||||||
|
SELECT StockID
|
||||||
|
FROM tblStock
|
||||||
|
WHERE AccountJournalID=@accountJournalId;";
|
||||||
|
|
||||||
|
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
|
||||||
|
|
||||||
|
using (var reader = cmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
if (reader.Read())
|
||||||
|
{
|
||||||
|
if (reader.Read())
|
||||||
|
{
|
||||||
|
throw new Exception("Integrity check failure! AccountJournalID=" + accountJournalId + " exists multiple time in stock table!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Delete stock first before proceeding, AccountJournalID=" + accountJournalId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete line in purchase line transaction table
|
||||||
|
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = @"
|
||||||
|
DELETE FROM tblPurchaseLineTransaction
|
||||||
|
WHERE AccountJournalID=@accountJournalId;";
|
||||||
|
|
||||||
|
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
|
||||||
|
|
||||||
|
int count = cmd.ExecuteNonQuery();
|
||||||
|
|
||||||
|
if (count != 1)
|
||||||
|
{
|
||||||
|
throw new Exception("Operation cancelled, failed to delete entry in tblPurchaseLineTransaction WHERE AccountJournalID=" + accountJournalId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete account journal entry
|
||||||
|
new AccountJournalRepository(_connection, _transaction).DeleteJournal(accountJournalId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,717 @@
|
|||||||
|
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;
|
||||||
|
using System.Transactions;
|
||||||
|
|
||||||
|
namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||||
|
{
|
||||||
|
internal class StockJournalRepository : _Base, IStockJournalRepository
|
||||||
|
{
|
||||||
|
public StockJournalRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create
|
||||||
|
//
|
||||||
|
|
||||||
|
// only to be assessable via code, use stock relocate to move stock bewtween status'
|
||||||
|
public int StockJournalInsert(int journalTypeId, int stockId, List<(int statusId, int quantity)> journalPosts,
|
||||||
|
DateTime entryDate, bool isNewStock = false)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* TODO: currently the consistancy check checks the journal after the entry has been inserted to the db, if the check fails
|
||||||
|
* the transaction scope is disposed, and the ne journal entries roll back. However, if this is done within a higher
|
||||||
|
* level transaction scope, this nested dispose() also rolls back the all transacopes scopes it is a child of.
|
||||||
|
*
|
||||||
|
* Therefore, a consistancy check needs to be simulated in code to negate the need to rollback/dispose of a db transaction.
|
||||||
|
* This would also have some slight performance benefits.
|
||||||
|
*
|
||||||
|
* Once you've done this, fix the SkuTransactionReconcile class: Currently it's transactionscope only covers updates.
|
||||||
|
* Need to set the scope to cover the intial table read (to lock the records). The issue above restricts this.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// balance and status IsCredit checks made by post insert function
|
||||||
|
|
||||||
|
// create the journal entry
|
||||||
|
int stockJournalId;
|
||||||
|
//consitancy check is required?
|
||||||
|
bool consistencyRequired = true;
|
||||||
|
// get date of most recent debit for status' that I will be crediting
|
||||||
|
if (isNewStock == false)
|
||||||
|
{
|
||||||
|
// build sql string
|
||||||
|
string stringSql = @"
|
||||||
|
SELECT
|
||||||
|
tblStockJournal.EntryDate
|
||||||
|
FROM
|
||||||
|
tblStockJournal
|
||||||
|
INNER JOIN tblStockJournalPost
|
||||||
|
ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
|
||||||
|
WHERE
|
||||||
|
tblStockJournal.StockID=@stockId
|
||||||
|
AND EntryDate>=@entryDate
|
||||||
|
AND tblStockJournalPost.Quantity>0
|
||||||
|
AND (";
|
||||||
|
|
||||||
|
bool firstDone = false;
|
||||||
|
foreach (var item in journalPosts)
|
||||||
|
{
|
||||||
|
if (item.quantity < 0)
|
||||||
|
{
|
||||||
|
if (firstDone)
|
||||||
|
{
|
||||||
|
stringSql = stringSql + " OR ";
|
||||||
|
}
|
||||||
|
stringSql = stringSql + "tblStockJournalPost.StockStatusID=" + item.statusId;
|
||||||
|
firstDone = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stringSql = stringSql + ");";
|
||||||
|
|
||||||
|
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.CommandText = stringSql;
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
|
||||||
|
cmd.Parameters.AddWithValue("@stockId", stockId);
|
||||||
|
cmd.Parameters.AddWithValue("@entryDate", entryDate.ToUniversalTime());
|
||||||
|
|
||||||
|
using (var reader = cmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
if (reader.HasRows)
|
||||||
|
{
|
||||||
|
consistencyRequired = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
consistencyRequired = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create journal entry
|
||||||
|
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = @"
|
||||||
|
INSERT INTO tblStockJournal ( EntryDate, StockJournalTypeID, StockID, IsLocked )
|
||||||
|
OUTPUT INSERTED.StockJournalID
|
||||||
|
VALUES ( @EntryDate, @journalTypeId, @stockID, @isLocked );";
|
||||||
|
|
||||||
|
cmd.Parameters.AddWithValue("@stockID", stockId);
|
||||||
|
cmd.Parameters.AddWithValue("@journalTypeId", journalTypeId);
|
||||||
|
cmd.Parameters.AddWithValue("@EntryDate", entryDate.ToUniversalTime());
|
||||||
|
cmd.Parameters.AddWithValue("@isLocked", isNewStock);
|
||||||
|
|
||||||
|
//execute
|
||||||
|
stockJournalId = (int)cmd.ExecuteScalar();
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert journal posts into database
|
||||||
|
//new Data.Database.Stock
|
||||||
|
Core.Stock.StockJournal.StockJournalPostInsert(conn, stockId, stockJournalId, journalPosts, isNewStock);
|
||||||
|
|
||||||
|
// consistency check
|
||||||
|
bool consistencyResult = true;
|
||||||
|
if (consistencyRequired)
|
||||||
|
{
|
||||||
|
consistencyResult = false;
|
||||||
|
// build list of effected status'
|
||||||
|
var statusIdEffected = new List<int>();
|
||||||
|
foreach (var item in journalPosts)
|
||||||
|
{
|
||||||
|
if (item.quantity < 0)
|
||||||
|
{
|
||||||
|
statusIdEffected.Add(item.statusId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// run check
|
||||||
|
consistencyResult = Stock.StockJournal.WIP_StockJournalConsistencyCheck(sqlConnectionString, stockId, statusIdEffected);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (consistencyResult)
|
||||||
|
{
|
||||||
|
// commit
|
||||||
|
scope.Complete();
|
||||||
|
return stockJournalId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Unable to insert stock journal entry, consistancy check failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read
|
||||||
|
//
|
||||||
|
|
||||||
|
public int ReadStatusBalanceBySku(string sku, int statusId)
|
||||||
|
{
|
||||||
|
int statusBalance = new int();
|
||||||
|
|
||||||
|
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = @"
|
||||||
|
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);";
|
||||||
|
|
||||||
|
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 ReadStatusBalanceByStockNumber(int stockNumber, int statusId)
|
||||||
|
{
|
||||||
|
int statusBalance = new int();
|
||||||
|
|
||||||
|
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = @"
|
||||||
|
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);";
|
||||||
|
|
||||||
|
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 ReadStatusBalanceByStockId(int stockId, int statusId)
|
||||||
|
{
|
||||||
|
int statusBalance = new int();
|
||||||
|
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = @"
|
||||||
|
SELECT
|
||||||
|
SUM(tblStockJournalPost.Quantity) AS Balance
|
||||||
|
FROM
|
||||||
|
tblStockJournal
|
||||||
|
INNER JOIN tblStockJournalPost
|
||||||
|
ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
|
||||||
|
WHERE
|
||||||
|
(tblStockJournal.StockID = @stockId )
|
||||||
|
AND (tblStockJournalPost.StockStatusID = @statusId );";
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// update
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Delete
|
||||||
|
//
|
||||||
|
|
||||||
|
public void StockJournalDelete(int stockJournalId)
|
||||||
|
{
|
||||||
|
// 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<int>();
|
||||||
|
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 void StockJournalPostInsert(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<int, int>();
|
||||||
|
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<int, bool>();
|
||||||
|
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 void StockJournalPostDelete(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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool WIP_StockJournalConsistencyCheck( int stockId, List<int> statusIdEffected = null)
|
||||||
|
{
|
||||||
|
if (statusIdEffected == null)
|
||||||
|
{
|
||||||
|
statusIdEffected = new List<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no list supplied, build list of all used status' for stockId
|
||||||
|
if (statusIdEffected.Count == 0)
|
||||||
|
{
|
||||||
|
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = @"
|
||||||
|
SELECT
|
||||||
|
tblStockJournalPost.StockStatusID
|
||||||
|
FROM
|
||||||
|
tblStockJournal
|
||||||
|
INNER JOIN tblStockJournalPost
|
||||||
|
ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
|
||||||
|
WHERE
|
||||||
|
tblStockJournal.StockID=@stockId
|
||||||
|
GROUP BY
|
||||||
|
tblStockJournalPost.StockStatusID;";
|
||||||
|
|
||||||
|
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<int, bool>();
|
||||||
|
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 = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = sqlString;
|
||||||
|
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 = _connection.CreateCommand() as SqlCommand)
|
||||||
|
{
|
||||||
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = @"
|
||||||
|
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;";
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,8 +44,8 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
|||||||
|
|
||||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||||
{
|
{
|
||||||
cmd.CommandText = sql;
|
|
||||||
cmd.Transaction = _transaction as SqlTransaction;
|
cmd.Transaction = _transaction as SqlTransaction;
|
||||||
|
cmd.CommandText = sql;
|
||||||
|
|
||||||
sqlwhere.AddParametersToSqlCommand(cmd);
|
sqlwhere.AddParametersToSqlCommand(cmd);
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace bnhtrade.Core.Data.Database.Repository.Interface
|
namespace bnhtrade.Core.Data.Database.Repository.Interface
|
||||||
{
|
{
|
||||||
internal interface IJournalRepository
|
internal interface IAccountJournalRepository
|
||||||
{
|
{
|
||||||
|
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<int, Core.Model.Account.Journal> ReadJournal(List<int> journalIdList);
|
Dictionary<int, Core.Model.Account.Journal> ReadJournal(List<int> journalIdList);
|
||||||
bool ReadJournalIsLocked(int journalId);
|
bool ReadJournalIsLocked(int journalId);
|
||||||
Dictionary<int, Model.Account.JournalType> ReadJournalType(List<int> journalTypeIds = null, List<string> typeTitles = null);
|
Dictionary<int, Model.Account.JournalType> ReadJournalType(List<int> journalTypeIds = null, List<string> typeTitles = null);
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
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 IPurchaseRepository
|
||||||
|
{
|
||||||
|
void WIP_PurchaseLineTransactionNetInsert(int purchaseLineId, string currencyCode, decimal amountNet, DateTime entryDate, int debitAccountId = 0);
|
||||||
|
void WIP_PurchaseLineTransactionNetUpdate(int accountJouranlId, string currencyCode, decimal amountNet, int debitAccountId);
|
||||||
|
void WIP_PurchaseLineTransactionDelete(int purchaseLineId, int accountJournalId);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
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 IStockJournalRepository
|
||||||
|
{
|
||||||
|
int ReadStatusBalanceBySku(string sku, int statusId);
|
||||||
|
int ReadStatusBalanceByStockNumber(int stockNumber, int statusId);
|
||||||
|
int ReadStatusBalanceByStockId(int stockId, int statusId);
|
||||||
|
Dictionary<string, int> ReadStatusBalanceByStatusId(int statusId);
|
||||||
|
void StockJournalDelete(int stockJournalId);
|
||||||
|
void StockJournalPostInsert(int stockId, int stockJournalId, List<(int statusId, int quantity)> journalPosts, bool isNewStock = false);
|
||||||
|
void StockJournalPostDelete(int stockJournalId);
|
||||||
|
bool WIP_StockJournalConsistencyCheck(int stockId, List<int> statusIdEffected = null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -373,7 +373,7 @@ namespace bnhtrade.Core.Data.Database.Stock
|
|||||||
{
|
{
|
||||||
if (item.Value < 0 && dicStatusIsCreditOnly[item.Key] == false)
|
if (item.Value < 0 && dicStatusIsCreditOnly[item.Key] == false)
|
||||||
{
|
{
|
||||||
int quantity = new Data.Database.Stock.ReadStatusBalance().ByStockId(stockId, item.Key);
|
int quantity = new Data.Database.Stock.ReadStatusBalance().ReadStatusBalanceByStockId(stockId, item.Key);
|
||||||
|
|
||||||
if (quantity + item.Value < 0)
|
if (quantity + item.Value < 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,76 +13,7 @@ namespace bnhtrade.Core.Data.Database.Stock
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public int BySku(string sku, int statusId)
|
public int ReadStatusBalanceByStockId(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 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();
|
int statusBalance = new int();
|
||||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||||
@@ -125,7 +56,7 @@ namespace bnhtrade.Core.Data.Database.Stock
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="statusId">The stock status id</param>
|
/// <param name="statusId">The stock status id</param>
|
||||||
/// <returns>Dictionary of SKUs and the balance of each</returns>
|
/// <returns>Dictionary of SKUs and the balance of each</returns>
|
||||||
public Dictionary<string, int> ByStatusId(int statusId)
|
public Dictionary<string, int> ReadStatusBalanceByStatusId(int statusId)
|
||||||
{
|
{
|
||||||
var returnList = new Dictionary<string, int>();
|
var returnList = new Dictionary<string, int>();
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,11 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
|
|||||||
IExportInvoiceRepository ExportInvoiceRepository { get; }
|
IExportInvoiceRepository ExportInvoiceRepository { get; }
|
||||||
IAmazonSettlementRepository AmazonSettlementRepository { get; }
|
IAmazonSettlementRepository AmazonSettlementRepository { get; }
|
||||||
IInvoiceRepository InvoiceRepository { get; }
|
IInvoiceRepository InvoiceRepository { get; }
|
||||||
IJournalRepository JournalRepository { get; }
|
IPurchaseRepository PurchaseRepository { get; }
|
||||||
|
IAccountJournalRepository JournalRepository { get; }
|
||||||
ISequenceGenerator SequenceGenerator { get; }
|
ISequenceGenerator SequenceGenerator { get; }
|
||||||
ISkuRepository SkuRepository { get; }
|
ISkuRepository SkuRepository { get; }
|
||||||
|
IStockJournalRepository StockJournalRepository { get; }
|
||||||
IStockRepository StockRepository { get; }
|
IStockRepository StockRepository { get; }
|
||||||
|
|
||||||
// Methods to manage the transaction
|
// Methods to manage the transaction
|
||||||
|
|||||||
@@ -24,9 +24,11 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
|
|||||||
private ICurrencyRepository _currencyRepository;
|
private ICurrencyRepository _currencyRepository;
|
||||||
private IExportInvoiceRepository _exportInvoiceRepository;
|
private IExportInvoiceRepository _exportInvoiceRepository;
|
||||||
private IInvoiceRepository _invoiceRepository;
|
private IInvoiceRepository _invoiceRepository;
|
||||||
private IJournalRepository _journalRepository;
|
private IPurchaseRepository _purchaseRepository;
|
||||||
|
private IAccountJournalRepository _journalRepository;
|
||||||
private ISequenceGenerator _sequenceGenerator;
|
private ISequenceGenerator _sequenceGenerator;
|
||||||
private ISkuRepository _skuRepository;
|
private ISkuRepository _skuRepository;
|
||||||
|
private IStockJournalRepository _stockJournalRespository;
|
||||||
private IStockRepository _stockRepository;
|
private IStockRepository _stockRepository;
|
||||||
|
|
||||||
internal UnitOfWork()
|
internal UnitOfWork()
|
||||||
@@ -108,13 +110,25 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IJournalRepository JournalRepository
|
public IPurchaseRepository PurchaseRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_purchaseRepository == null)
|
||||||
|
{
|
||||||
|
_purchaseRepository = new PurchaseRepository(_connection, _transaction);
|
||||||
|
}
|
||||||
|
return _purchaseRepository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAccountJournalRepository JournalRepository
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_journalRepository == null)
|
if (_journalRepository == null)
|
||||||
{
|
{
|
||||||
_journalRepository = new JournalRepository(_connection, _transaction);
|
_journalRepository = new AccountJournalRepository(_connection, _transaction);
|
||||||
}
|
}
|
||||||
return _journalRepository;
|
return _journalRepository;
|
||||||
}
|
}
|
||||||
@@ -144,6 +158,18 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IStockJournalRepository StockJournalRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_stockJournalRespository == null)
|
||||||
|
{
|
||||||
|
_stockJournalRespository = new StockJournalRepository(_connection, _transaction);
|
||||||
|
}
|
||||||
|
return _stockJournalRespository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public IStockRepository StockRepository
|
public IStockRepository StockRepository
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data.SqlClient;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Transactions;
|
|
||||||
|
|
||||||
namespace bnhtrade.Core.Logic.Account
|
|
||||||
{
|
|
||||||
public class Journal : UnitOfWorkBase
|
|
||||||
{
|
|
||||||
public int AccountJournalInsert(int journalTypeId, DateTime entryDate, string currencyCode,
|
|
||||||
decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false)
|
|
||||||
{
|
|
||||||
return new Data.Database.Account.CreateJournal().AccountJournalInsert(journalTypeId, entryDate, currencyCode,
|
|
||||||
amount, debitAccountId, creditAccountId, lockEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AccountJournalDelete(int accountJournalId)
|
|
||||||
{
|
|
||||||
return WithUnitOfWork(uow =>
|
|
||||||
{
|
|
||||||
bool result = uow.JournalRepository.DeleteJournal(accountJournalId);
|
|
||||||
CommitIfOwned(uow);
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
44
src/bnhtrade.Core/Logic/Account/JournalService.cs
Normal file
44
src/bnhtrade.Core/Logic/Account/JournalService.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using bnhtrade.Core.Data.Database.UnitOfWork;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.SqlClient;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Transactions;
|
||||||
|
|
||||||
|
namespace bnhtrade.Core.Logic.Account
|
||||||
|
{
|
||||||
|
public class JournalService : UnitOfWorkBase
|
||||||
|
{
|
||||||
|
public JournalService()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal JournalService(IUnitOfWork unitOfWork) : base(unitOfWork)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public int JournalInsert(int journalTypeId, DateTime entryDate, string currencyCode,
|
||||||
|
decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false)
|
||||||
|
{
|
||||||
|
return WithUnitOfWork(uow =>
|
||||||
|
{
|
||||||
|
int journalId = uow.JournalRepository.AccountJournalInsert(journalTypeId, entryDate, currencyCode,
|
||||||
|
amount, debitAccountId, creditAccountId, lockEntry);
|
||||||
|
CommitIfOwned(uow);
|
||||||
|
return journalId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool JournalDelete(int accountJournalId)
|
||||||
|
{
|
||||||
|
return WithUnitOfWork(uow =>
|
||||||
|
{
|
||||||
|
bool result = uow.JournalRepository.DeleteJournal(accountJournalId);
|
||||||
|
CommitIfOwned(uow);
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,18 @@
|
|||||||
using System;
|
using bnhtrade.Core.Data.Database.UnitOfWork;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data.SqlClient;
|
using System.Data.SqlClient;
|
||||||
using System.Transactions;
|
using System.Transactions;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace bnhtrade.Core.Logic.Sku
|
namespace bnhtrade.Core.Logic.Inventory
|
||||||
{
|
{
|
||||||
public class SkuService : UnitOfWorkBase
|
public class SkuService : UnitOfWorkBase
|
||||||
{
|
{
|
||||||
|
public SkuService() : base() { }
|
||||||
|
|
||||||
|
internal SkuService(IUnitOfWork unitOfWork) : base(unitOfWork) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used for retriving an SKU ID by parameters. If no match, can create a new SKU if required.
|
/// Used for retriving an SKU ID by parameters. If no match, can create a new SKU if required.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
45
src/bnhtrade.Core/Logic/Inventory/StockJournalService.cs
Normal file
45
src/bnhtrade.Core/Logic/Inventory/StockJournalService.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using bnhtrade.Core.Data.Database.UnitOfWork;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace bnhtrade.Core.Logic.Inventory
|
||||||
|
{
|
||||||
|
public class StockJournalService : UnitOfWorkBase
|
||||||
|
{
|
||||||
|
public StockJournalService() { }
|
||||||
|
|
||||||
|
internal StockJournalService(IUnitOfWork unitOfWork) : base(unitOfWork) { }
|
||||||
|
|
||||||
|
public void StockJournalDelete(int stockJournalId)
|
||||||
|
{
|
||||||
|
WithUnitOfWork(uow =>
|
||||||
|
{
|
||||||
|
if (stockJournalId <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Stock journal ID must be greater than zero", nameof(stockJournalId));
|
||||||
|
}
|
||||||
|
bool result = uow.StockJournalRepository.DeleteStockJournal(stockJournalId);
|
||||||
|
CommitIfOwned(uow);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Failed to delete stock journal with ID {stockJournalId}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool WIP_StockJournalConsistencyCheck(int stockId, List<int> statusIdEffected = null)
|
||||||
|
{
|
||||||
|
return WithUnitOfWork(uow =>
|
||||||
|
{
|
||||||
|
if (stockId <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId));
|
||||||
|
}
|
||||||
|
return uow.StockJournalRepository.WIP_StockJournalConsistencyCheck(stockId, statusIdEffected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
443
src/bnhtrade.Core/Logic/Inventory/StockService.cs
Normal file
443
src/bnhtrade.Core/Logic/Inventory/StockService.cs
Normal file
@@ -0,0 +1,443 @@
|
|||||||
|
using bnhtrade.Core.Data.Database.UnitOfWork;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Transactions;
|
||||||
|
using static System.Formats.Asn1.AsnWriter;
|
||||||
|
|
||||||
|
namespace bnhtrade.Core.Logic.Inventory
|
||||||
|
{
|
||||||
|
public class StockService : UnitOfWorkBase
|
||||||
|
{
|
||||||
|
public StockService() : base() { }
|
||||||
|
|
||||||
|
internal StockService(IUnitOfWork unitOfWork) : base(unitOfWork) { }
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
conn.Open();
|
||||||
|
|
||||||
|
// add account journal entry
|
||||||
|
int accountJournalId = new Logic.Account.JournalService().JournalInsert(accountJournalType, entryDate, currencyCode, amount);
|
||||||
|
|
||||||
|
// make the stock insert
|
||||||
|
int stockId = WIP_StockInsertSub(sqlConnectionString, productId, conditionId, accountTaxCodeId,
|
||||||
|
accountJournalId, stockJournalType, entryDate, quantity, debitStatusId);
|
||||||
|
|
||||||
|
scope.Complete();
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
Core.Stock.StockJournal.StockJournalDelete(sqlConnectionString, 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 int WIP_StockInsertPurchase(int productId, int conditionId, int accountTaxCodeId, int accountJournalId, int quantity, int statusDebitId)
|
||||||
|
{
|
||||||
|
DateTime stockJournalEntryDate;
|
||||||
|
int stockJournalTypeId = 1;
|
||||||
|
|
||||||
|
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WIP_StockDeletePurchase(int stockId)
|
||||||
|
{
|
||||||
|
WIP_StockDeleteSub(sqlConnectionString, stockId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WIP_StockDeleteOwnerIntroduced(int stockId)
|
||||||
|
{
|
||||||
|
WIP_StockDelete(sqlConnectionString, stockId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
39
src/bnhtrade.Core/Logic/Inventory/StockStatusService.cs
Normal file
39
src/bnhtrade.Core/Logic/Inventory/StockStatusService.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using bnhtrade.Core.Data.Database.UnitOfWork;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace bnhtrade.Core.Logic.Inventory
|
||||||
|
{
|
||||||
|
public class StockStatusService : UnitOfWorkBase
|
||||||
|
{
|
||||||
|
public StockStatusService() : base() { }
|
||||||
|
|
||||||
|
internal StockStatusService(IUnitOfWork unitOfWork) : base(unitOfWork) { }
|
||||||
|
|
||||||
|
/// <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 WithUnitOfWork(uow =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(sku))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("SKU number is null, empty, or whitespace", nameof(sku));
|
||||||
|
}
|
||||||
|
|
||||||
|
return uow.StockJournalRepository.ReadStatusBalanceBySku(sku, statusId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/bnhtrade.Core/Logic/Purchase/PurchaseService.cs
Normal file
44
src/bnhtrade.Core/Logic/Purchase/PurchaseService.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using bnhtrade.Core.Data.Database.UnitOfWork;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Transactions;
|
||||||
|
|
||||||
|
namespace bnhtrade.Core.Logic.Purchase
|
||||||
|
{
|
||||||
|
public class PurchaseService : UnitOfWorkBase
|
||||||
|
{
|
||||||
|
public PurchaseService() : base() { }
|
||||||
|
|
||||||
|
internal PurchaseService(IUnitOfWork unitOfWork) : base(unitOfWork) { }
|
||||||
|
|
||||||
|
public void WIP_PurchaseLineTransactionNetInsert(int purchaseLineId, string currencyCode, decimal amountNet, DateTime entryDate, int debitAccountId = 0)
|
||||||
|
{
|
||||||
|
WithUnitOfWork(uow =>
|
||||||
|
{
|
||||||
|
uow.PurchaseRepository.WIP_PurchaseLineTransactionNetInsert(purchaseLineId, currencyCode, amountNet, entryDate, debitAccountId);
|
||||||
|
CommitIfOwned(uow);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WIP_PurchaseLineTransactionNetUpdate(int accountJouranlId, string currencyCode, decimal amountNet, int debitAccountId)
|
||||||
|
{
|
||||||
|
WithUnitOfWork(uow =>
|
||||||
|
{
|
||||||
|
uow.PurchaseRepository.WIP_PurchaseLineTransactionNetUpdate(accountJouranlId, currencyCode, amountNet, debitAccountId);
|
||||||
|
CommitIfOwned(uow);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WIP_PurchaseLineTransactionDelete(int purchaseLineId, int accountJournalId)
|
||||||
|
{
|
||||||
|
WithUnitOfWork(uow =>
|
||||||
|
{
|
||||||
|
uow.PurchaseRepository.WIP_PurchaseLineTransactionDelete(purchaseLineId, accountJournalId);
|
||||||
|
CommitIfOwned(uow);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,22 +12,9 @@ namespace bnhtrade.Core.Logic.Stock
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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().BySku(sku, statusId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Return the avaliable balance of a status, includes datetime that each stockNumber became avaiable.
|
/// Return the avaliable balance of a status, includes datetime that each stockNumber became avaiable.
|
||||||
/// Useful for checking availability before moving stock/sku retrospectivly
|
/// Useful for checking availability before moving stock/sku retrospectivly
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="skuNumber">SKU number</param>
|
/// <param name="skuNumber">SKU number</param>
|
||||||
/// <param name="statusId">Status ID</param>
|
/// <param name="statusId">Status ID</param>
|
||||||
@@ -131,7 +118,7 @@ namespace bnhtrade.Core.Logic.Stock
|
|||||||
/// <returns>Dictionary of SKUs and the repective balance of each</returns>
|
/// <returns>Dictionary of SKUs and the repective balance of each</returns>
|
||||||
public Dictionary<string, int> GetSkuQuantity(int statusId)
|
public Dictionary<string, int> GetSkuQuantity(int statusId)
|
||||||
{
|
{
|
||||||
return new Data.Database.Stock.ReadStatusBalance().ByStatusId(statusId);
|
return new Data.Database.Stock.ReadStatusBalance().ReadStatusBalanceByStatusId(statusId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using bnhtrade.Core.Logic;
|
using bnhtrade.Core.Data.Database.UnitOfWork;
|
||||||
|
using bnhtrade.Core.Logic;
|
||||||
using Microsoft.Data.SqlClient;
|
using Microsoft.Data.SqlClient;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -234,573 +235,8 @@ namespace bnhtrade.Core
|
|||||||
|
|
||||||
namespace Stock
|
namespace Stock
|
||||||
{
|
{
|
||||||
public class StockCreate : UnitOfWorkBase
|
public class StockJournal : UnitOfWorkBase
|
||||||
{
|
{
|
||||||
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())
|
|
||||||
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
// add account journal entry
|
|
||||||
int accountJournalId = new Logic.Account.Journal().AccountJournalInsert(accountJournalType, entryDate, currencyCode, amount);
|
|
||||||
|
|
||||||
// make the stock insert
|
|
||||||
int stockId = WIP_StockInsertSub(sqlConnectionString, productId, conditionId, accountTaxCodeId,
|
|
||||||
accountJournalId, stockJournalType, entryDate, quantity, debitStatusId);
|
|
||||||
|
|
||||||
scope.Complete();
|
|
||||||
return stockId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
using (TransactionScope scope = new TransactionScope())
|
|
||||||
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
// 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.Sku.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 static void WIP_StockDelete(string sqlConnectionString, 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())
|
|
||||||
{
|
|
||||||
if (reader.Read())
|
|
||||||
{
|
|
||||||
accountJournalType = reader.GetInt32(1);
|
|
||||||
stockJournalType = reader.GetInt32(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception("Integrity check failed, cancelling StockDeleteOwnerIntroduced");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
Stock.StockCreate.WIP_StockDeleteSubAccountJournalEntry(sqlConnectionString, stockId);
|
|
||||||
|
|
||||||
// remove stock
|
|
||||||
Stock.StockCreate.WIP_StockDeleteSub(sqlConnectionString, stockId);
|
|
||||||
|
|
||||||
scope.Complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void WIP_StockDeleteSub(string sqlConnectionString, 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
|
|
||||||
Stock.StockJournal.StockJournalDelete(sqlConnectionString, 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// to be used by other methods within a transaction scope
|
|
||||||
private static void WIP_StockDeleteSubAccountJournalEntry(string sqlConnectionString, 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.JournalRepository(conn, trans).DeleteJournal(accountJournalId);
|
|
||||||
|
|
||||||
trans.Commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int WIP_StockInsertPurchase(string sqlConnectionString, int productId, int conditionId, int accountTaxCodeId, int accountJournalId, int quantity, int statusDebitId)
|
|
||||||
{
|
|
||||||
DateTime stockJournalEntryDate;
|
|
||||||
int stockJournalTypeId = 1;
|
|
||||||
|
|
||||||
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
|
|
||||||
{
|
|
||||||
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 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)
|
|
||||||
{
|
|
||||||
int accountJournalType = 3;
|
|
||||||
int stockJournalType = 2;
|
|
||||||
string currencyCode = "GBP";
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
WIP_StockDeleteSub(sqlConnectionString, stockId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void WIP_StockDeleteOwnerIntroduced(string sqlConnectionString, int stockId)
|
|
||||||
{
|
|
||||||
WIP_StockDelete(sqlConnectionString, stockId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class StockJournal
|
|
||||||
{
|
|
||||||
// only to be assessable via code, use stock relocate to move stock bewtween status'
|
|
||||||
public static int StockJournalInsert(string sqlConnectionString, int journalTypeId, int stockId, List<(int statusId, int quantity)> journalPosts,
|
|
||||||
DateTime entryDate, bool isNewStock = false)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* TODO: currently the consistancy check checks the journal after the entry has been inserted to the db, if the check fails
|
|
||||||
* the transaction scope is disposed, and the ne journal entries roll back. However, if this is done within a higher
|
|
||||||
* level transaction scope, this nested dispose() also rolls back the all transacopes scopes it is a child of.
|
|
||||||
*
|
|
||||||
* Therefore, a consistancy check needs to be simulated in code to negate the need to rollback/dispose of a db transaction.
|
|
||||||
* This would also have some slight performance benefits.
|
|
||||||
*
|
|
||||||
* Once you've done this, fix the SkuTransactionReconcile class: Currently it's transactionscope only covers updates.
|
|
||||||
* Need to set the scope to cover the intial table read (to lock the records). The issue above restricts this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// balance and status IsCredit checks made by post insert function
|
|
||||||
|
|
||||||
// create the journal entry
|
|
||||||
int stockJournalId;
|
|
||||||
using (TransactionScope scope = new TransactionScope())
|
|
||||||
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
//consitancy check is required?
|
|
||||||
bool consistencyRequired = true;
|
|
||||||
// get date of most recent debit for status' that I will be crediting
|
|
||||||
if (isNewStock == false)
|
|
||||||
{
|
|
||||||
// build sql string
|
|
||||||
string stringSql = @"
|
|
||||||
SELECT
|
|
||||||
tblStockJournal.EntryDate
|
|
||||||
FROM
|
|
||||||
tblStockJournal
|
|
||||||
INNER JOIN tblStockJournalPost
|
|
||||||
ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
|
|
||||||
WHERE
|
|
||||||
tblStockJournal.StockID=@stockId
|
|
||||||
AND EntryDate>=@entryDate
|
|
||||||
AND tblStockJournalPost.Quantity>0
|
|
||||||
AND (";
|
|
||||||
|
|
||||||
bool firstDone = false;
|
|
||||||
foreach (var item in journalPosts)
|
|
||||||
{
|
|
||||||
if (item.quantity < 0)
|
|
||||||
{
|
|
||||||
if (firstDone)
|
|
||||||
{
|
|
||||||
stringSql = stringSql + " OR ";
|
|
||||||
}
|
|
||||||
stringSql = stringSql + "tblStockJournalPost.StockStatusID=" + item.statusId;
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
consistencyRequired = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
consistencyRequired = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create journal entry
|
|
||||||
using (SqlCommand cmd = new SqlCommand(@"
|
|
||||||
INSERT INTO tblStockJournal ( EntryDate, StockJournalTypeID, StockID, IsLocked )
|
|
||||||
OUTPUT INSERTED.StockJournalID
|
|
||||||
VALUES ( @EntryDate, @journalTypeId, @stockID, @isLocked );
|
|
||||||
", conn))
|
|
||||||
{
|
|
||||||
// add parameters
|
|
||||||
cmd.Parameters.AddWithValue("@stockID", stockId);
|
|
||||||
cmd.Parameters.AddWithValue("@journalTypeId", journalTypeId);
|
|
||||||
cmd.Parameters.AddWithValue("@EntryDate", entryDate.ToUniversalTime());
|
|
||||||
cmd.Parameters.AddWithValue("@isLocked", isNewStock);
|
|
||||||
|
|
||||||
//execute
|
|
||||||
stockJournalId = (int)cmd.ExecuteScalar();
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert journal posts into database
|
|
||||||
//new Data.Database.Stock
|
|
||||||
Core.Stock.StockJournal.StockJournalPostInsert(conn, stockId, stockJournalId, journalPosts, isNewStock);
|
|
||||||
|
|
||||||
// consistency check
|
|
||||||
bool consistencyResult = true;
|
|
||||||
if (consistencyRequired)
|
|
||||||
{
|
|
||||||
consistencyResult = false;
|
|
||||||
// build list of effected status'
|
|
||||||
var statusIdEffected = new List<int>();
|
|
||||||
foreach (var item in journalPosts)
|
|
||||||
{
|
|
||||||
if (item.quantity < 0)
|
|
||||||
{
|
|
||||||
statusIdEffected.Add(item.statusId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// run check
|
|
||||||
consistencyResult = Stock.StockJournal.WIP_StockJournalConsistencyCheck(sqlConnectionString, stockId, statusIdEffected);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (consistencyResult)
|
|
||||||
{
|
|
||||||
// commit
|
|
||||||
scope.Complete();
|
|
||||||
return stockJournalId;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception("Unable to insert stock journal entry, consistancy check failed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void StockJournalDelete(string sqlConnectionString, int stockJournalId)
|
public static void StockJournalDelete(string sqlConnectionString, int stockJournalId)
|
||||||
{
|
{
|
||||||
using (TransactionScope scope = new TransactionScope())
|
using (TransactionScope scope = new TransactionScope())
|
||||||
@@ -1034,7 +470,7 @@ namespace bnhtrade.Core
|
|||||||
{
|
{
|
||||||
if (item.Value < 0 && dicStatusIsCreditOnly[item.Key] == false)
|
if (item.Value < 0 && dicStatusIsCreditOnly[item.Key] == false)
|
||||||
{
|
{
|
||||||
int quantity = new Data.Database.Stock.ReadStatusBalance().ByStockId(stockId, item.Key);
|
int quantity = new Data.Database.Stock.ReadStatusBalance().ReadStatusBalanceByStockId(stockId, item.Key);
|
||||||
|
|
||||||
if (quantity + item.Value < 0)
|
if (quantity + item.Value < 0)
|
||||||
{
|
{
|
||||||
@@ -1323,202 +759,6 @@ namespace bnhtrade.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Purchase
|
|
||||||
{
|
|
||||||
public class PurchaseQuery
|
|
||||||
{
|
|
||||||
private static int accountJournalTypeIdNet = 1;
|
|
||||||
private static int accountJournalTypeIdTax = 2;
|
|
||||||
private static int stockJournalTypeId = 1;
|
|
||||||
private static int creditAccountId = 59;
|
|
||||||
private static int creditStatusId = 13;
|
|
||||||
private static int defaultAccountId = 138;
|
|
||||||
|
|
||||||
public static void WIP_PurchaseLineTransactionNetInsert(string sqlConnectionString, int purchaseLineId,
|
|
||||||
string currencyCode, decimal amountNet, DateTime entryDate, int debitAccountId = 0)
|
|
||||||
{
|
|
||||||
// default to 'Inventory, Receivable/Processing'
|
|
||||||
if (debitAccountId < 1)
|
|
||||||
{
|
|
||||||
debitAccountId = defaultAccountId;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (TransactionScope scope = new TransactionScope())
|
|
||||||
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
// create account journal entry
|
|
||||||
int journalId = new Data.Database.Account.CreateJournal().AccountJournalInsert(
|
|
||||||
accountJournalTypeIdNet, entryDate, currencyCode, amountNet, debitAccountId);
|
|
||||||
|
|
||||||
// add transaction to purchase line transaction table
|
|
||||||
using (SqlCommand cmd = new SqlCommand(@"
|
|
||||||
INSERT INTO
|
|
||||||
tblPurchaseLineTransaction
|
|
||||||
( PurchaseLineID, AccountJournalID )
|
|
||||||
VALUES
|
|
||||||
( @purchaseLineID, @accountJournalID );
|
|
||||||
", conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@purchaseLineID", purchaseLineId);
|
|
||||||
cmd.Parameters.AddWithValue("@accountJournalID", journalId);
|
|
||||||
|
|
||||||
int count = cmd.ExecuteNonQuery();
|
|
||||||
|
|
||||||
if (count != 1)
|
|
||||||
{
|
|
||||||
throw new Exception("Operation cancelled, failed to update tblPurchaseLineTransaction!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//commit the transaction and return value
|
|
||||||
scope.Complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void WIP_PurchaseLineTransactionNetUpdate(string sqlConnectionString, int accountJouranlId,
|
|
||||||
string currencyCode, decimal amountNet, int debitAccountId)
|
|
||||||
{
|
|
||||||
using (TransactionScope scope = new TransactionScope())
|
|
||||||
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
// stock accountId check
|
|
||||||
if (debitAccountId == 86)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
using (SqlCommand cmd = new SqlCommand(@"
|
|
||||||
SELECT Count(tblStock.StockID) AS CountOfStockID
|
|
||||||
FROM tblStock
|
|
||||||
WHERE (((tblStock.AccountJournalID)=@accountJouranlId));
|
|
||||||
", conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@accountJouranlId", accountJouranlId);
|
|
||||||
|
|
||||||
count = (int)cmd.ExecuteScalar();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count == 0)
|
|
||||||
{
|
|
||||||
throw new Exception("Add account journal entry to stock before attempting this operation.");
|
|
||||||
}
|
|
||||||
else if (count > 1)
|
|
||||||
{
|
|
||||||
throw new Exception("Houston we have a problem! An account journal entry is assigned to " + count + " stock lines.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// make the update
|
|
||||||
bool result = new Data.Database.Account.UpdateJournal().AccountJournalPostUpdate(accountJouranlId, currencyCode, amountNet, debitAccountId, creditAccountId);
|
|
||||||
|
|
||||||
scope.Complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete after testing....
|
|
||||||
|
|
||||||
//public static void WIP_PurchaseLineTransactionStockDelete(string sqlConnectionString, int accountJournalId, int stockId)
|
|
||||||
//{
|
|
||||||
// using (TransactionScope scope = new TransactionScope())
|
|
||||||
// using (SqlConnection conn = new SqlConnection(sqlConnectionString))
|
|
||||||
// {
|
|
||||||
// conn.Open();
|
|
||||||
|
|
||||||
// // get stock cost
|
|
||||||
// (int quantity, decimal totalCost) result = Stock.StockJournal.StockGetTotalQuantityAndCost(sqlConnectionString, stockId);
|
|
||||||
// decimal amount = result.totalCost;
|
|
||||||
|
|
||||||
// // delete accountJournalId from stock table
|
|
||||||
// using (SqlCommand cmd = new SqlCommand(@"
|
|
||||||
// UPDATE tblStock
|
|
||||||
// SET AccountJournalID=Null
|
|
||||||
// WHERE StockID=@stockId AND AccountJournalID=@accountJournalId;
|
|
||||||
// ", conn))
|
|
||||||
// {
|
|
||||||
// cmd.Parameters.AddWithValue("@stockId", stockId);
|
|
||||||
// cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
|
|
||||||
|
|
||||||
// int count = cmd.ExecuteNonQuery();
|
|
||||||
|
|
||||||
// if (count != 1)
|
|
||||||
// {
|
|
||||||
// throw new Exception("Integrity check failure! StockID=" + stockId + ", AccountJournalID=" + accountJournalId +
|
|
||||||
// " combination not found on stock table.");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // reset the account journal to default
|
|
||||||
// Account.AccountQuery.AccountJournalPostUpdate(sqlConnectionString, accountJournalId, "GBP", amount, defaultAccountId, creditAccountId);
|
|
||||||
|
|
||||||
// // delete the stock entry
|
|
||||||
// Stock.StockCreate.WIP_StockDeleteSub(sqlConnectionString, stockId);
|
|
||||||
|
|
||||||
// scope.Complete();
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
public static void WIP_PurchaseLineTransactionDelete(string sqlConnectionString, int purchaseLineId, int accountJournalId)
|
|
||||||
{
|
|
||||||
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var trans = conn.BeginTransaction();
|
|
||||||
|
|
||||||
// check accountJournalId does not exist in stock table
|
|
||||||
using (SqlCommand cmd = new SqlCommand(@"
|
|
||||||
SELECT StockID
|
|
||||||
FROM tblStock
|
|
||||||
WHERE AccountJournalID=@accountJournalId;
|
|
||||||
", conn))
|
|
||||||
{
|
|
||||||
cmd.Transaction = trans;
|
|
||||||
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
{
|
|
||||||
if (reader.Read())
|
|
||||||
{
|
|
||||||
if (reader.Read())
|
|
||||||
{
|
|
||||||
throw new Exception("Integrity check failure! AccountJournalID=" + accountJournalId + " exists multiple time in stock table!");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception("Delete stock first before proceeding, AccountJournalID=" + accountJournalId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete line in purchase line transaction table
|
|
||||||
using (SqlCommand cmd = new SqlCommand(@"
|
|
||||||
DELETE FROM tblPurchaseLineTransaction
|
|
||||||
WHERE AccountJournalID=@accountJournalId;
|
|
||||||
", conn))
|
|
||||||
{
|
|
||||||
cmd.Transaction = trans;
|
|
||||||
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
|
|
||||||
|
|
||||||
int count = cmd.ExecuteNonQuery();
|
|
||||||
|
|
||||||
if (count != 1)
|
|
||||||
{
|
|
||||||
throw new Exception("Operation cancelled, failed to delete entry in tblPurchaseLineTransaction WHERE AccountJournalID=" + accountJournalId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete account journal entry
|
|
||||||
new Data.Database.Repository.Implementation.JournalRepository(conn, trans).DeleteJournal(accountJournalId);
|
|
||||||
|
|
||||||
trans.Commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MiscFunction
|
public class MiscFunction
|
||||||
{
|
{
|
||||||
public static string TraceMessage(
|
public static string TraceMessage(
|
||||||
|
|||||||
Reference in New Issue
Block a user