mirror of
https://github.com/stokebob/bnhtrade.git
synced 2026-05-18 19:48:23 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6151652b9f | |||
| db9a2b9ccc | |||
| 8e8c4138e3 | |||
| f921e79671 | |||
| db8eafe571 | |||
| b2bcb72469 | |||
| 80dfc2a9d7 | |||
| c28d2c6060 | |||
| ecf48ba8b4 | |||
| 2d751ebf80 | |||
| afd4bae10e | |||
| be9944f066 | |||
| 7a28e2cc66 | |||
| 97b945e0cb | |||
| ee487db21f | |||
| d4170d2b80 | |||
| e2af1e4f99 | |||
| eb959dd6e2 | |||
| c0f7f1a476 | |||
| 8c3b00c75c | |||
| 479acecdbc |
@@ -35,13 +35,13 @@ namespace bnhtrade.ComTypeLib
|
||||
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)
|
||||
{
|
||||
return new Core.Logic.Account.Journal().AccountJournalInsert(journalTypeId, entryDate,
|
||||
return new Core.Logic.Account.AccountJournalService().JournalInsert(journalTypeId, entryDate,
|
||||
currencyCode, amount, debitAccountId, creditAccountId, lockEntry);
|
||||
}
|
||||
|
||||
public bool AccountJournalDelete(ConnectionCredential sqlConnCred, int accountJournalId)
|
||||
{
|
||||
return new Core.Logic.Account.Journal().AccountJournalDelete(accountJournalId);
|
||||
return new Core.Logic.Account.AccountJournalService().DeleteJournal(accountJournalId);
|
||||
}
|
||||
|
||||
[return: MarshalAs(UnmanagedType.Currency)]
|
||||
|
||||
@@ -35,32 +35,30 @@ namespace bnhtrade.ComTypeLib.Purchase
|
||||
string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amountNet,
|
||||
DateTime entryDate)
|
||||
{
|
||||
Core.Purchase.PurchaseQuery.WIP_PurchaseLineTransactionNetInsert(sqlConnCred.ConnectionString,
|
||||
purchaseLineId, currencyCode, amountNet, entryDate);
|
||||
new Core.Logic.Purchase.PurchaseService().WIP_PurchaseLineTransactionNetInsert(purchaseLineId, currencyCode, amountNet, entryDate);
|
||||
}
|
||||
|
||||
public void PurchaseLineTransactionNetUpdate(ConnectionCredential sqlConnCred, int accountJouranlId,
|
||||
string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amountNet, int debitAccountId)
|
||||
{
|
||||
Core.Purchase.PurchaseQuery.WIP_PurchaseLineTransactionNetUpdate(sqlConnCred.ConnectionString,
|
||||
accountJouranlId, currencyCode, amountNet, debitAccountId);
|
||||
new Core.Logic.Purchase.PurchaseService().WIP_PurchaseLineTransactionNetUpdate(accountJouranlId, currencyCode, amountNet, debitAccountId);
|
||||
}
|
||||
|
||||
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,
|
||||
string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amount, int quantity, int productId, int conditionId,
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
Core.Stock.StockCreate.WIP_StockDeletePurchase(sqlConnCred.ConnectionString, stockId);
|
||||
new Core.Logic.Inventory.StockService().WIP_StockDeletePurchase(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)
|
||||
@@ -70,7 +70,7 @@ namespace bnhtrade.ComTypeLib
|
||||
|
||||
public void StockJournalDelete(ConnectionCredential sqlConnCred, int stockJournalId)
|
||||
{
|
||||
Core.Stock.StockJournal.StockJournalDelete(sqlConnCred.ConnectionString, stockJournalId);
|
||||
new Core.Logic.Inventory.StockJournalService().StockJournalDelete(stockJournalId);
|
||||
}
|
||||
|
||||
public object ReconcileStockTransactions(ConnectionCredential sqlConnCred)
|
||||
@@ -128,7 +128,7 @@ namespace bnhtrade.ComTypeLib
|
||||
|
||||
public bool StockJournalConsistencyCheck(ConnectionCredential sqlConnCred, int stockId)
|
||||
{
|
||||
return Core.Stock.StockJournal.WIP_StockJournalConsistencyCheck(sqlConnCred.ConnectionString, stockId, null);
|
||||
return new Core.Logic.Inventory.StockJournalService().WIP_StockJournalConsistencyCheck(stockId, null);
|
||||
}
|
||||
|
||||
public void SkuTransactionAdd(ConnectionCredential sqlConnCred, int quantity, string skuNumber, string transactionTypeCode, DateTime transactionDate)
|
||||
|
||||
@@ -12,7 +12,21 @@ namespace bnhtrade.Core
|
||||
{
|
||||
public string GetAppDataPath()
|
||||
{
|
||||
string path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\bnhtrade\";
|
||||
string path = null;
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
|
||||
+ @"\bnhtrade\";
|
||||
}
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
{
|
||||
path = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)
|
||||
+ "/.bnhtrade/";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException("Unsupported operating system");
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Data.SqlClient;
|
||||
using System.Configuration;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.IO;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Import
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using bnhtrade.Core.Logic.Amazon.Fba;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Eventing.Reader;
|
||||
using System.IO;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
@@ -3,7 +3,7 @@ using FikaAmazonAPI.ConstructFeed.Messages;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Dapper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
+488
@@ -0,0 +1,488 @@
|
||||
using bnhtrade.Core.Data.Database._BoilerPlate;
|
||||
using bnhtrade.Core.Data.Database.Repository.Interface;
|
||||
using bnhtrade.Core.Model.Account;
|
||||
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 AccountJournalRepository : _Base, IAccountJournalRepository
|
||||
{
|
||||
public AccountJournalRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// create
|
||||
//
|
||||
|
||||
public int InsertJournalHeader(int accountJournalTypeId, DateTime entryDate, bool lockEntry = false)
|
||||
{
|
||||
// ensure date is UTC
|
||||
if (entryDate.Kind != DateTimeKind.Utc)
|
||||
{
|
||||
throw new Exception("DateTime kind must be utc");
|
||||
}
|
||||
|
||||
// debit and credit locks are checked in journal post method
|
||||
// insert the journal entry
|
||||
int journalId;
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
INSERT INTO tblAccountJournal
|
||||
(AccountJournalTypeID, EntryDate, IsLocked)
|
||||
OUTPUT INSERTED.AccountJournalID
|
||||
VALUES
|
||||
(@journalTypeId, @entryDate, @lockEntry);";
|
||||
|
||||
// add parameters
|
||||
cmd.Parameters.AddWithValue("@journalTypeId", accountJournalTypeId);
|
||||
cmd.Parameters.AddWithValue("@entryDate", entryDate.ToUniversalTime());
|
||||
cmd.Parameters.AddWithValue("@lockEntry", lockEntry);
|
||||
|
||||
//execute
|
||||
journalId = (int)cmd.ExecuteScalar();
|
||||
}
|
||||
|
||||
return journalId;
|
||||
}
|
||||
|
||||
public int InsertJournalPost(int accountJournalId, int accountChartOfId, decimal amountGbp)
|
||||
{
|
||||
if (accountJournalId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Invalid journal ID provided.", nameof(accountJournalId));
|
||||
}
|
||||
if (accountChartOfId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Invalid account chart of ID provided.", nameof(accountChartOfId));
|
||||
}
|
||||
if (amountGbp == 0)
|
||||
{
|
||||
throw new ArgumentException("Amount cannot be zero.", nameof(amountGbp));
|
||||
}
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
INSERT INTO tblAccountJournalPost
|
||||
(AccountJournalID, AccountChartOfID, AmountGbp)
|
||||
OUTPUT INSERTED.AccountJournalPostID
|
||||
VALUES
|
||||
(@accountJournalId, @accountChartOfId, @amountGbp);";
|
||||
|
||||
// add parameters
|
||||
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
|
||||
cmd.Parameters.AddWithValue("@accountChartOfId", accountChartOfId);
|
||||
cmd.Parameters.AddWithValue("@amountGbp", amountGbp);
|
||||
|
||||
// execute
|
||||
return (int)cmd.ExecuteScalar();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// read
|
||||
//
|
||||
|
||||
public Dictionary<int, Model.Account.JournalBuilder> ReadJournalBuilder(List<int> journalIdList)
|
||||
{
|
||||
var sqlBuilder = new SqlWhereBuilder();
|
||||
var returnDict = new Dictionary<int, Model.Account.JournalBuilder>();
|
||||
|
||||
//build sql query
|
||||
string sql = @"
|
||||
SELECT tblAccountJournal.AccountJournalID
|
||||
,tblAccountJournal.AccountJournalTypeID
|
||||
,tblAccountJournal.EntryDate
|
||||
,tblAccountJournal.PostDate
|
||||
,tblAccountJournal.LastModified
|
||||
,tblAccountJournal.IsLocked
|
||||
,tblAccountJournalPost.AccountJournalPostID
|
||||
,tblAccountJournalPost.AccountChartOfID
|
||||
,tblAccountJournalPost.AmountGbp
|
||||
FROM tblAccountJournal
|
||||
INNER JOIN tblAccountJournalPost ON tblAccountJournal.AccountJournalID = tblAccountJournalPost.AccountJournalID
|
||||
WHERE 1 = 1 ";
|
||||
|
||||
// build the where statments
|
||||
if (journalIdList.Any())
|
||||
{
|
||||
sqlBuilder.In("tblAccountJournal.AccountJournalID", journalIdList, "AND");
|
||||
}
|
||||
|
||||
// append where string to the sql
|
||||
if (sqlBuilder.IsSetSqlWhereString)
|
||||
{
|
||||
sql = sql + sqlBuilder.SqlWhereString;
|
||||
}
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = sql;
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
|
||||
if (sqlBuilder.ParameterListIsSet)
|
||||
{
|
||||
sqlBuilder.AddParametersToSqlCommand(cmd);
|
||||
}
|
||||
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
int journalId = reader.GetInt32(0);
|
||||
if (returnDict.ContainsKey(journalId) == false)
|
||||
{
|
||||
var journalBuilder = new Model.Account.JournalBuilder();
|
||||
journalBuilder.JournalId = journalId;
|
||||
journalBuilder.JournalTypeId = reader.GetInt32(1);
|
||||
journalBuilder.EntryDate = DateTime.SpecifyKind(reader.GetDateTime(2), DateTimeKind.Utc);
|
||||
journalBuilder.PostDate = DateTime.SpecifyKind(reader.GetDateTime(3), DateTimeKind.Utc);
|
||||
journalBuilder.LastModified = DateTime.SpecifyKind(reader.GetDateTime(4), DateTimeKind.Utc);
|
||||
journalBuilder.IsLocked = reader.GetBoolean(5);
|
||||
journalBuilder.JournalBuilderPosts = new List<Model.Account.JournalBuilder.JournalPostBuilder>();
|
||||
|
||||
returnDict.Add(journalId, journalBuilder);
|
||||
}
|
||||
|
||||
var journalBuilderLine = new Model.Account.JournalBuilder.JournalPostBuilder();
|
||||
journalBuilderLine.PostId = reader.GetInt32(6);
|
||||
journalBuilderLine.AccountId = reader.GetInt32(7);
|
||||
journalBuilderLine.AmountGbp = reader.GetDecimal(8);
|
||||
|
||||
returnDict[journalId].JournalBuilderPosts.Add(journalBuilderLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnDict;
|
||||
}
|
||||
|
||||
public DateTime ReadJournalEntryDate(int journalId)
|
||||
{
|
||||
if (journalId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Invalid journal ID provided.", nameof(journalId));
|
||||
}
|
||||
|
||||
string sql = @"
|
||||
SELECT tblAccountJournal.EntryDate
|
||||
FROM tblAccountJournal
|
||||
WHERE (((tblAccountJournal.AccountJournalID)=@accountJournalId));";
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = sql;
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
|
||||
cmd.Parameters.AddWithValue("@accountJournalId", journalId);
|
||||
|
||||
object obj = cmd.ExecuteScalar();
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
throw new Exception("Journal entry not found for AccountJournalID=" + journalId);
|
||||
}
|
||||
|
||||
return DateTime.SpecifyKind((DateTime)obj, DateTimeKind.Utc);
|
||||
}
|
||||
}
|
||||
|
||||
public int CountJournalPosts(int accountJournalId)
|
||||
{
|
||||
if (accountJournalId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Invalid journal ID provided.", nameof(accountJournalId));
|
||||
}
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
SELECT
|
||||
Count(tblAccountJournalPost.AccountJournalPostID) AS CountOfAccountJournalPostID
|
||||
FROM
|
||||
tblAccountJournalPost
|
||||
WHERE
|
||||
(((tblAccountJournalPost.AccountJournalID)=@AccountJournalID));";
|
||||
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
|
||||
return (int)cmd.ExecuteScalar();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsJournalDebitAssetType(int accountJournalId)
|
||||
{
|
||||
if (accountJournalId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Invalid journal ID provided.", nameof(accountJournalId));
|
||||
}
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
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;";
|
||||
|
||||
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
|
||||
|
||||
if ((int)cmd.ExecuteScalar() < 1)
|
||||
{
|
||||
return false; // no debit posts of type Asset found
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test for locked journal entry
|
||||
/// </summary>
|
||||
/// <returns>True/False or null on no records found</returns>
|
||||
public bool? IsJournalLocked(int accountJournalId)
|
||||
{
|
||||
if (accountJournalId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Invalid journal ID provided.", nameof(accountJournalId));
|
||||
}
|
||||
|
||||
string sql = @"
|
||||
SELECT
|
||||
tblAccountJournal.IsLocked
|
||||
FROM
|
||||
tblAccountJournal
|
||||
WHERE
|
||||
tblAccountJournal.AccountJournalID=@accountJournalId;";
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = sql;
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
|
||||
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
|
||||
|
||||
object obj = cmd.ExecuteScalar();
|
||||
if (obj == null || obj == DBNull.Value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (bool)obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<(int, string, int?, int?)> ReadJournalType(List<int> accountJournalTypeIds = null, List<string> typeTitles = null)
|
||||
{
|
||||
var returnList = new List<(int, string, int?, int?)>();
|
||||
var sqlBuilder = new SqlWhereBuilder();
|
||||
|
||||
//build sql query
|
||||
string sql = @"
|
||||
SELECT [AccountJournalTypeID]
|
||||
,[TypeTitle]
|
||||
,[ChartOfAccountID_Debit]
|
||||
,[ChartOfAccountID_Credit]
|
||||
FROM [e2A].[dbo].[tblAccountJournalType]
|
||||
WHERE 1 = 1 ";
|
||||
|
||||
// build the where statments
|
||||
if (accountJournalTypeIds.Any())
|
||||
{
|
||||
sqlBuilder.In("AccountJournalTypeID", accountJournalTypeIds, "AND");
|
||||
}
|
||||
if (typeTitles.Any())
|
||||
{
|
||||
sqlBuilder.In("TypeTitle", typeTitles, "AND");
|
||||
}
|
||||
|
||||
// append where string to the sql
|
||||
if (sqlBuilder.IsSetSqlWhereString)
|
||||
{
|
||||
sql = sql + sqlBuilder.SqlWhereString;
|
||||
}
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = sql;
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
|
||||
if (sqlBuilder.ParameterListIsSet)
|
||||
{
|
||||
sqlBuilder.AddParametersToSqlCommand(cmd);
|
||||
}
|
||||
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
// read from db and create object
|
||||
int journalTypeId = reader.GetInt32(0);
|
||||
string title = reader.GetString(1);
|
||||
int? debitAccountId = null;
|
||||
if (!reader.IsDBNull(2))
|
||||
debitAccountId = reader.GetInt32(2);
|
||||
int? creditAccountId = null;
|
||||
if (!reader.IsDBNull(3))
|
||||
creditAccountId = reader.GetInt32(3);
|
||||
|
||||
returnList.Add((journalTypeId, title, debitAccountId, creditAccountId));
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the default debit and credit account IDs associated with a specific account journal.
|
||||
/// </summary>
|
||||
/// <remarks>This method queries the database to retrieve the default debit and credit account IDs
|
||||
/// for the specified account journal. If the account journal does not exist, an exception is thrown. Ensure
|
||||
/// that the provided <paramref name="accountJournalId"/> is valid.</remarks>
|
||||
/// <param name="accountJournalId">The unique identifier of the account journal for which to retrieve the default debit and credit account IDs.</param>
|
||||
/// <returns>A tuple containing two nullable integers: <list type="bullet"> <item><description>The first value represents
|
||||
/// the default debit account ID, or <see langword="null"/> if no debit account is set.</description></item>
|
||||
/// <item><description>The second value represents the default credit account ID, or <see langword="null"/> if
|
||||
/// no credit account is set.</description></item> </list></returns>
|
||||
/// <exception cref="Exception">Thrown if the specified <paramref name="accountJournalId"/> does not exist in the database.</exception>
|
||||
public (int?, int?) ReadJournalTypeDefaultDebitCredit(int accountJournalId)
|
||||
{
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
SELECT
|
||||
tblAccountJournalType.ChartOfAccountID_Debit, tblAccountJournalType.ChartOfAccountID_Credit
|
||||
FROM
|
||||
tblAccountJournal
|
||||
INNER JOIN tblAccountJournalType
|
||||
ON tblAccountJournal.AccountJournalTypeID = tblAccountJournalType.AccountJournalTypeID
|
||||
WHERE
|
||||
(((tblAccountJournal.AccountJournalID)=@journalId));";
|
||||
|
||||
cmd.Parameters.AddWithValue("@journalId", accountJournalId);
|
||||
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
if (reader.Read())
|
||||
{
|
||||
int? defaultDebit = null;
|
||||
int? defaultCredit = null;
|
||||
|
||||
// debit check
|
||||
if (reader.IsDBNull(0) == false)
|
||||
{
|
||||
defaultDebit = reader.GetInt32(0);
|
||||
}
|
||||
// credit check
|
||||
if (reader.IsDBNull(1) == false)
|
||||
{
|
||||
defaultCredit = reader.GetInt32(1);
|
||||
}
|
||||
return (defaultDebit, defaultCredit);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("AccountJournalID '" + accountJournalId + "' does not exist.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// update
|
||||
//
|
||||
|
||||
public bool UpdateJournalEntryModifiedDate(int accountJournalId)
|
||||
{
|
||||
if (accountJournalId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Invalid journal ID provided.", nameof(accountJournalId));
|
||||
}
|
||||
|
||||
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", accountJournalId);
|
||||
cmd.Parameters.AddWithValue("@utcNow", DateTime.UtcNow);
|
||||
|
||||
if (cmd.ExecuteNonQuery() == 1)
|
||||
{
|
||||
return true; // update successful
|
||||
}
|
||||
else
|
||||
{
|
||||
return false; // update failed, journal ID may not exist
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// delete
|
||||
//
|
||||
|
||||
public int DeleteJournalHeader(int accountJournalId)
|
||||
{
|
||||
if (accountJournalId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Invalid journal ID provided.", nameof(accountJournalId));
|
||||
}
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
DELETE FROM
|
||||
tblAccountJournal
|
||||
WHERE
|
||||
AccountJournalID=@accountJournalId;";
|
||||
|
||||
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
|
||||
return cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
public int DeleteJournalPostAll(int accountJournalId)
|
||||
{
|
||||
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", accountJournalId);
|
||||
return cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+95
-94
@@ -2,7 +2,6 @@
|
||||
using bnhtrade.Core.Data.Database.Repository.Interface;
|
||||
using bnhtrade.Core.Model.Amazon;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.VisualBasic.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
@@ -369,7 +368,7 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||
//
|
||||
|
||||
/// <summary>
|
||||
/// Update the settlement report marketplace name by settlement Id (not table id)
|
||||
/// Update the settlement report marketplace name by settlement Id (not row id)
|
||||
/// </summary>
|
||||
/// <param name="settlementId">Settlement id (not table/record id) of the settlement to update</param>
|
||||
/// <param name="marketPlaceName">marketplace name</param>
|
||||
@@ -433,13 +432,13 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||
/// Takes a Settlement Report flat file from Amazon and imports it into the database.
|
||||
/// </summary>
|
||||
/// <param name="filePath">path to the Amazon report flat file</param>
|
||||
/// <param name="reportId">The unique Amazon SP-API report id (not settlement id)</param>
|
||||
/// <param name="spapiReportId">The unique Amazon SP-API report id (not settlement id)</param>
|
||||
/// <returns></returns>
|
||||
public bool CreateAmazonSettlements(string filePath, string reportId)
|
||||
public bool CreateAmazonSettlements(string filePath, string spapiReportId)
|
||||
{
|
||||
int settlementReportId = 0;
|
||||
string settlementRef = "";
|
||||
bool marketPlaceUpdated = false;
|
||||
string settlementRef = null;
|
||||
string marketplaceName = null;
|
||||
decimal settlementAmount = 0m;
|
||||
int lineNumber = 2;
|
||||
int lineSkip = 0;
|
||||
@@ -479,17 +478,17 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||
int indexQuantityPurchased = Array.IndexOf(headers, "quantity-purchased");
|
||||
int indexPromotionId = Array.IndexOf(headers, "promotion-id");
|
||||
|
||||
string currency = "";
|
||||
string currency = null;
|
||||
|
||||
string fileRow;
|
||||
while ((fileRow = reader.ReadLine()) != null)
|
||||
{
|
||||
Console.Write("\rParsing record: " + lineNumber);
|
||||
//split line into array
|
||||
string[] items = fileRow.Split('\t');
|
||||
if (items.Length != columnCount)
|
||||
string[] rowArray = fileRow.Split('\t');
|
||||
if (rowArray.Length != columnCount)
|
||||
{
|
||||
// skip line
|
||||
// skip line, check settlement total at the end
|
||||
lineSkip = lineSkip + 1;
|
||||
_log.LogWarning(
|
||||
"Line #" + lineNumber + " skipped due to no enough element in row.",
|
||||
@@ -498,28 +497,25 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||
}
|
||||
else if (lineNumber == 2)
|
||||
{
|
||||
// check if settlement has already been imported
|
||||
settlementRef = rowArray[indexSettlementId];
|
||||
currency = rowArray[indexCurrency];
|
||||
settlementAmount = decimal.Parse(rowArray[indexTotalAmount].Replace(",", "."));
|
||||
|
||||
// check if settlement has already been imported
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = "SELECT COUNT(*) FROM tblImportAmazonSettlementReport WHERE [settlement-id]=@settlementId;";
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.Parameters.AddWithValue("@settlementId", items[indexSettlementId]);
|
||||
cmd.Parameters.AddWithValue("@settlementId", rowArray[indexSettlementId]);
|
||||
|
||||
int recordCount = (int)cmd.ExecuteScalar();
|
||||
if (recordCount > 0)
|
||||
{
|
||||
SetSpapiReportId(items[indexSettlementId], reportId);
|
||||
SetSpapiReportId(rowArray[indexSettlementId], spapiReportId);
|
||||
_log.LogInformation("Settlement report already imported, skipping...");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//set currencyId
|
||||
//currencyId = GeneralQueries.GetCurrencyId(items[5]);
|
||||
|
||||
//set currency
|
||||
currency = items[indexCurrency];
|
||||
settlementAmount = decimal.Parse(items[indexTotalAmount].Replace(",", "."));
|
||||
|
||||
// insert
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
@@ -543,61 +539,38 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||
,@depositDate
|
||||
,@settlementotalAmounttId
|
||||
,@currency
|
||||
,@reportId
|
||||
,@spapiReportId
|
||||
);";
|
||||
|
||||
// add parameters
|
||||
if (indexSettlementId == -1 || items[indexSettlementId].Length == 0) { cmd.Parameters.AddWithValue("@settlementId", DBNull.Value); }
|
||||
else
|
||||
{
|
||||
settlementRef = items[indexSettlementId];
|
||||
cmd.Parameters.AddWithValue("@settlementId", settlementRef);
|
||||
}
|
||||
|
||||
var parseDateTime = new Core.Logic.Utilities.DateTime();
|
||||
|
||||
if (indexSettlementStartDate == -1 || items[indexSettlementStartDate].Length == 0) { cmd.Parameters.AddWithValue("@settlementStartDate", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@settlementStartDate", parseDateTime.ParseIsoDateTimeString(items[indexSettlementStartDate])); }
|
||||
|
||||
if (indexSettlementEndDate == -1 || items[indexSettlementEndDate].Length == 0) { cmd.Parameters.AddWithValue("@settlementEndDate", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@settlementEndDate", parseDateTime.ParseIsoDateTimeString(items[indexSettlementEndDate])); }
|
||||
|
||||
if (indexDepositDate == -1 || items[indexDepositDate].Length == 0) { cmd.Parameters.AddWithValue("@depositDate", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@depositDate", parseDateTime.ParseIsoDateTimeString(items[indexDepositDate])); }
|
||||
|
||||
if (indexTotalAmount == -1 || items[indexTotalAmount].Length == 0) { cmd.Parameters.AddWithValue("@totalAmount", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@settlementotalAmounttId", settlementAmount); }
|
||||
|
||||
if (string.IsNullOrWhiteSpace(reportId)) { cmd.Parameters.AddWithValue("@reportId", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@reportId", reportId); }
|
||||
|
||||
// add parameters
|
||||
cmd.Parameters.AddWithValue("@settlementId", rowArray[indexSettlementId]);
|
||||
cmd.Parameters.AddWithValue("@settlementStartDate", parseDateTime.ParseIsoDateTimeString(rowArray[indexSettlementStartDate]));
|
||||
cmd.Parameters.AddWithValue("@settlementEndDate", parseDateTime.ParseIsoDateTimeString(rowArray[indexSettlementEndDate]));
|
||||
cmd.Parameters.AddWithValue("@depositDate", parseDateTime.ParseIsoDateTimeString(rowArray[indexDepositDate]));
|
||||
cmd.Parameters.AddWithValue("@settlementotalAmounttId", settlementAmount);
|
||||
if (string.IsNullOrWhiteSpace(spapiReportId)) { cmd.Parameters.AddWithValue("@spapiReportId", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@spapiReportId", spapiReportId); }
|
||||
cmd.Parameters.AddWithValue("@currency", currency);
|
||||
|
||||
//if (currencyId == -1) { sqlCommand.Parameters.AddWithValue("@currencyId", DBNull.Value); }
|
||||
//else { sqlCommand.Parameters.AddWithValue("@currencyId", currencyId); }
|
||||
|
||||
//execute and retrive id
|
||||
settlementReportId = (int)cmd.ExecuteScalar();
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//update market place name in main table, if required
|
||||
if (marketPlaceUpdated == false && settlementReportId > 0 && items[indexMarketplaceName].Length > 1)
|
||||
// attempt to retrieve marketplace name for header table
|
||||
if (rowArray[indexMarketplaceName].Length > 1 && settlementReportId > 0)
|
||||
{
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
if (marketplaceName == null)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
UPDATE tblImportAmazonSettlementReport
|
||||
SET [marketplace-name]=@MarketplaceName
|
||||
WHERE ImportAmazonSettlementReportID=@ImportAmazonSettlementReportID;";
|
||||
cmd.Parameters.AddWithValue("@MarketplaceName", items[indexMarketplaceName]);
|
||||
cmd.Parameters.AddWithValue("@ImportAmazonSettlementReportID", settlementReportId);
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
marketPlaceUpdated = true;
|
||||
marketplaceName = rowArray[indexMarketplaceName];
|
||||
}
|
||||
else if (marketplaceName != rowArray[indexMarketplaceName])
|
||||
{
|
||||
_log.LogError("Marketplace name '" + rowArray[indexMarketplaceName] + "' on line " + lineNumber +
|
||||
" is different from marketplace name '" + marketplaceName + "' on previous line. This shouldn't be possible!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,67 +593,95 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||
|
||||
cmd.Parameters.AddWithValue("@currency", currency);
|
||||
|
||||
if (indexTransactionType == -1 || items[indexTransactionType].Length == 0) { cmd.Parameters.AddWithValue("@TransactionType", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@TransactionType", items[indexTransactionType]); }
|
||||
if (indexTransactionType == -1 || rowArray[indexTransactionType].Length == 0) { cmd.Parameters.AddWithValue("@TransactionType", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@TransactionType", rowArray[indexTransactionType]); }
|
||||
|
||||
if (indexOrderId == -1 || items[indexOrderId].Length == 0) { cmd.Parameters.AddWithValue("@orderRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@orderRef", items[indexOrderId]); }
|
||||
if (indexOrderId == -1 || rowArray[indexOrderId].Length == 0) { cmd.Parameters.AddWithValue("@orderRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@orderRef", rowArray[indexOrderId]); }
|
||||
|
||||
if (indexMerchantOrderId == -1 || items[indexMerchantOrderId].Length == 0) { cmd.Parameters.AddWithValue("@merchantOrderRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@merchantOrderRef", items[indexMerchantOrderId]); }
|
||||
if (indexMerchantOrderId == -1 || rowArray[indexMerchantOrderId].Length == 0) { cmd.Parameters.AddWithValue("@merchantOrderRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@merchantOrderRef", rowArray[indexMerchantOrderId]); }
|
||||
|
||||
if (indexAdjustmentId == -1 || items[indexAdjustmentId].Length == 0) { cmd.Parameters.AddWithValue("@AdjustmentRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@AdjustmentRef", items[indexAdjustmentId]); }
|
||||
if (indexAdjustmentId == -1 || rowArray[indexAdjustmentId].Length == 0) { cmd.Parameters.AddWithValue("@AdjustmentRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@AdjustmentRef", rowArray[indexAdjustmentId]); }
|
||||
|
||||
if (indexShipmentId == -1 || items[indexShipmentId].Length == 0) { cmd.Parameters.AddWithValue("@ShipmentRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@ShipmentRef", items[indexShipmentId]); }
|
||||
if (indexShipmentId == -1 || rowArray[indexShipmentId].Length == 0) { cmd.Parameters.AddWithValue("@ShipmentRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@ShipmentRef", rowArray[indexShipmentId]); }
|
||||
|
||||
if (indexMarketplaceName == -1 || items[indexMarketplaceName].Length == 0) { cmd.Parameters.AddWithValue("@MarketplaceName", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@MarketplaceName", items[indexMarketplaceName]); }
|
||||
if (indexMarketplaceName == -1 || rowArray[indexMarketplaceName].Length == 0) { cmd.Parameters.AddWithValue("@MarketplaceName", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@MarketplaceName", rowArray[indexMarketplaceName]); }
|
||||
|
||||
if (indexAmountType == -1 || items[indexAmountType].Length == 0) { cmd.Parameters.AddWithValue("@AmountType", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@AmountType", items[indexAmountType]); }
|
||||
if (indexAmountType == -1 || rowArray[indexAmountType].Length == 0) { cmd.Parameters.AddWithValue("@AmountType", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@AmountType", rowArray[indexAmountType]); }
|
||||
|
||||
if (indexAmountDescription == -1 || items[indexAmountDescription].Length == 0) { cmd.Parameters.AddWithValue("@AmountDescription", DBNull.Value); }
|
||||
if (indexAmountDescription == -1 || rowArray[indexAmountDescription].Length == 0) { cmd.Parameters.AddWithValue("@AmountDescription", DBNull.Value); }
|
||||
else
|
||||
{
|
||||
string amountDescription = items[indexAmountDescription];
|
||||
string amountDescription = rowArray[indexAmountDescription];
|
||||
if (amountDescription.Length > 100) { amountDescription = amountDescription.Substring(0, 100); }
|
||||
cmd.Parameters.AddWithValue("@AmountDescription", amountDescription);
|
||||
}
|
||||
|
||||
if (indexAmount == -1 || items[indexAmount].Length == 0) { cmd.Parameters.AddWithValue("@Amount", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@Amount", decimal.Parse(items[indexAmount].Replace(",", "."))); }
|
||||
if (indexAmount == -1 || rowArray[indexAmount].Length == 0) { cmd.Parameters.AddWithValue("@Amount", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@Amount", decimal.Parse(rowArray[indexAmount].Replace(",", "."))); }
|
||||
|
||||
if (indexFulfillmentId == -1 || items[indexFulfillmentId].Length == 0) { cmd.Parameters.AddWithValue("@FulfillmentRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@FulfillmentRef", items[indexFulfillmentId]); }
|
||||
if (indexFulfillmentId == -1 || rowArray[indexFulfillmentId].Length == 0) { cmd.Parameters.AddWithValue("@FulfillmentRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@FulfillmentRef", rowArray[indexFulfillmentId]); }
|
||||
|
||||
if (indexPostedDateTime == -1 || items[indexPostedDateTime].Length == 0) { cmd.Parameters.AddWithValue("@PostedDateTimeUTC", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@PostedDateTimeUTC", new Logic.Utilities.DateTime().ParseIsoDateTimeString(items[indexPostedDateTime])); }
|
||||
if (indexPostedDateTime == -1 || rowArray[indexPostedDateTime].Length == 0) { cmd.Parameters.AddWithValue("@PostedDateTimeUTC", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@PostedDateTimeUTC", new Logic.Utilities.DateTime().ParseIsoDateTimeString(rowArray[indexPostedDateTime])); }
|
||||
|
||||
if (indexOrderItemCode == -1 || items[indexOrderItemCode].Length == 0) { cmd.Parameters.AddWithValue("@OrderItemCode", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@OrderItemCode", long.Parse(items[indexOrderItemCode])); }
|
||||
if (indexOrderItemCode == -1 || rowArray[indexOrderItemCode].Length == 0) { cmd.Parameters.AddWithValue("@OrderItemCode", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@OrderItemCode", long.Parse(rowArray[indexOrderItemCode])); }
|
||||
|
||||
if (indexMerchantOrderItemId == -1 || items[indexMerchantOrderItemId].Length == 0) { cmd.Parameters.AddWithValue("@MerchantOrderItemRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@MerchantOrderItemRef", long.Parse(items[indexMerchantOrderItemId])); }
|
||||
if (indexMerchantOrderItemId == -1 || rowArray[indexMerchantOrderItemId].Length == 0) { cmd.Parameters.AddWithValue("@MerchantOrderItemRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@MerchantOrderItemRef", long.Parse(rowArray[indexMerchantOrderItemId])); }
|
||||
|
||||
if (indexMerchantAdjustmentItemId == -1 || items[indexMerchantAdjustmentItemId].Length == 0) { cmd.Parameters.AddWithValue("@MerchantAdjustmentItemRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@MerchantAdjustmentItemRef", items[indexMerchantAdjustmentItemId]); }
|
||||
if (indexMerchantAdjustmentItemId == -1 || rowArray[indexMerchantAdjustmentItemId].Length == 0) { cmd.Parameters.AddWithValue("@MerchantAdjustmentItemRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@MerchantAdjustmentItemRef", rowArray[indexMerchantAdjustmentItemId]); }
|
||||
|
||||
if (indexSku == -1 || items[indexSku].Length == 0) { cmd.Parameters.AddWithValue("@SkuNumber", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@SkuNumber", items[indexSku]); }
|
||||
if (indexSku == -1 || rowArray[indexSku].Length == 0) { cmd.Parameters.AddWithValue("@SkuNumber", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@SkuNumber", rowArray[indexSku]); }
|
||||
|
||||
if (indexQuantityPurchased == -1 || items[indexQuantityPurchased].Length == 0) { cmd.Parameters.AddWithValue("@QuantityPurchased", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@QuantityPurchased", int.Parse(items[indexQuantityPurchased])); }
|
||||
if (indexQuantityPurchased == -1 || rowArray[indexQuantityPurchased].Length == 0) { cmd.Parameters.AddWithValue("@QuantityPurchased", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@QuantityPurchased", int.Parse(rowArray[indexQuantityPurchased])); }
|
||||
|
||||
if (indexPromotionId == -1 || items[indexPromotionId].Length == 0) { cmd.Parameters.AddWithValue("@PromotionRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@PromotionRef", items[indexPromotionId]); }
|
||||
if (indexPromotionId == -1 || rowArray[indexPromotionId].Length == 0) { cmd.Parameters.AddWithValue("@PromotionRef", DBNull.Value); }
|
||||
else { cmd.Parameters.AddWithValue("@PromotionRef", rowArray[indexPromotionId]); }
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
lineNumber = lineNumber + 1;
|
||||
}
|
||||
// end of filestream reading
|
||||
|
||||
// if we haven't gotten the marketplace name from the line items, attempt to infer from currency
|
||||
if (marketplaceName == null && settlementReportId > 0)
|
||||
{
|
||||
if (currency == "GBP")
|
||||
{
|
||||
marketplaceName = MarketPlaceEnum.AmazonUK.GetMarketplaceUrl();
|
||||
marketplaceName = char.ToUpper(marketplaceName[0]) + marketplaceName.Substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
// finally, if we have it, add marketplace name to main table
|
||||
if (marketplaceName != null && settlementReportId > 0)
|
||||
{
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
UPDATE tblImportAmazonSettlementReport
|
||||
SET [marketplace-name]=@MarketplaceName
|
||||
WHERE ImportAmazonSettlementReportID=@ImportAmazonSettlementReportID;";
|
||||
cmd.Parameters.AddWithValue("@MarketplaceName", marketplaceName);
|
||||
cmd.Parameters.AddWithValue("@ImportAmazonSettlementReportID", settlementReportId);
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//final check - settlement amount matches sum of inserted settlement lines
|
||||
|
||||
@@ -340,19 +340,19 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||
WHERE 1 = 1 ";
|
||||
|
||||
// build the where statments
|
||||
if (invoiceIdList != null || invoiceIdList.Any())
|
||||
if (invoiceIdList != null && invoiceIdList.Any())
|
||||
{
|
||||
sqlBuilder.In("PurchaseID", invoiceLineIdList, "AND");
|
||||
}
|
||||
if (invoiceLineIdList != null || invoiceLineIdList.Any())
|
||||
if (invoiceLineIdList != null && invoiceLineIdList.Any())
|
||||
{
|
||||
sqlBuilder.In("PurchaseLineID", invoiceLineIdList, "AND");
|
||||
}
|
||||
if (statusList != null || statusList.Any())
|
||||
if (statusList != null && statusList.Any())
|
||||
{
|
||||
sqlBuilder.In("PurchaseLineStatus", invoiceLineIdList, "AND");
|
||||
}
|
||||
if (itemDescriptionList != null || itemDescriptionList.Any())
|
||||
if (itemDescriptionList != null && itemDescriptionList.Any())
|
||||
{
|
||||
sqlBuilder.LikeAnd("ItemDescription", itemDescriptionList, "AND");
|
||||
}
|
||||
|
||||
@@ -1,372 +0,0 @@
|
||||
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 JournalRepository : _Base, IJournalRepository
|
||||
{
|
||||
public JournalRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
|
||||
{
|
||||
}
|
||||
|
||||
public Dictionary<int, Core.Model.Account.Journal> ReadJournal(List<int> journalIdList)
|
||||
{
|
||||
var sqlBuilder = new SqlWhereBuilder();
|
||||
|
||||
//build sql query
|
||||
string sql = @"
|
||||
SELECT tblAccountJournal.AccountJournalID
|
||||
,tblAccountJournal.AccountJournalTypeID
|
||||
,tblAccountJournal.EntryDate
|
||||
,tblAccountJournal.PostDate
|
||||
,tblAccountJournal.LastModified
|
||||
,tblAccountJournal.IsLocked
|
||||
,tblAccountJournalPost.AccountJournalPostID
|
||||
,tblAccountJournalPost.AccountChartOfID
|
||||
,tblAccountJournalPost.AmountGbp
|
||||
FROM tblAccountJournal
|
||||
INNER JOIN tblAccountJournalPost ON tblAccountJournal.AccountJournalID = tblAccountJournalPost.AccountJournalID
|
||||
WHERE 1 = 1 ";
|
||||
|
||||
// build the where statments
|
||||
if (journalIdList.Any())
|
||||
{
|
||||
sqlBuilder.In("tblAccountJournal.AccountJournalID", journalIdList, "AND");
|
||||
}
|
||||
|
||||
// append where string to the sql
|
||||
if (sqlBuilder.IsSetSqlWhereString)
|
||||
{
|
||||
sql = sql + sqlBuilder.SqlWhereString;
|
||||
}
|
||||
|
||||
// build tuple list
|
||||
var dbJournalList = new List<(
|
||||
int AccountJournalId
|
||||
, int AccountJournalTypeId
|
||||
, DateTime EntryDate
|
||||
, DateTime PostDate
|
||||
, DateTime LastModified
|
||||
, bool IsLocked
|
||||
)>();
|
||||
|
||||
var dbJournalPostList = new List<(
|
||||
int AccountJournalId
|
||||
, int AccountJournalPostId
|
||||
, int AccountChartOfId
|
||||
, decimal AmountGbp
|
||||
)>();
|
||||
|
||||
|
||||
bool hasRows = false;
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = sql;
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
|
||||
if (sqlBuilder.ParameterListIsSet)
|
||||
{
|
||||
sqlBuilder.AddParametersToSqlCommand(cmd);
|
||||
}
|
||||
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
if (reader.HasRows)
|
||||
{
|
||||
hasRows = true;
|
||||
int lastJournalId = 0;
|
||||
while (reader.Read())
|
||||
{
|
||||
// read journal header
|
||||
int journalId = reader.GetInt32(0);
|
||||
if (journalId != lastJournalId)
|
||||
{
|
||||
lastJournalId = journalId;
|
||||
|
||||
(int AccountJournalId
|
||||
, int AccountJournalTypeId
|
||||
, DateTime EntryDate
|
||||
, DateTime PostDate
|
||||
, DateTime LastModified
|
||||
, bool IsLocked
|
||||
)
|
||||
journal =
|
||||
(journalId
|
||||
, reader.GetInt32(1)
|
||||
, DateTime.SpecifyKind(reader.GetDateTime(2), DateTimeKind.Utc)
|
||||
, DateTime.SpecifyKind(reader.GetDateTime(3), DateTimeKind.Utc)
|
||||
, DateTime.SpecifyKind(reader.GetDateTime(4), DateTimeKind.Utc)
|
||||
, reader.GetBoolean(5)
|
||||
);
|
||||
|
||||
dbJournalList.Add(journal);
|
||||
}
|
||||
|
||||
// read journal posts
|
||||
(int AccountJournalId
|
||||
, int AccountJournalPostId
|
||||
, int AccountChartOfId
|
||||
, decimal AmountGbp
|
||||
)
|
||||
journalPost =
|
||||
(journalId
|
||||
, reader.GetInt32(6)
|
||||
, reader.GetInt32(7)
|
||||
, reader.GetDecimal(8)
|
||||
);
|
||||
|
||||
dbJournalPostList.Add(journalPost);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var returnList = new Dictionary<int, Core.Model.Account.Journal>();
|
||||
if (hasRows)
|
||||
{
|
||||
// build lists to filter db results by
|
||||
var journalTypeIdList = new List<int>();
|
||||
var accountIdList = new List<int>();
|
||||
foreach (var item in dbJournalList)
|
||||
{
|
||||
journalTypeIdList.Add(item.AccountJournalTypeId);
|
||||
}
|
||||
foreach (var item in dbJournalPostList)
|
||||
{
|
||||
accountIdList.Add(item.AccountChartOfId);
|
||||
}
|
||||
|
||||
// get journalTypes from db
|
||||
var journalTypeDict = new JournalRepository(_connection, _transaction).ReadJournalType(journalTypeIdList);
|
||||
|
||||
// get accounts from db
|
||||
var accountDict = new AccountCodeRepository(_connection, _transaction).ReadAccountCode(accountIdList);
|
||||
|
||||
// build final return dictionary
|
||||
foreach (var dbJournal in dbJournalList)
|
||||
{
|
||||
// build posts
|
||||
var newPosts = new List<Core.Model.Account.Journal.Post>();
|
||||
foreach (var dbJournalPost in dbJournalPostList)
|
||||
{
|
||||
if (dbJournalPost.AccountJournalId == dbJournal.AccountJournalId)
|
||||
{
|
||||
var newPost = new Core.Model.Account.Journal.Post(
|
||||
dbJournalPost.AccountJournalPostId
|
||||
, accountDict[dbJournalPost.AccountChartOfId]
|
||||
, dbJournalPost.AmountGbp);
|
||||
|
||||
newPosts.Add(newPost);
|
||||
}
|
||||
}
|
||||
|
||||
// create the journal
|
||||
var newJournal = new Core.Model.Account.Journal(
|
||||
dbJournal.AccountJournalId
|
||||
, journalTypeDict[dbJournal.AccountJournalTypeId]
|
||||
, newPosts
|
||||
, dbJournal.EntryDate
|
||||
, dbJournal.PostDate
|
||||
, dbJournal.LastModified
|
||||
, dbJournal.IsLocked);
|
||||
|
||||
returnList.Add(dbJournal.AccountJournalId, newJournal);
|
||||
}
|
||||
}
|
||||
// all done, return the list herevar
|
||||
return returnList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test for locked journal entry
|
||||
/// </summary>
|
||||
/// <returns>False on locked journal entry</returns>
|
||||
public bool ReadJournalIsLocked(int journalId)
|
||||
{
|
||||
string sql = @"
|
||||
SELECT
|
||||
tblAccountJournal.IsLocked
|
||||
FROM
|
||||
tblAccountJournal
|
||||
WHERE
|
||||
tblAccountJournal.AccountJournalID=@accountJournalId;";
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = sql;
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
|
||||
cmd.Parameters.AddWithValue("@accountJournalId", journalId);
|
||||
|
||||
object obj = cmd.ExecuteScalar();
|
||||
if (obj == null)
|
||||
{
|
||||
throw new Exception("Journal entry not found for AccountJournalID=" + journalId);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (bool)obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Dictionary<int, Model.Account.JournalType> ReadJournalType(List<int> journalTypeIds = null, List<string> typeTitles = null)
|
||||
{
|
||||
var sqlBuilder = new SqlWhereBuilder();
|
||||
|
||||
// create the return (emptyP list) here
|
||||
var returnList = new Dictionary<int, Model.Account.JournalType>();
|
||||
sqlBuilder.Init();
|
||||
|
||||
//build sql query
|
||||
string sql = @"
|
||||
SELECT [AccountJournalTypeID]
|
||||
,[TypeTitle]
|
||||
,[ChartOfAccountID_Debit]
|
||||
,[ChartOfAccountID_Credit]
|
||||
FROM [e2A].[dbo].[tblAccountJournalType]
|
||||
WHERE 1 = 1 ";
|
||||
|
||||
// build the where statments
|
||||
if (journalTypeIds.Any())
|
||||
{
|
||||
sqlBuilder.In("AccountJournalTypeID", journalTypeIds, "AND");
|
||||
}
|
||||
if (typeTitles.Any())
|
||||
{
|
||||
sqlBuilder.In("TypeTitle", typeTitles, "AND");
|
||||
}
|
||||
|
||||
// append where string to the sql
|
||||
if (sqlBuilder.IsSetSqlWhereString)
|
||||
{
|
||||
sql = sql + sqlBuilder.SqlWhereString;
|
||||
}
|
||||
|
||||
// create dictionary to add credit/debit accounts on after db read
|
||||
var creditDict = new Dictionary<int, int>();
|
||||
var debitDict = new Dictionary<int, int>();
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = sql;
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
|
||||
if (sqlBuilder.ParameterListIsSet)
|
||||
{
|
||||
sqlBuilder.AddParametersToSqlCommand(cmd);
|
||||
}
|
||||
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
if (reader.HasRows)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
// read from db and create object
|
||||
int journalTypeId = reader.GetInt32(0);
|
||||
string title = reader.GetString(1);
|
||||
int? debitAccountId = null;
|
||||
if (!reader.IsDBNull(2)) { debitAccountId = reader.GetInt32(2); }
|
||||
int? creditAccountId = null;
|
||||
if (!reader.IsDBNull(3)) { creditAccountId = reader.GetInt32(3); }
|
||||
|
||||
// build return list
|
||||
var item = new Model.Account.JournalType(journalTypeId, title);
|
||||
returnList.Add(journalTypeId, item);
|
||||
|
||||
// build dictionaries
|
||||
if (debitAccountId != null)
|
||||
{
|
||||
debitDict.Add(journalTypeId, debitAccountId.Value);
|
||||
}
|
||||
if (creditAccountId != null)
|
||||
{
|
||||
creditDict.Add(journalTypeId, creditAccountId.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// get account objects from db
|
||||
var accountIdList = debitDict.Values.ToList();
|
||||
accountIdList.AddRange(creditDict.Values.ToList());
|
||||
var dbDict = new AccountCodeRepository(_connection, _transaction).ReadAccountCode(accountIdList);
|
||||
|
||||
// add to the returnlist
|
||||
foreach (var account in returnList.Values)
|
||||
{
|
||||
Model.Account.Account debitAccount = null;
|
||||
if (debitDict.ContainsKey(account.JournalTypeId))
|
||||
{
|
||||
debitAccount = dbDict[debitDict[account.JournalTypeId]];
|
||||
}
|
||||
|
||||
Model.Account.Account creditAccount = null;
|
||||
if (creditDict.ContainsKey(account.JournalTypeId))
|
||||
{
|
||||
creditAccount = dbDict[creditDict[account.JournalTypeId]]; // key of 59 needed
|
||||
}
|
||||
|
||||
account.AddDefaultAccounts(creditAccount, debitAccount);
|
||||
}
|
||||
|
||||
// all done, return the list here
|
||||
return returnList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Old code needs sorting
|
||||
/// </summary>
|
||||
public bool DeleteJournal(int accountJournalId)
|
||||
{
|
||||
bool IsLocked = ReadJournalIsLocked(accountJournalId);
|
||||
if (IsLocked == true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// make the delete
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = @"
|
||||
DELETE FROM tblAccountJournalPost
|
||||
WHERE AccountJournalID=@accountJournalId;";
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
|
||||
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
|
||||
|
||||
int rows = cmd.ExecuteNonQuery();
|
||||
|
||||
if (rows == 0)
|
||||
{
|
||||
throw new Exception("Journal entry and/or entry posts do not exist for AccountJournalId=" + accountJournalId);
|
||||
}
|
||||
}
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = @"
|
||||
DELETE FROM tblAccountJournal
|
||||
WHERE AccountJournalID=@accountJournalId;";
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
|
||||
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
using bnhtrade.Core.Data.Database.Repository.Interface;
|
||||
using bnhtrade.Core.Model.Account;
|
||||
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 int DeletePurchaseLineTransaction(int accountJournalId)
|
||||
{
|
||||
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);
|
||||
|
||||
return cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
public void InsertPurchaseLineTransaction(int accountJournalId, int purchaseLineId)
|
||||
{
|
||||
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", accountJournalId);
|
||||
|
||||
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)=@accountJournalId));
|
||||
";
|
||||
cmd.Parameters.AddWithValue("@accountJournalId", 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,552 @@
|
||||
using bnhtrade.Core.Data.Database._BoilerPlate;
|
||||
using bnhtrade.Core.Data.Database.Repository.Interface;
|
||||
using bnhtrade.Core.Model.Account;
|
||||
using bnhtrade.Core.Model.Stock;
|
||||
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;
|
||||
using static bnhtrade.Core.Data.Database.Constants;
|
||||
using static bnhtrade.Core.Model.Account.Journal;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||
{
|
||||
internal class StockJournalRepository : _Base, IStockJournalRepository
|
||||
{
|
||||
public StockJournalRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
|
||||
{
|
||||
}
|
||||
|
||||
private List<string> ConvertStockNumbers(List<int> stockNumbers)
|
||||
{
|
||||
if (stockNumbers == null || stockNumbers.Count == 0)
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
return stockNumbers.Select(sn => "STK#" + sn.ToString("D6")).ToList();
|
||||
}
|
||||
|
||||
private List<int> ConvertStockNumbers(List<string> stockNumbers)
|
||||
{
|
||||
if (stockNumbers == null || stockNumbers.Count == 0)
|
||||
{
|
||||
return new List<int>();
|
||||
}
|
||||
return stockNumbers.Select(sn => int.Parse(sn.Substring(4))).ToList();
|
||||
}
|
||||
|
||||
//
|
||||
// Create
|
||||
//
|
||||
|
||||
public int InsertStockJournalHeader(int stockId, int journalTypeId, DateTime entryDate, bool isLocked)
|
||||
{
|
||||
if (entryDate.Kind != DateTimeKind.Utc)
|
||||
{
|
||||
throw new ArgumentException("Entry date must be in UTC format.", nameof(entryDate));
|
||||
}
|
||||
|
||||
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", isLocked);
|
||||
|
||||
//execute
|
||||
return (int)cmd.ExecuteScalar();
|
||||
}
|
||||
}
|
||||
|
||||
public int InsertStockJournalPost(int stockJournalId, int stockStatusId, int quantity)
|
||||
{
|
||||
if (quantity == 0)
|
||||
{
|
||||
throw new ArgumentException("Quantity must be non-zero.", nameof(quantity));
|
||||
}
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
INSERT INTO tblStockJournalPost ( StockJournalID, StockStatusID, Quantity )
|
||||
OUTPUT INSERTED.StockJournalPostID
|
||||
VALUES ( @StockJournalId, @stockStatudId, @quantity );";
|
||||
|
||||
cmd.Parameters.AddWithValue("@StockJournalId", stockJournalId);
|
||||
cmd.Parameters.AddWithValue("@stockStatudId", stockStatusId);
|
||||
cmd.Parameters.AddWithValue("@quantity", quantity);
|
||||
|
||||
// execute
|
||||
return cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Read
|
||||
//
|
||||
|
||||
public Dictionary<int, Model.Stock.StockJournalBuilder> ReadStockJournal(bool lockRecords = false,
|
||||
List<int> stockJournalIds = null, List<int> stockIds = null, List<string> stockNumbers = null
|
||||
, DateTime? minEntryDate = null, DateTime? maxEntryDate = null, List<int> stockStatusIds = null)
|
||||
{
|
||||
var returnDict = new Dictionary<int, Model.Stock.StockJournalBuilder>();
|
||||
var sqlWhere = new SqlWhereBuilder();
|
||||
|
||||
string lockClause = "";
|
||||
if (lockRecords)
|
||||
{
|
||||
lockClause = "WITH (UPDLOCK, HOLDLOCK)";
|
||||
}
|
||||
|
||||
string sql = $@"
|
||||
SELECT tblStockJournal.StockJournalID,
|
||||
tblStockJournal.StockJournalTypeID,
|
||||
tblStockJournal.StockID,
|
||||
tblStock.StockNumber
|
||||
tblStockJournal.EntryDate,
|
||||
tblStockJournal.PostDate,
|
||||
tblStockJournal.LastModified,
|
||||
tblStockJournal.IsLocked,
|
||||
tblStockJournal.AccountIsProcessed,
|
||||
tblStockJournalPost.StockJournalPostID,
|
||||
tblStockJournalPost.StockStatusID,
|
||||
tblStockJournalPost.Quantity,
|
||||
FROM tblStockJournal {lockClause}
|
||||
LEFT OUTER JOIN tblStock {lockClause} ON tblStockJournal.StockID = tblStock.StockID
|
||||
LEFT OUTER JOIN tblStockJournalPost {lockClause} ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
|
||||
WHERE 1=1 ";
|
||||
|
||||
// build where clause based on provided filters
|
||||
bool noFilter = true;
|
||||
if (stockJournalIds != null && stockJournalIds.Any())
|
||||
{
|
||||
sql += sqlWhere.InClause("tblStockJournal.StockJournalID", stockJournalIds, "AND");
|
||||
noFilter = false;
|
||||
}
|
||||
if (stockIds != null && stockIds.Any())
|
||||
{
|
||||
sql += sqlWhere.InClause("tblStockJournal.StockID", stockIds, "AND");
|
||||
noFilter = false;
|
||||
}
|
||||
if (stockNumbers != null && stockNumbers.Any())
|
||||
{
|
||||
List<int> stockNumbersInt = ConvertStockNumbers(stockNumbers);
|
||||
sql += sqlWhere.InClause("tblStock.StockNumber", stockNumbersInt, "AND");
|
||||
noFilter = false;
|
||||
}
|
||||
if (minEntryDate.HasValue)
|
||||
{
|
||||
sql += sqlWhere.IsEqualToOrGreaterThanClause("tblStockJournal.EntryDate", minEntryDate.Value.ToUniversalTime(), "AND");
|
||||
noFilter = false;
|
||||
}
|
||||
if (maxEntryDate.HasValue)
|
||||
{
|
||||
sql += sqlWhere.IsEqualToOrLessThanClause("tblStockJournal.EntryDate", maxEntryDate.Value.ToUniversalTime(), "AND");
|
||||
noFilter = false;
|
||||
}
|
||||
if (stockStatusIds != null && stockStatusIds.Any())
|
||||
{
|
||||
sql += sqlWhere.InClause(
|
||||
"StockStatusID"
|
||||
, stockStatusIds
|
||||
, " AND tblStockJournal.StockJournalID IN (SELECT StockJournalID FROM tblStockJournalPost WHERE "
|
||||
, " ) "
|
||||
);
|
||||
noFilter = false;
|
||||
}
|
||||
if (noFilter)
|
||||
{
|
||||
throw new ArgumentException("At least one filter must be provided for stock journal retrieval.");
|
||||
}
|
||||
|
||||
sql += " ORDER BY tblStockJournal.EntryDate, tblStockJournal.StockJournalID, tblStockJournalPost.StockJournalPostID;";
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = sql;
|
||||
|
||||
if (sqlWhere.ParameterListIsSet)
|
||||
{
|
||||
sqlWhere.AddParametersToSqlCommand(cmd);
|
||||
}
|
||||
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
int stockJournalId = reader.GetInt32(0);
|
||||
|
||||
// add header information, if not already in dictionary
|
||||
if (returnDict.ContainsKey(stockJournalId) == false)
|
||||
{
|
||||
// create new StockJournalBuilder
|
||||
var stockJournalBuilder = new Model.Stock.StockJournalBuilder
|
||||
{
|
||||
StockJournalId = stockJournalId,
|
||||
StockJournalTypeId = reader.GetInt32(1),
|
||||
StockId = reader.GetInt32(2),
|
||||
StockNumber = "STK#" + reader.GetInt32(3).ToString("D6"),
|
||||
EntryDate = DateTime.SpecifyKind(reader.GetDateTime(4), DateTimeKind.Utc),
|
||||
PostDate = DateTime.SpecifyKind(reader.GetDateTime(5), DateTimeKind.Utc),
|
||||
LastModified = DateTime.SpecifyKind(reader.GetDateTime(6), DateTimeKind.Utc),
|
||||
IsLocked = reader.GetBoolean(7),
|
||||
AccountIsProcessed = reader.GetBoolean(8),
|
||||
StockJournalBuilderPosts = new List<Model.Stock.StockJournalBuilder.StockJournalBuilderPost>()
|
||||
};
|
||||
returnDict.Add(stockJournalId, stockJournalBuilder);
|
||||
}
|
||||
|
||||
var stockJournalBuilderPost = new Model.Stock.StockJournalBuilder.StockJournalBuilderPost
|
||||
{
|
||||
StockJournalPostId = reader.GetInt32(9),
|
||||
StatusId = reader.GetInt32(10),
|
||||
Quantity = reader.GetInt32(11)
|
||||
};
|
||||
|
||||
returnDict[stockJournalId].StockJournalBuilderPosts.Add(stockJournalBuilderPost);
|
||||
}
|
||||
return returnDict;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<int, (int id, string title, int? stockStatusIdDebit, int? stockStatusIdCredit)> ReadStockJournalType(List<int> stockJournalTypeIdList)
|
||||
{
|
||||
var returnDict = new Dictionary<int, (int id, string title, int? stockStatusIdDebit, int? stockStatusIdCredit)>();
|
||||
var sqlWhere = new SqlWhereBuilder();
|
||||
|
||||
string sql = @"
|
||||
SELECT StockJournalTypeID, TypeTitle, StockStatusID_Debit, StockStatusID_Credit
|
||||
FROM tblStockJournalType
|
||||
WHERE 1=1 ";
|
||||
|
||||
if (stockJournalTypeIdList != null && stockJournalTypeIdList.Any())
|
||||
{
|
||||
sql += sqlWhere.InClause("StockJournalTypeID", stockJournalTypeIdList, "AND");
|
||||
}
|
||||
|
||||
sql += ";";
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = sql;
|
||||
|
||||
if (sqlWhere.ParameterListIsSet)
|
||||
{
|
||||
sqlWhere.AddParametersToSqlCommand(cmd);
|
||||
}
|
||||
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
int stockJournalTypeId = reader.GetInt32(0);
|
||||
returnDict.Add(stockJournalTypeId, (
|
||||
id: stockJournalTypeId,
|
||||
title: reader.GetString(1),
|
||||
stockStatusIdDebit: reader.IsDBNull(2) ? (int?)null : reader.GetInt32(2),
|
||||
stockStatusIdCredit: reader.IsDBNull(3) ? (int?)null : reader.GetInt32(3)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnDict;
|
||||
}
|
||||
|
||||
public (int, DateTime) ReadJournalStockIdAndEntryDate(int stockJournalId)
|
||||
{
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
SELECT tblStockJournal.EntryDate, StockID
|
||||
FROM tblStockJournal
|
||||
WHERE (((tblStockJournal.StockJournalID)=@stockJournalId));";
|
||||
|
||||
cmd.Parameters.AddWithValue("@stockJournalId", stockJournalId);
|
||||
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
if (reader.Read())
|
||||
{
|
||||
return (reader.GetInt32(1), DateTime.SpecifyKind(reader.GetDateTime(0), DateTimeKind.Utc));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("StockJournalID=" + stockJournalId + " does not exist!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int ReadJournalTypeIdByStockId(int stockId)
|
||||
{
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
SELECT tblStockJournal.StockJournalTypeID
|
||||
FROM tblStock INNER JOIN
|
||||
tblStockJournal ON tblStock.StockJournalID = tblStockJournal.StockJournalID
|
||||
WHERE (tblStock.StockID = @stockId);";
|
||||
|
||||
cmd.Parameters.AddWithValue("@stockId", stockId);
|
||||
|
||||
object obj = cmd.ExecuteScalar();
|
||||
|
||||
if (obj == null || obj == DBNull.Value)
|
||||
{
|
||||
throw new Exception("No stock journal type found for StockID=" + stockId);
|
||||
}
|
||||
|
||||
return (int)obj;
|
||||
}
|
||||
}
|
||||
|
||||
public int ReadStatusBalanceBySku(string sku, int statusId)
|
||||
{
|
||||
int statusBalance = new int();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public int ReadJournalEntryCountByStockId(int stockId)
|
||||
{
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
SELECT Count(tblStockJournal.StockJournalID) AS CountOfStockJournalID
|
||||
FROM tblStockJournal
|
||||
WHERE (((tblStockJournal.StockID)=@stockId));";
|
||||
|
||||
cmd.Parameters.AddWithValue("@stockId", stockId);
|
||||
|
||||
return (int)cmd.ExecuteScalar();
|
||||
}
|
||||
}
|
||||
|
||||
public int? ReadTypeIdStatusCreditId(int stockJournalTypeId)
|
||||
{
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
SELECT
|
||||
tblStockJournalType.StockStatusID_Credit
|
||||
FROM
|
||||
tblStockJournalType
|
||||
WHERE
|
||||
tblStockJournalType.StockJournalTypeID=@stockJournalTypeId
|
||||
AND tblStockJournalType.StockStatusID_Credit Is Not Null;";
|
||||
|
||||
cmd.Parameters.AddWithValue("@stockJournalTypeId", stockJournalTypeId);
|
||||
|
||||
object obj = cmd.ExecuteScalar();
|
||||
|
||||
if (obj == null || obj == DBNull.Value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)obj;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public DateTime? ReadMostRecentEntryDateForStatusDebit(int stockId, List<int> stockStatusIdList)
|
||||
{
|
||||
if (stockId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Stock ID must be greater than zero.", nameof(stockId));
|
||||
}
|
||||
if (stockStatusIdList == null || stockStatusIdList.Count == 0)
|
||||
{
|
||||
throw new ArgumentException("Stock status ID list cannot be null or empty.", nameof(stockStatusIdList));
|
||||
}
|
||||
|
||||
var sqlWhere = new SqlWhereBuilder();
|
||||
|
||||
// build sql string
|
||||
string stringSql = @"
|
||||
MAX (tblStockJournal.EntryDate) AS MostRecentEntryDate
|
||||
FROM
|
||||
tblStockJournal
|
||||
INNER JOIN tblStockJournalPost
|
||||
ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID
|
||||
WHERE
|
||||
tblStockJournal.StockID=@stockId
|
||||
AND tblStockJournalPost.Quantity>0 ";
|
||||
|
||||
stringSql += sqlWhere.InClause("tblStockJournalPost.StockStatusID", stockStatusIdList, "AND") + ";";
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = stringSql;
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
|
||||
cmd.Parameters.AddWithValue("@stockId", stockId);
|
||||
sqlWhere.AddParametersToSqlCommand(cmd);
|
||||
|
||||
object obj = cmd.ExecuteScalar();
|
||||
if (obj == null || obj == DBNull.Value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return DateTime.SpecifyKind((DateTime)obj, DateTimeKind.Utc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// update
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// Delete
|
||||
//
|
||||
|
||||
public void StockJournalDelete(int stockJournalId)
|
||||
{
|
||||
// delete posts
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
DELETE FROM tblStockJournalPost
|
||||
WHERE StockJournalID=@stockJournalId;";
|
||||
|
||||
cmd.Parameters.AddWithValue("@StockJournalId", stockJournalId);
|
||||
|
||||
// execute
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
// delete journal entry
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
DELETE FROM tblStockJournal
|
||||
WHERE StockJournalID=@stockJournalId;";
|
||||
|
||||
// add parameters
|
||||
cmd.Parameters.AddWithValue("@stockJournalId", stockJournalId);
|
||||
|
||||
int count = cmd.ExecuteNonQuery();
|
||||
|
||||
if (count != 1)
|
||||
{
|
||||
throw new Exception("Failed to delete stock journal header.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using bnhtrade.Core.Data.Database._BoilerPlate;
|
||||
using bnhtrade.Core.Data.Database.Repository.Interface;
|
||||
using bnhtrade.Core.Data.Database.Repository.Interface;
|
||||
using bnhtrade.Core.Data.Database.UnitOfWork;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -7,6 +7,8 @@ using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Transactions;
|
||||
using static System.Formats.Asn1.AsnWriter;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||
{
|
||||
@@ -16,126 +18,254 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||
{
|
||||
}
|
||||
|
||||
public List<Model.Stock.Status> ReadStatus(List<int> statusIds = null, List<int> statusTypeIds = null)
|
||||
{
|
||||
var sqlBuilder = new SqlWhereBuilder();
|
||||
var returnList = new List<Model.Stock.Status>();
|
||||
//
|
||||
// create
|
||||
//
|
||||
|
||||
public int InsertNewStock(int skuId, int accountJournalId)
|
||||
{
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
INSERT INTO tblStock
|
||||
(SkuID, AccountJournalID)
|
||||
OUTPUT INSERTED.StockID
|
||||
VALUES
|
||||
(@skuId, @accountJournalId);";
|
||||
|
||||
cmd.Parameters.AddWithValue("@skuId", skuId);
|
||||
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
|
||||
|
||||
return (int)cmd.ExecuteScalar();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// read
|
||||
//
|
||||
|
||||
public int CountStockTableRecords(List<int> accountJournalId = null)
|
||||
{
|
||||
throw new NotImplementedException("This needs testing before use");
|
||||
|
||||
var sqlWhere = new SqlWhereBuilder();
|
||||
|
||||
//build sql query
|
||||
string sql = @"
|
||||
SELECT [StockStatusID]
|
||||
,[StatusCode]
|
||||
,[StockStatus]
|
||||
,[StockStatusTypeID]
|
||||
,[Reference]
|
||||
,[ForeignKeyID]
|
||||
,[IsCreditOnly]
|
||||
,[IsClosed]
|
||||
,[RecordCreated]
|
||||
FROM [e2A].[dbo].[tblStockStatus]
|
||||
SELECT Count(tblStock.StockID) AS CountOfID
|
||||
FROM tblStock
|
||||
WHERE 1=1 ";
|
||||
|
||||
// build the where statments
|
||||
if (statusIds.Any())
|
||||
if (accountJournalId != null)
|
||||
{
|
||||
sqlBuilder.In("StockStatusID", statusIds, "AND");
|
||||
}
|
||||
if (statusTypeIds.Any())
|
||||
{
|
||||
sqlBuilder.In("StockStatusTypeID", statusTypeIds, "AND");
|
||||
sqlWhere.In("AccountJournalID", accountJournalId, "AND");
|
||||
}
|
||||
|
||||
// append where string to the sql
|
||||
if (sqlBuilder.IsSetSqlWhereString)
|
||||
if (sqlWhere.IsSetSqlWhereString)
|
||||
{
|
||||
sql = sql + sqlBuilder.SqlWhereString;
|
||||
sql += sqlWhere.SqlWhereString;
|
||||
}
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = sql;
|
||||
|
||||
if (sqlWhere.ParameterListIsSet)
|
||||
{
|
||||
sqlWhere.AddParametersToSqlCommand(cmd);
|
||||
}
|
||||
|
||||
return (int)cmd.ExecuteScalar();
|
||||
}
|
||||
}
|
||||
|
||||
public int? ReadStockIdByAccountJournalId(int accountJournalId)
|
||||
{
|
||||
if (accountJournalId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Account Journal ID must be greater than zero", nameof(accountJournalId));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
object obj = cmd.ExecuteScalar();
|
||||
|
||||
// unique index on tblStock.AccountJournalID ensures that this will return at most one row
|
||||
if (obj == null)
|
||||
{
|
||||
throw new Exception("AccountJournalID=" + accountJournalId + " does not exist.");
|
||||
}
|
||||
else if (obj == DBNull.Value)
|
||||
{
|
||||
return null; // no stock entry found
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int? ReadStockJournalId(int stockId)
|
||||
{
|
||||
if (stockId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId));
|
||||
}
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
SELECT StockJournalID
|
||||
FROM tblStock
|
||||
WHERE StockID=@stockId;;";
|
||||
|
||||
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)
|
||||
{
|
||||
return null; // no stock journal entry
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int? ReadAccountJournalId(int stockId)
|
||||
{
|
||||
if (stockId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId));
|
||||
}
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
SELECT AccountJournalID
|
||||
FROM tblStock
|
||||
WHERE StockID=@stockId;";
|
||||
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)
|
||||
{
|
||||
return null; // no account journal entry
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// update
|
||||
//
|
||||
|
||||
public int UpdateAccountJournalId(int stockId, int? accountJournalID)
|
||||
{
|
||||
if (stockId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId));
|
||||
}
|
||||
|
||||
string sql = @"
|
||||
UPDATE
|
||||
tblStock
|
||||
SET
|
||||
AccountJournalID = @accountJournalID
|
||||
WHERE
|
||||
StockID = @stockId;";
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = sql;
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
|
||||
if (sqlBuilder.ParameterListIsSet)
|
||||
cmd.Parameters.AddWithValue("@stockId", stockId);
|
||||
if (accountJournalID == null)
|
||||
{
|
||||
sqlBuilder.AddParametersToSqlCommand(cmd);
|
||||
cmd.Parameters.AddWithValue("@accountJournalID", DBNull.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@accountJournalID", accountJournalID);
|
||||
}
|
||||
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
var typeDict = new StockRepository(_connection, _transaction).ReadStatusType();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
int statusId = reader.GetInt32(0);
|
||||
int? statusCode = null;
|
||||
if (!reader.IsDBNull(1)) { statusCode = reader.GetInt32(1); }
|
||||
string stockStatus = reader.GetString(2);
|
||||
int typeId = reader.GetInt32(3);
|
||||
string reference = null;
|
||||
if (!reader.IsDBNull(4)) { reference = reader.GetString(4); }
|
||||
int? foreignKeyId = null;
|
||||
if (!reader.IsDBNull(5)) { foreignKeyId = reader.GetInt32(5); }
|
||||
bool isCreditOnly = reader.GetBoolean(6);
|
||||
bool isClosed = reader.GetBoolean(7);
|
||||
DateTime recordCreated = DateTime.SpecifyKind(reader.GetDateTime(8), DateTimeKind.Utc);
|
||||
|
||||
var newItem = new Model.Stock.Status(statusId
|
||||
, statusCode
|
||||
, stockStatus
|
||||
, typeDict[typeId]
|
||||
, reference
|
||||
, foreignKeyId
|
||||
, isCreditOnly
|
||||
, isClosed
|
||||
, recordCreated
|
||||
);
|
||||
|
||||
returnList.Add(newItem);
|
||||
}
|
||||
}
|
||||
return cmd.ExecuteNonQuery();
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
public Dictionary<int, Model.Stock.StatusType> ReadStatusType()
|
||||
public int UpdateStockJournalId(int stockId, int? stockJournalId)
|
||||
{
|
||||
var returnDict = new Dictionary<int, Model.Stock.StatusType>();
|
||||
if (stockId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId));
|
||||
}
|
||||
|
||||
// get all account info before we start
|
||||
var accountDict = new AccountCodeRepository(_connection, _transaction).ReadAccountCode();
|
||||
string sql = @"
|
||||
UPDATE
|
||||
tblStock
|
||||
SET
|
||||
StockJournalID = @stockJournalId
|
||||
WHERE
|
||||
StockID = @stockId;";
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = @"
|
||||
SELECT [StockStatusTypeID]
|
||||
,[StatusTypeName]
|
||||
,[ForeignKeyType]
|
||||
,[ReferenceType]
|
||||
,[AccountChartOfID]
|
||||
FROM [e2A].[dbo].[tblStockStatusType]";
|
||||
cmd.CommandText = sql;
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
cmd.Parameters.AddWithValue("@stockId", stockId);
|
||||
if (stockJournalId == null)
|
||||
{
|
||||
var accountIdDict = new Dictionary<int, int>();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
int statusTypeId = reader.GetInt32(0);
|
||||
string name = reader.GetString(1);
|
||||
string foreignKey = null;
|
||||
if (!reader.IsDBNull(2)) { foreignKey = reader.GetString(2); }
|
||||
string reference = null;
|
||||
if (!reader.IsDBNull(3)) { reference = reader.GetString(3); }
|
||||
uint accountId = (uint)reader.GetInt32(4);
|
||||
|
||||
var statusType = new Model.Stock.StatusType(statusTypeId, name, foreignKey, reference, accountDict[(int)accountId]);
|
||||
returnDict.Add(statusTypeId, statusType);
|
||||
}
|
||||
cmd.Parameters.AddWithValue("@stockJournalId", DBNull.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@stockJournalId", stockJournalId);
|
||||
}
|
||||
|
||||
return cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// delete
|
||||
//
|
||||
|
||||
public int DeleteStock(int stockId)
|
||||
{
|
||||
if (stockId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId));
|
||||
}
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = @"
|
||||
DELETE FROM tblStock
|
||||
WHERE StockID=@stockId;";
|
||||
cmd.Parameters.AddWithValue("@stockId", stockId);
|
||||
return cmd.ExecuteNonQuery();
|
||||
}
|
||||
return returnDict;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
using Amazon.Runtime.Internal.Transform;
|
||||
using bnhtrade.Core.Data.Database._BoilerPlate;
|
||||
using bnhtrade.Core.Data.Database.Repository.Interface;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||
{
|
||||
internal class StockStatusRepository : _Base, IStockStatusRepository
|
||||
{
|
||||
public StockStatusRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
|
||||
{
|
||||
}
|
||||
|
||||
public Dictionary<int, Model.Stock.StatusBuilder> ReadStatus(List<int> statusIds = null, List<int> statusTypeIds = null)
|
||||
{
|
||||
var sqlBuilder = new SqlWhereBuilder();
|
||||
var returnList = new Dictionary<int, Model.Stock.StatusBuilder>();
|
||||
|
||||
//build sql query
|
||||
string sql = @"
|
||||
SELECT [StockStatusID]
|
||||
,[StatusCode]
|
||||
,[StockStatus]
|
||||
,[StockStatusTypeID]
|
||||
,[Reference]
|
||||
,[ForeignKeyID]
|
||||
,[IsCreditOnly]
|
||||
,[IsClosed]
|
||||
,[RecordCreated]
|
||||
FROM [e2A].[dbo].[tblStockStatus]
|
||||
WHERE 1=1 ";
|
||||
|
||||
// build the where statments
|
||||
if (statusIds.Any())
|
||||
{
|
||||
sqlBuilder.In("StockStatusID", statusIds, "AND");
|
||||
}
|
||||
if (statusTypeIds.Any())
|
||||
{
|
||||
sqlBuilder.In("StockStatusTypeID", statusTypeIds, "AND");
|
||||
}
|
||||
|
||||
// append where string to the sql
|
||||
if (sqlBuilder.IsSetSqlWhereString)
|
||||
{
|
||||
sql = sql + sqlBuilder.SqlWhereString;
|
||||
}
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = sql;
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
|
||||
if (sqlBuilder.ParameterListIsSet)
|
||||
{
|
||||
sqlBuilder.AddParametersToSqlCommand(cmd);
|
||||
}
|
||||
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
var statusBuilder = new Model.Stock.StatusBuilder
|
||||
{
|
||||
StatusId = reader.GetInt32(0),
|
||||
StatusCode = reader.IsDBNull(1) ? (int?)null : reader.GetInt32(1),
|
||||
StatusTitle = reader.GetString(2),
|
||||
StatusTypeId = reader.GetInt32(3),
|
||||
Reference = reader.IsDBNull(4) ? null : reader.GetString(4),
|
||||
ForeignKeyID = reader.IsDBNull(5) ? (int?)null : reader.GetInt32(5),
|
||||
IsCreditOnly = reader.GetBoolean(6),
|
||||
IsClosed = reader.GetBoolean(7),
|
||||
RecordCreated = DateTime.SpecifyKind(reader.GetDateTime(8), DateTimeKind.Utc)
|
||||
};
|
||||
|
||||
returnList.Add(statusBuilder.StatusId, statusBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
public Dictionary<int, Model.Stock.StatusTypeBuilder> ReadStatusType(List<int> stockStatusTypeIds = null)
|
||||
{
|
||||
var returnDict = new Dictionary<int, Model.Stock.StatusTypeBuilder>();
|
||||
var sqlWhere = new SqlWhereBuilder();
|
||||
|
||||
string sql = @"
|
||||
SELECT [StockStatusTypeID]
|
||||
,[StatusTypeName]
|
||||
,[ForeignKeyType]
|
||||
,[ReferenceType]
|
||||
,[AccountChartOfID]
|
||||
FROM [e2A].[dbo].[tblStockStatusType]
|
||||
WHERE 1=1 ";
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = sql;
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
if (sqlWhere.ParameterListIsSet)
|
||||
{
|
||||
sqlWhere.AddParametersToSqlCommand(cmd);
|
||||
}
|
||||
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
var statusTypeBuilder = new Model.Stock.StatusTypeBuilder
|
||||
{
|
||||
StockStatusTypeID = reader.GetInt32(0),
|
||||
StatusTypeName = reader.GetString(1),
|
||||
ForeignKeyType = reader.IsDBNull(2) ? null : reader.GetString(2),
|
||||
ReferenceType = reader.IsDBNull(3) ? null : reader.GetString(3),
|
||||
AccountId = reader.GetInt32(4)
|
||||
};
|
||||
returnDict.Add(statusTypeBuilder.StockStatusTypeID, statusTypeBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnDict;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,8 +44,8 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
|
||||
|
||||
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
|
||||
{
|
||||
cmd.CommandText = sql;
|
||||
cmd.Transaction = _transaction as SqlTransaction;
|
||||
cmd.CommandText = sql;
|
||||
|
||||
sqlwhere.AddParametersToSqlCommand(cmd);
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
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 IAccountJournalRepository
|
||||
{
|
||||
int InsertJournalHeader(int journalTypeId, DateTime entryDate, bool lockEntry = false);
|
||||
int InsertJournalPost(int accountJournalId, int accountChartOfId, decimal amountGbp);
|
||||
Dictionary<int, Model.Account.JournalBuilder> ReadJournalBuilder(List<int> journalIdList);
|
||||
DateTime ReadJournalEntryDate(int journalId);
|
||||
int CountJournalPosts(int accountJournalId);
|
||||
bool IsJournalDebitAssetType(int accountJournalId);
|
||||
bool? IsJournalLocked(int journalId);
|
||||
List<(int, string, int?, int?)> ReadJournalType(List<int> accountJournalTypeIds = null, List<string> typeTitles = null);
|
||||
(int?, int?) ReadJournalTypeDefaultDebitCredit(int accountJournalId);
|
||||
bool UpdateJournalEntryModifiedDate(int accountJournalId);
|
||||
int DeleteJournalHeader(int accountJournalId);
|
||||
int DeleteJournalPostAll(int accountJournalId);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
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 IJournalRepository
|
||||
{
|
||||
Dictionary<int, Core.Model.Account.Journal> ReadJournal(List<int> journalIdList);
|
||||
bool ReadJournalIsLocked(int journalId);
|
||||
Dictionary<int, Model.Account.JournalType> ReadJournalType(List<int> journalTypeIds = null, List<string> typeTitles = null);
|
||||
bool DeleteJournal(int accountJournalId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
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
|
||||
{
|
||||
int DeletePurchaseLineTransaction(int accountJournalId);
|
||||
void InsertPurchaseLineTransaction(int accountJournalId, int purchaseLineId);
|
||||
void WIP_PurchaseLineTransactionNetUpdate(int accountJouranlId, string currencyCode, decimal amountNet, int debitAccountId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
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 InsertStockJournalHeader(int stockId, int journalTypeId, DateTime entryDate, bool isLocked);
|
||||
int InsertStockJournalPost(int stockJournalId, int stockStatusId, int quantity);
|
||||
Dictionary<int, Model.Stock.StockJournalBuilder> ReadStockJournal(bool lockRecords = false,
|
||||
List<int> stockJournalIds = null, List<int> stockIds = null, List<string> stockNumbers = null
|
||||
, DateTime? minEntryDate = null, DateTime? maxEntryDate = null, List<int> stockStatusIds = null);
|
||||
Dictionary<int, (int id, string title, int? stockStatusIdDebit, int? stockStatusIdCredit)> ReadStockJournalType(List<int> stockJournalTypeIdList);
|
||||
(int, DateTime) ReadJournalStockIdAndEntryDate(int stockJournalId);
|
||||
int ReadJournalTypeIdByStockId(int stockId);
|
||||
int ReadStatusBalanceBySku(string sku, int statusId);
|
||||
int ReadStatusBalanceByStockNumber(int stockNumber, int statusId);
|
||||
int ReadStatusBalanceByStockId(int stockId, int statusId);
|
||||
int ReadJournalEntryCountByStockId(int stockId);
|
||||
int? ReadTypeIdStatusCreditId(int stockJournalTypeId);
|
||||
DateTime? ReadMostRecentEntryDateForStatusDebit(int stockId, List<int> stockStatusIdList);
|
||||
void StockJournalDelete(int stockJournalId);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,13 @@ namespace bnhtrade.Core.Data.Database.Repository.Interface
|
||||
{
|
||||
internal interface IStockRepository
|
||||
{
|
||||
List<Model.Stock.Status> ReadStatus(List<int> statusIds = null, List<int> statusTypeIds = null);
|
||||
Dictionary<int, Model.Stock.StatusType> ReadStatusType();
|
||||
int InsertNewStock(int skuId, int accountJournalId);
|
||||
int CountStockTableRecords(List<int> accountJournalId = null);
|
||||
int? ReadStockIdByAccountJournalId(int accountJournalId);
|
||||
int? ReadAccountJournalId(int stockId);
|
||||
int? ReadStockJournalId(int stockId);
|
||||
int UpdateAccountJournalId(int stockId, int? accountJournalID);
|
||||
int UpdateStockJournalId(int stockId, int? stockJournalID);
|
||||
int DeleteStock(int stockId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Repository.Interface
|
||||
{
|
||||
internal interface IStockStatusRepository
|
||||
{
|
||||
Dictionary<int, Model.Stock.StatusBuilder> ReadStatus(List<int> statusIds = null, List<int> statusTypeIds = null);
|
||||
Dictionary<int, Model.Stock.StatusTypeBuilder> ReadStatusType(List<int> stockStatusTypeIds = null);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Transactions;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Sku.Price
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using bnhtrade.Core.Data.Database._BoilerPlate;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -10,17 +8,15 @@ using Microsoft.IdentityModel.Tokens;
|
||||
namespace bnhtrade.Core.Data.Database
|
||||
{
|
||||
/// <summary>
|
||||
/// Step 1: Call the methods for each where clause you want to create. This can be done multiple times to create an sql where string. Pay attention
|
||||
/// to the prefixes that you'll require between each where clause, as each time a method is called the sql statement will be appended to the previous sql
|
||||
/// string.
|
||||
/// Sep 1: Call each Where_____ method in this class as needed, the method returns a string that can be appended to your SQL statement and builds
|
||||
/// a parameter list.
|
||||
///
|
||||
/// Step 2: Appened the created sql string to your sql statement, NB the WHERE statemet is not included by default.
|
||||
///
|
||||
/// Step 3: Once you've created your sql command object, add the parameters to it using the method contained within this class.
|
||||
/// Step 2: Once you've created your sql command object, add the parameters to it using the method contained within this class.
|
||||
///
|
||||
/// Step 4: exceute your sql commend.
|
||||
/// </summary>
|
||||
public class SqlWhereBuilder
|
||||
|
||||
internal class SqlWhereBuilder
|
||||
{
|
||||
private int parameterCount = 0;
|
||||
|
||||
@@ -29,8 +25,10 @@ namespace bnhtrade.Core.Data.Database
|
||||
Init();
|
||||
}
|
||||
|
||||
[Obsolete("Deprecated. Use the new methods.")]
|
||||
public string SqlWhereString { get; private set; }
|
||||
|
||||
[Obsolete("Deprecated. Use the new methods.")]
|
||||
public bool IsSetSqlWhereString
|
||||
{
|
||||
get
|
||||
@@ -117,6 +115,7 @@ namespace bnhtrade.Core.Data.Database
|
||||
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
|
||||
/// <param name="phraseList">List of phrases to test in condition statement</param>
|
||||
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
|
||||
[Obsolete("Deprecated. Use the new methods.")]
|
||||
public void LikeAnd(string columnReference, IEnumerable<string> phraseList, string wherePrefix = null)
|
||||
{
|
||||
Like(columnReference, phraseList, true, wherePrefix);
|
||||
@@ -128,11 +127,13 @@ namespace bnhtrade.Core.Data.Database
|
||||
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
|
||||
/// <param name="phraseList">List of phrases to test in condition statement</param>
|
||||
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
|
||||
[Obsolete("Deprecated. Use the new methods.")]
|
||||
public void LikeOr(string columnReference, IEnumerable<string> phraseList, string wherePrefix = null)
|
||||
{
|
||||
Like(columnReference, phraseList, false, wherePrefix);
|
||||
}
|
||||
|
||||
[Obsolete("Deprecated. Use the new methods.")]
|
||||
private void Like(string columnReference, IEnumerable<string> phraseList, bool isAnd, string wherePrefix = null)
|
||||
{
|
||||
if (phraseList == null || !phraseList.Any())
|
||||
@@ -192,35 +193,62 @@ namespace bnhtrade.Core.Data.Database
|
||||
}
|
||||
|
||||
|
||||
public void IsEqualTo(string columnReference, bool booleanValue, string wherePrefix = null)
|
||||
//public void IsEqualTo(string columnReference, bool booleanValue, string wherePrefix = null)
|
||||
//{
|
||||
// string sqlWhereString = @"
|
||||
// ";
|
||||
|
||||
// if (wherePrefix != null)
|
||||
// {
|
||||
// sqlWhereString += wherePrefix;
|
||||
// }
|
||||
|
||||
// sqlWhereString += " ( " + columnReference + " = ";
|
||||
|
||||
// if (booleanValue)
|
||||
// {
|
||||
// sqlWhereString += "1 ) ";
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// sqlWhereString += "0 ) ";
|
||||
// }
|
||||
|
||||
// SqlWhereString = SqlWhereString + sqlWhereString;
|
||||
//}
|
||||
|
||||
[Obsolete("Deprecated. Use the new methods.")]
|
||||
public void IsEqualTo(string columnReference, object whereArgument, string wherePrefix = null)
|
||||
{
|
||||
string sqlWhereString = @"
|
||||
";
|
||||
|
||||
if (wherePrefix != null)
|
||||
{
|
||||
sqlWhereString += wherePrefix;
|
||||
}
|
||||
|
||||
sqlWhereString += " ( " + columnReference + " = ";
|
||||
|
||||
if (booleanValue)
|
||||
{
|
||||
sqlWhereString += "1 ) ";
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlWhereString += "0 ) ";
|
||||
}
|
||||
|
||||
SqlWhereString = SqlWhereString + sqlWhereString;
|
||||
IsEqualSub(columnReference, whereArgument, "=", wherePrefix);
|
||||
}
|
||||
|
||||
public void IsEqualTo(string columnReference, string stringValue, string wherePrefix = null)
|
||||
[Obsolete("Deprecated. Use the new methods.")]
|
||||
public void IsEqualToOrLessThan(string columnReference, object whereArgument, string wherePrefix = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(stringValue) || string.IsNullOrEmpty(columnReference))
|
||||
IsEqualSub(columnReference, whereArgument, "<=", wherePrefix);
|
||||
}
|
||||
|
||||
[Obsolete("Deprecated. Use the new methods.")]
|
||||
public void IsEqualToOrGreaterThan(string columnReference, object whereArgument, string wherePrefix = null)
|
||||
{
|
||||
IsEqualSub(columnReference, whereArgument, ">=", wherePrefix);
|
||||
}
|
||||
|
||||
[Obsolete("Deprecated. Use the new methods.")]
|
||||
private void IsEqualSub(string columnReference, object whereArgument, string operatorString, string wherePrefix = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(columnReference))
|
||||
{
|
||||
throw new Exception(wherePrefix + " IsEqualTo method requires a valid column reference and string value.");
|
||||
throw new Exception(wherePrefix + " IsEqual method requires a valid column reference.");
|
||||
}
|
||||
if (whereArgument == null)
|
||||
{
|
||||
throw new Exception(wherePrefix + " IsEqual method requires a valid where argument.");
|
||||
}
|
||||
if (whereArgument is string && string.IsNullOrEmpty(whereArgument.ToString()))
|
||||
{
|
||||
throw new Exception(wherePrefix + " IsEqual method requires a valid where argument.");
|
||||
}
|
||||
|
||||
string sqlWhereString = @"
|
||||
@@ -230,27 +258,26 @@ namespace bnhtrade.Core.Data.Database
|
||||
{
|
||||
sqlWhereString += wherePrefix;
|
||||
}
|
||||
|
||||
sqlWhereString += " ( " + columnReference + " = " + GetSetParameter(stringValue) + " ) ";
|
||||
sqlWhereString += " ( " + columnReference + " " + operatorString + " " + GetSetParameter(whereArgument) + " ) ";
|
||||
|
||||
SqlWhereString = SqlWhereString + sqlWhereString;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Append an 'In' statement and parameter list to the class properties
|
||||
/// </summary>
|
||||
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
|
||||
/// <param name="orValueList">List of values to test in condition statement</param>
|
||||
/// <param name="orArgumentList">List of values to test in condition statement</param>
|
||||
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
|
||||
public void In(string columnReference, IEnumerable<object> orValueList, string wherePrefix = null)
|
||||
[Obsolete("Deprecated. Use the new methods.")]
|
||||
public void In(string columnReference, IEnumerable<object> orArgumentList, string wherePrefix = null)
|
||||
{
|
||||
if (orValueList == null || !orValueList.Any())
|
||||
if (orArgumentList == null || !orArgumentList.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var distinctList = orValueList.Distinct().ToList();
|
||||
var distinctList = orArgumentList.Distinct().ToList();
|
||||
|
||||
string sqlWhere = @"
|
||||
";
|
||||
@@ -281,15 +308,16 @@ namespace bnhtrade.Core.Data.Database
|
||||
/// Append an 'In' statement and parameter list to the class properties
|
||||
/// </summary>
|
||||
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
|
||||
/// <param name="orValueList">List of values to test in condition statement</param>
|
||||
/// <param name="orArgumentList">List of values to test in condition statement</param>
|
||||
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
|
||||
public void In(string columnReference, IEnumerable<string> orValueList, string wherePrefix = null)
|
||||
[Obsolete("Deprecated. Use the new methods.")]
|
||||
public void In(string columnReference, IEnumerable<string> orArgumentList, string wherePrefix = null)
|
||||
{
|
||||
var objectList = new List<object>();
|
||||
|
||||
if (orValueList != null && orValueList.Any())
|
||||
if (orArgumentList != null && orArgumentList.Any())
|
||||
{
|
||||
foreach (string value in orValueList)
|
||||
foreach (string value in orArgumentList)
|
||||
{
|
||||
objectList.Add(value.ToString());
|
||||
}
|
||||
@@ -302,15 +330,16 @@ namespace bnhtrade.Core.Data.Database
|
||||
/// Append an 'In' statement and parameter list to the class properties
|
||||
/// </summary>
|
||||
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
|
||||
/// <param name="orValueList">List of values to test in condition statement</param>
|
||||
/// <param name="orArgumentList">List of values to test in condition statement</param>
|
||||
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
|
||||
public void In(string columnReference, IEnumerable<int> orValueList, string wherePrefix = null)
|
||||
[Obsolete("Deprecated. Use the new methods.")]
|
||||
public void In(string columnReference, IEnumerable<int> orArgumentList, string wherePrefix = null)
|
||||
{
|
||||
var objectList = new List<object>();
|
||||
|
||||
if (orValueList != null && orValueList.Any())
|
||||
if (orArgumentList != null && orArgumentList.Any())
|
||||
{
|
||||
foreach (var value in orValueList)
|
||||
foreach (var value in orArgumentList)
|
||||
{
|
||||
objectList.Add(value.ToString());
|
||||
}
|
||||
@@ -323,15 +352,16 @@ namespace bnhtrade.Core.Data.Database
|
||||
/// Append an 'In' statement and parameter list to the class properties
|
||||
/// </summary>
|
||||
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
|
||||
/// <param name="orValueList">List of values to test in condition statement</param>
|
||||
/// <param name="orArgumentList">List of values to test in condition statement</param>
|
||||
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
|
||||
public void In(string columnReference, IEnumerable<uint> orValueList, string wherePrefix = null)
|
||||
[Obsolete("Deprecated. Use the new methods.")]
|
||||
public void In(string columnReference, IEnumerable<uint> orArgumentList, string wherePrefix = null)
|
||||
{
|
||||
var objectList = new List<object>();
|
||||
|
||||
if (orValueList != null && orValueList.Any())
|
||||
if (orArgumentList != null && orArgumentList.Any())
|
||||
{
|
||||
foreach (var value in orValueList)
|
||||
foreach (var value in orArgumentList)
|
||||
{
|
||||
objectList.Add(value.ToString());
|
||||
}
|
||||
@@ -340,13 +370,14 @@ namespace bnhtrade.Core.Data.Database
|
||||
In(columnReference, objectList, wherePrefix);
|
||||
}
|
||||
|
||||
public void In(string columnReference, IEnumerable<DateTime> orValueList, string wherePrefix = null)
|
||||
[Obsolete("Deprecated. Use the new methods.")]
|
||||
public void In(string columnReference, IEnumerable<DateTime> orArgumentList, string wherePrefix = null)
|
||||
{
|
||||
var objectList = new List<object>();
|
||||
|
||||
if (orValueList != null && orValueList.Any())
|
||||
if (orArgumentList != null && orArgumentList.Any())
|
||||
{
|
||||
foreach(var value in orValueList)
|
||||
foreach(var value in orArgumentList)
|
||||
{
|
||||
objectList.Add(value.ToString());
|
||||
}
|
||||
@@ -355,17 +386,188 @@ namespace bnhtrade.Core.Data.Database
|
||||
In(columnReference, objectList, wherePrefix);
|
||||
}
|
||||
|
||||
//
|
||||
// new code below, going to change everything over to these methods, it returns the sql string instead of appending it to the class property
|
||||
// which is more versatile and more intuitive to use
|
||||
//
|
||||
|
||||
/// <summary>
|
||||
/// Append an 'Like' statement (with AND between each like string) and parameter list to the class properties
|
||||
/// </summary>
|
||||
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
|
||||
/// <param name="arguments">List of phrases to test in condition statement</param>
|
||||
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
|
||||
public string LikeAndClause(string columnReference, IEnumerable<string> arguments, string clausePrefix = null, string clausePostfix = null)
|
||||
{
|
||||
return LikeClause(columnReference, arguments, true, clausePrefix, clausePostfix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append an 'Like' statement (with OR between each like string) and parameter list to the class properties
|
||||
/// </summary>
|
||||
/// <param name="columnReference">Name of the column to used to for the condition statement</param>
|
||||
/// <param name="phraseList">List of phrases to test in condition statement</param>
|
||||
/// <param name="wherePrefix">Optional prefix that gets added to the sql string result</param>
|
||||
public string LikeOrClause(string columnReference, IEnumerable<string> arguments, string clausePrefix = null, string clausePostfix = null)
|
||||
{
|
||||
return LikeClause(columnReference, arguments, false, clausePrefix, clausePostfix);
|
||||
}
|
||||
|
||||
private string LikeClause(string columnReference, IEnumerable<string> arguments, bool isAnd, string clausePrefix = null, string clausePostfix = null)
|
||||
{
|
||||
if (arguments == null || !arguments.Any())
|
||||
{
|
||||
throw new ArgumentException("The arguments cannot be null or empty.", nameof(arguments));
|
||||
}
|
||||
|
||||
// ensure no values are repeated
|
||||
var distinctList = arguments.Distinct().ToList();
|
||||
|
||||
// clean the list
|
||||
for (int i = 0; i < distinctList.Count; i++)
|
||||
{
|
||||
if (string.IsNullOrEmpty(distinctList[i]))
|
||||
{
|
||||
distinctList.RemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
// check again
|
||||
if (distinctList == null || !distinctList.Any())
|
||||
{
|
||||
throw new ArgumentException("The arguments must contain at least one valid value.", nameof(arguments));
|
||||
}
|
||||
|
||||
string sqlWhere = Environment.NewLine + clausePrefix + " ";
|
||||
|
||||
|
||||
int listCount = distinctList.Count();
|
||||
for (int i = 0; i < listCount; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
if (isAnd)
|
||||
{
|
||||
sqlWhere += " AND ";
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlWhere += " OR ";
|
||||
}
|
||||
}
|
||||
|
||||
sqlWhere += " ( " + columnReference + " LIKE '%' + ";
|
||||
|
||||
|
||||
sqlWhere = sqlWhere + GetSetParameter(distinctList[i]) + " + '%' ) ";
|
||||
}
|
||||
return sqlWhere + clausePostfix;
|
||||
}
|
||||
|
||||
|
||||
public string IsEqualToClause(string columnReference, object whereArgument, string clausePrefix = null, string clausePostfix = null)
|
||||
{
|
||||
return IsEqualSubClause(columnReference, whereArgument, "=", clausePrefix, clausePostfix);
|
||||
}
|
||||
|
||||
public string IsEqualToOrLessThanClause(string columnReference, object whereArgument, string clausePrefix = null, string clausePostfix = null)
|
||||
{
|
||||
return IsEqualSubClause(columnReference, whereArgument, "<=", clausePrefix, clausePostfix);
|
||||
}
|
||||
|
||||
public string IsEqualToOrGreaterThanClause(string columnReference, object whereArgument, string clausePrefix = null, string clausePostfix = null)
|
||||
{
|
||||
return IsEqualSubClause(columnReference, whereArgument, ">=", clausePrefix, clausePostfix);
|
||||
}
|
||||
|
||||
private string IsEqualSubClause(string columnReference, object whereArgument, string operatorString, string clausePrefix = null, string clausePostfix = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(columnReference))
|
||||
{
|
||||
throw new Exception(" WhereIsEqual* method requires a valid column reference.");
|
||||
}
|
||||
if (whereArgument == null)
|
||||
{
|
||||
throw new Exception(" WhereIsEqual* method requires a valid where argument.");
|
||||
}
|
||||
if (whereArgument is string && string.IsNullOrEmpty(whereArgument.ToString()))
|
||||
{
|
||||
throw new Exception(" WhereIsEqual* method requires a valid where argument.");
|
||||
}
|
||||
|
||||
// build the SQL WHERE clause and parameter list
|
||||
string sqlWhere = Environment.NewLine + clausePrefix + " ( " + columnReference + " " + operatorString + " " + GetSetParameter(whereArgument) + " ) ";
|
||||
|
||||
return sqlWhere + clausePostfix;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a SQL WHERE clause with an IN condition for the specified column and a list of values and adds to the parameter list.
|
||||
/// </summary>
|
||||
/// <param name="columnReference">The name of the column to be used in the IN condition</param>
|
||||
/// <param name="orArgumentList">A collection of values to include in the IN condition.</param>
|
||||
/// <param name="lineReturn">A boolean value indicating whether to prefix the returned SQL clause with a line return</param>
|
||||
/// <returns>A string representing the SQL WHERE clause with the specified column and values in the IN condition.</returns>
|
||||
public string InClause<T>(string columnReference, IEnumerable<T> orArgumentList, string clausePrefix = null, string clausePostfix = null)
|
||||
{
|
||||
// new code, going to change everything over to this method, it returns the sql string instead of appending it to the class property
|
||||
// which is more versatile and more intuitive to use
|
||||
|
||||
if (string.IsNullOrEmpty(columnReference))
|
||||
{
|
||||
throw new ArgumentException("Column reference cannot be null or empty.", nameof(columnReference));
|
||||
}
|
||||
if (orArgumentList == null || !orArgumentList.Any())
|
||||
{
|
||||
throw new ArgumentException("The orArgumentList cannot be null or empty.", nameof(orArgumentList));
|
||||
}
|
||||
|
||||
// ensure no values are repeated, null, or empty
|
||||
var distinctList = orArgumentList
|
||||
.Where(x =>
|
||||
x is not null && // not null
|
||||
(!(x.GetType().IsGenericType && x.GetType().GetGenericTypeDefinition() == typeof(Nullable<>)) // not a nullable type
|
||||
|| x.GetType().GetProperty("HasValue")?.GetValue(x) as bool? == true) // or, if nullable, HasValue is true
|
||||
&& (!(x is string s) || !string.IsNullOrEmpty(s)) // not an empty string
|
||||
)
|
||||
.ToList();
|
||||
|
||||
if (!distinctList.Any())
|
||||
{
|
||||
throw new ArgumentException("The orArgumentList must contain at least one valid value.", nameof(orArgumentList));
|
||||
}
|
||||
|
||||
// build the SQL WHERE clause and parameter list
|
||||
string sqlWhere = Environment.NewLine + clausePrefix + " " + columnReference + " IN ( ";
|
||||
|
||||
int listCount = distinctList.Count();
|
||||
for (int i = 0; i < listCount; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
sqlWhere += ", ";
|
||||
}
|
||||
|
||||
sqlWhere = sqlWhere + GetSetParameter(distinctList[i]);
|
||||
}
|
||||
sqlWhere += " ) ";
|
||||
|
||||
return sqlWhere + clausePostfix;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a string value to the ParameterList and returns '@parameterN' that is then appended to the SQL statement
|
||||
/// i.e. @parameter1, @parameter2, etc.
|
||||
/// </summary>
|
||||
/// <param name="value">parameter string that is then appended to the SQL statement</param>
|
||||
/// <param name="argument">parameter string that is then appended to the SQL statement</param>
|
||||
/// <returns></returns>
|
||||
private string GetSetParameter(string value)
|
||||
private string GetSetParameter(object argument)
|
||||
{
|
||||
parameterCount++;
|
||||
string parameterString = "@parameter" + parameterCount;
|
||||
ParameterList.Add(parameterString, value);
|
||||
ParameterList.Add(parameterString, argument);
|
||||
return parameterString;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Transactions;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.Stock
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -373,7 +373,7 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -13,76 +13,7 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
{
|
||||
}
|
||||
|
||||
public int BySku(string sku, int statusId)
|
||||
{
|
||||
int statusBalance = new int();
|
||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
using (SqlCommand cmd = new SqlCommand(@"
|
||||
SELECT SUM(tblStockJournalPost.Quantity) AS Balance
|
||||
FROM tblStockJournal INNER JOIN
|
||||
tblStockJournalPost ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID INNER JOIN
|
||||
tblStock ON tblStockJournal.StockID = tblStock.StockID INNER JOIN
|
||||
tblSku ON tblStock.SkuID = tblSku.skuSkuID
|
||||
WHERE (tblStockJournalPost.StockStatusID = @statusId) AND (tblSku.skuSkuNumber = @sku)
|
||||
", conn))
|
||||
{
|
||||
// add parameters
|
||||
cmd.Parameters.AddWithValue("@sku", sku);
|
||||
cmd.Parameters.AddWithValue("@statusId", statusId);
|
||||
|
||||
// execute
|
||||
object obj = cmd.ExecuteScalar();
|
||||
if (obj == null || obj == DBNull.Value)
|
||||
{
|
||||
statusBalance = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
statusBalance = (int)obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
return statusBalance;
|
||||
}
|
||||
|
||||
public int ByStockNumber(int stockNumber, int statusId)
|
||||
{
|
||||
int statusBalance = new int();
|
||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||
{
|
||||
conn.Open();
|
||||
|
||||
using (SqlCommand cmd = new SqlCommand(@"
|
||||
SELECT SUM(tblStockJournalPost.Quantity) AS Balance
|
||||
FROM tblStockJournal INNER JOIN
|
||||
tblStockJournalPost ON tblStockJournal.StockJournalID = tblStockJournalPost.StockJournalID INNER JOIN
|
||||
tblStock ON tblStockJournal.StockID = tblStock.StockID
|
||||
WHERE (tblStockJournalPost.StockStatusID = @statusId) AND (tblStock.StockNumber = @stockNumber)
|
||||
", conn))
|
||||
{
|
||||
// add parameters
|
||||
cmd.Parameters.AddWithValue("@stockNumber", stockNumber);
|
||||
cmd.Parameters.AddWithValue("@statusId", statusId);
|
||||
|
||||
// execute
|
||||
object obj = cmd.ExecuteScalar();
|
||||
if (obj == null || obj == DBNull.Value)
|
||||
{
|
||||
statusBalance = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
statusBalance = (int)obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
return statusBalance;
|
||||
}
|
||||
|
||||
public int ByStockId(int stockId, int statusId)
|
||||
public int ReadStatusBalanceByStockId(int stockId, int statusId)
|
||||
{
|
||||
int statusBalance = new int();
|
||||
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
|
||||
@@ -125,7 +56,7 @@ namespace bnhtrade.Core.Data.Database.Stock
|
||||
/// </summary>
|
||||
/// <param name="statusId">The stock status id</param>
|
||||
/// <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>();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Configuration;
|
||||
|
||||
namespace bnhtrade.Core.Data.Database.UnitOfWork
|
||||
|
||||
@@ -16,10 +16,13 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
|
||||
IExportInvoiceRepository ExportInvoiceRepository { get; }
|
||||
IAmazonSettlementRepository AmazonSettlementRepository { get; }
|
||||
IInvoiceRepository InvoiceRepository { get; }
|
||||
IJournalRepository JournalRepository { get; }
|
||||
IPurchaseRepository PurchaseRepository { get; }
|
||||
IAccountJournalRepository AccountJournalRepository { get; }
|
||||
ISequenceGenerator SequenceGenerator { get; }
|
||||
ISkuRepository SkuRepository { get; }
|
||||
IStockRepository StockRepository { get; }
|
||||
IStockJournalRepository StockJournalRepository { get; }
|
||||
IStockStatusRepository StockStatusRepository { get; }
|
||||
|
||||
// Methods to manage the transaction
|
||||
void Commit();
|
||||
|
||||
@@ -19,15 +19,18 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
|
||||
|
||||
// Private field for lazy loading, add here for each repository
|
||||
private IAccountCodeRepository _accountCodeRepository;
|
||||
private IAccountJournalRepository _accountJournalRepository;
|
||||
private IAccountTaxRepository _accountTaxRepository;
|
||||
private IAmazonSettlementRepository _amazonSettlementRepository;
|
||||
private ICurrencyRepository _currencyRepository;
|
||||
private IExportInvoiceRepository _exportInvoiceRepository;
|
||||
private IInvoiceRepository _invoiceRepository;
|
||||
private IJournalRepository _journalRepository;
|
||||
private IPurchaseRepository _purchaseRepository;
|
||||
private ISequenceGenerator _sequenceGenerator;
|
||||
private ISkuRepository _skuRepository;
|
||||
private IStockRepository _stockRepository;
|
||||
private IStockJournalRepository _stockJournalRespository;
|
||||
private IStockStatusRepository _stockStatusRepository;
|
||||
|
||||
internal UnitOfWork()
|
||||
{
|
||||
@@ -48,6 +51,18 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
|
||||
}
|
||||
}
|
||||
|
||||
public IAccountJournalRepository AccountJournalRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_accountJournalRepository == null)
|
||||
{
|
||||
_accountJournalRepository = new AccountJournalRepository(_connection, _transaction);
|
||||
}
|
||||
return _accountJournalRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public IAccountTaxRepository AccountTaxRepository
|
||||
{
|
||||
get
|
||||
@@ -108,15 +123,15 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
|
||||
}
|
||||
}
|
||||
|
||||
public IJournalRepository JournalRepository
|
||||
public IPurchaseRepository PurchaseRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_journalRepository == null)
|
||||
if (_purchaseRepository == null)
|
||||
{
|
||||
_journalRepository = new JournalRepository(_connection, _transaction);
|
||||
_purchaseRepository = new PurchaseRepository(_connection, _transaction);
|
||||
}
|
||||
return _journalRepository;
|
||||
return _purchaseRepository;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +171,30 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
|
||||
}
|
||||
}
|
||||
|
||||
public IStockJournalRepository StockJournalRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_stockJournalRespository == null)
|
||||
{
|
||||
_stockJournalRespository = new StockJournalRepository(_connection, _transaction);
|
||||
}
|
||||
return _stockJournalRespository;
|
||||
}
|
||||
}
|
||||
|
||||
public IStockStatusRepository StockStatusRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_stockStatusRepository == null)
|
||||
{
|
||||
_stockStatusRepository = new StockStatusRepository(_connection, _transaction);
|
||||
}
|
||||
return _stockStatusRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public void Commit()
|
||||
{
|
||||
try
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using bnhtrade.Core.Test.Amazon.SP_API;
|
||||
using CsvHelper;
|
||||
using CsvHelper.Configuration.Attributes;
|
||||
using Microsoft.VisualBasic.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using bnhtrade.Core.Data.Database.UnitOfWork;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -12,52 +13,16 @@ namespace bnhtrade.Core.Logic.Account
|
||||
{
|
||||
}
|
||||
|
||||
public Dictionary<int, Model.Account.Account> GetAll()
|
||||
internal AccountCodeService(IUnitOfWork unitOfWork) : base(unitOfWork)
|
||||
{
|
||||
}
|
||||
|
||||
public Dictionary<int, Model.Account.Account> GetAccountCode(List<int> accountIdList = null, List<int> accountCodeList = null)
|
||||
{
|
||||
return WithUnitOfWork(uow =>
|
||||
{
|
||||
return uow.AccountCodeRepository.ReadAccountCode();
|
||||
return uow.AccountCodeRepository.ReadAccountCode(accountIdList, accountCodeList);
|
||||
});
|
||||
}
|
||||
|
||||
public Model.Account.Account ByAccountCode(int accountCode)
|
||||
{
|
||||
var list = ByAccountCode(new List<int> { accountCode });
|
||||
if (list.Any())
|
||||
{
|
||||
return list[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Model.Account.Account> ByAccountCode(List<int> accountCodeList)
|
||||
{
|
||||
return WithUnitOfWork(uow =>
|
||||
{
|
||||
return uow.AccountCodeRepository.ReadAccountCode(null, accountCodeList).Values.ToList();
|
||||
});
|
||||
}
|
||||
|
||||
public Dictionary<int, Model.Account.Account> ConvertToDictionary(List<Model.Account.Account> accountCodeList)
|
||||
{
|
||||
var returnDict = new Dictionary<int, Model.Account.Account>();
|
||||
|
||||
if (accountCodeList == null)
|
||||
{
|
||||
return returnDict;
|
||||
}
|
||||
|
||||
foreach (var accountCode in accountCodeList)
|
||||
{
|
||||
if (!returnDict.ContainsKey((int)accountCode.AccountCode))
|
||||
{
|
||||
returnDict.Add((int)accountCode.AccountCode, accountCode);
|
||||
}
|
||||
}
|
||||
return returnDict;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
using bnhtrade.Core.Data.Database;
|
||||
using bnhtrade.Core.Data.Database.Repository.Implementation;
|
||||
using bnhtrade.Core.Data.Database.UnitOfWork;
|
||||
using FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentInbound;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Transactions;
|
||||
|
||||
namespace bnhtrade.Core.Logic.Account
|
||||
{
|
||||
public class AccountJournalService : UnitOfWorkBase
|
||||
{
|
||||
public AccountJournalService()
|
||||
{
|
||||
}
|
||||
|
||||
internal AccountJournalService(IUnitOfWork unitOfWork) : base(unitOfWork)
|
||||
{
|
||||
}
|
||||
|
||||
public int JournalInsert(int journalTypeId, DateTime entryDate, string currencyCode,
|
||||
decimal amount, int? debitAccountId = null, int? creditAccountId = null, bool lockEntry = false)
|
||||
{
|
||||
return WithUnitOfWork(uow =>
|
||||
{
|
||||
// insert header record
|
||||
int journalId = uow.AccountJournalRepository.InsertJournalHeader(journalTypeId, entryDate, lockEntry);
|
||||
|
||||
// ensure their are no other entries (not sure why this is needed, but it was in the old code)
|
||||
int count = uow.AccountJournalRepository.CountJournalPosts(journalId);
|
||||
if (count > 0)
|
||||
{
|
||||
throw new Exception("Unable the insert journal posts, post already present AccountJournalID=" + journalId);
|
||||
}
|
||||
|
||||
// check defaults for debit and credit accounts
|
||||
var result = uow.AccountJournalRepository.ReadJournalTypeDefaultDebitCredit(journalId);
|
||||
int? defaultDebit = result.Item1;
|
||||
int? defaultCredit = result.Item2;
|
||||
|
||||
if (defaultDebit == null)
|
||||
{
|
||||
if (debitAccountId == null)
|
||||
{
|
||||
throw new Exception("Debit Account ID required, default not set for journal type");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (debitAccountId == null)
|
||||
{
|
||||
debitAccountId = defaultDebit.Value;
|
||||
}
|
||||
else if (debitAccountId.Value != defaultDebit)
|
||||
{
|
||||
throw new Exception("Debit Account ID supplied does not match default set for journal type");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (defaultCredit == null)
|
||||
{
|
||||
if (creditAccountId == null)
|
||||
{
|
||||
throw new Exception("Credit Account ID required, default not set for journal type");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (creditAccountId == null)
|
||||
{
|
||||
creditAccountId = defaultCredit.Value;
|
||||
}
|
||||
else if (creditAccountId.Value != defaultCredit)
|
||||
{
|
||||
throw new Exception("Credit Account ID supplied does not match default set for journal type");
|
||||
}
|
||||
}
|
||||
|
||||
// currency conversion
|
||||
if (currencyCode != "GBP")
|
||||
{
|
||||
amount = new Logic.Account.CurrencyService(uow).CurrencyConvertToGbp(currencyCode, amount, entryDate);
|
||||
}
|
||||
|
||||
// ensure decimal is rounded
|
||||
amount = Math.Round(amount, 2);
|
||||
|
||||
// insert posts
|
||||
int debitPostId = uow.AccountJournalRepository.InsertJournalPost(journalId, debitAccountId.Value, amount);
|
||||
int creditPostId = uow.AccountJournalRepository.InsertJournalPost(journalId, creditAccountId.Value, amount * -1);
|
||||
|
||||
// need to add verification here to ensure the entry is correct
|
||||
|
||||
// finished
|
||||
CommitIfOwned(uow);
|
||||
return journalId;
|
||||
});
|
||||
}
|
||||
|
||||
public Dictionary<int, Core.Model.Account.Journal> ReadJournal(List<int> journalIdList)
|
||||
{
|
||||
throw new NotImplementedException("done, but needs testing");
|
||||
|
||||
var returnDict = new Dictionary<int, Core.Model.Account.Journal>();
|
||||
|
||||
WithUnitOfWork(uow =>
|
||||
{
|
||||
var builderDict = uow.AccountJournalRepository.ReadJournalBuilder(journalIdList);
|
||||
if (builderDict.Any())
|
||||
{
|
||||
// build list of journal types and accounts from the builderDict
|
||||
var journalTypeIdList = new List<int>();
|
||||
var accountIdList = new List<int>();
|
||||
|
||||
foreach (var journal in builderDict.Values)
|
||||
{
|
||||
journalTypeIdList.Add(journal.JournalTypeId);
|
||||
foreach (var post in journal.JournalBuilderPosts)
|
||||
{
|
||||
accountIdList.Add(post.AccountId);
|
||||
}
|
||||
}
|
||||
|
||||
journalTypeIdList = journalTypeIdList.Distinct().ToList();
|
||||
accountIdList = accountIdList.Distinct().ToList();
|
||||
|
||||
// get object dictionaries
|
||||
var journalTypeDict = ReadJournalType(journalTypeIdList);
|
||||
var accountDict = uow.AccountCodeRepository.ReadAccountCode(accountIdList);
|
||||
|
||||
// build final return dictionary
|
||||
foreach (var item in builderDict)
|
||||
{
|
||||
var journal = item.Value.Build(journalTypeDict, accountDict);
|
||||
returnDict.Add(journal.JournalId, journal);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return returnDict;
|
||||
}
|
||||
|
||||
public DateTime ReadJournalEntryDate(int journalId)
|
||||
{
|
||||
return WithUnitOfWork(uow =>
|
||||
{
|
||||
return uow.AccountJournalRepository.ReadJournalEntryDate(journalId);
|
||||
});
|
||||
}
|
||||
|
||||
public Dictionary<int, Model.Account.JournalType> ReadJournalType(List<int> journalTypeIdList)
|
||||
{
|
||||
var returnDict = new Dictionary<int, Model.Account.JournalType>();
|
||||
|
||||
WithUnitOfWork(uow =>
|
||||
{
|
||||
// get base info from db
|
||||
var dbJournalTypeList = uow.AccountJournalRepository.ReadJournalType(journalTypeIdList);
|
||||
|
||||
// build list of account object to retrieve
|
||||
var accountIdList = new List<int>();
|
||||
foreach (var dbJournalType in dbJournalTypeList)
|
||||
{
|
||||
if (dbJournalType.Item3.HasValue)
|
||||
{
|
||||
accountIdList.Add(dbJournalType.Item3.Value);
|
||||
}
|
||||
if (dbJournalType.Item4.HasValue)
|
||||
{
|
||||
accountIdList.Add(dbJournalType.Item4.Value);
|
||||
}
|
||||
}
|
||||
accountIdList = accountIdList.Distinct().ToList();
|
||||
|
||||
// retieve account objects from db
|
||||
var accountDict = uow.AccountCodeRepository.ReadAccountCode(accountIdList);
|
||||
|
||||
// build the return dictionary
|
||||
foreach (var dbJournalType in dbJournalTypeList)
|
||||
{
|
||||
var journalType = new Model.Account.JournalType(
|
||||
dbJournalType.Item1, // JournalTypeId
|
||||
dbJournalType.Item2, // Name
|
||||
dbJournalType.Item3.HasValue ? accountDict[dbJournalType.Item3.Value] : null, // DebitAccount
|
||||
dbJournalType.Item4.HasValue ? accountDict[dbJournalType.Item4.Value] : null // CreditAccount
|
||||
);
|
||||
returnDict.Add(journalType.JournalTypeId, journalType);
|
||||
}
|
||||
});
|
||||
|
||||
return returnDict;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all posts associated with an entry and replaces the posts for a journal entry with two new posts
|
||||
/// </summary>
|
||||
/// <param name="twoPostCheck">Raise exception if journal entry has more than two associated posts</param>
|
||||
internal bool AccountJournalPostReplace(int accountJournalId, string currencyCode, decimal amountGbp, int debitAccountId = 0, int creditAccountId = 0, bool twoPostCheck = true)
|
||||
{
|
||||
if (amountGbp <= 0)
|
||||
{
|
||||
throw new ArgumentException("Amount must be greater than zero", nameof(amountGbp));
|
||||
}
|
||||
if ( amountGbp.Scale > 2)
|
||||
{
|
||||
throw new ArgumentException("Amount must have a maximum of two decimal places", nameof(amountGbp));
|
||||
}
|
||||
if (debitAccountId <= 0 || creditAccountId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Debit and Credit Account IDs must be greater than zero", nameof(debitAccountId));
|
||||
}
|
||||
|
||||
WithUnitOfWork(uow =>
|
||||
{
|
||||
// check if the journal entry is locked
|
||||
bool? isLocked = uow.AccountJournalRepository.IsJournalLocked(accountJournalId);
|
||||
if (isLocked == null)
|
||||
{
|
||||
throw new Exception("Journal entry does not exist for AccountJournalID=" + accountJournalId);
|
||||
}
|
||||
else if (isLocked.Value)
|
||||
{
|
||||
throw new Exception("Cannot replace posts for locked journal entry AccountJournalID=" + accountJournalId);
|
||||
}
|
||||
|
||||
// retrive journal entry date
|
||||
DateTime entryDate = uow.AccountJournalRepository.ReadJournalEntryDate(accountJournalId);
|
||||
|
||||
// delete the original posts
|
||||
var rowsDeleted = uow.AccountJournalRepository.DeleteJournalPostAll(accountJournalId);
|
||||
if (rowsDeleted == 0)
|
||||
{
|
||||
throw new Exception("No posts found for AccountJournalID=" + accountJournalId);
|
||||
}
|
||||
if (twoPostCheck && rowsDeleted > 2)
|
||||
{
|
||||
throw new Exception("More than two posts found for AccountJournalID=" + accountJournalId + ", cannot replace posts with two new posts.");
|
||||
}
|
||||
|
||||
//insert new posts
|
||||
var rowsInserted = uow.AccountJournalRepository.InsertJournalPost(accountJournalId, debitAccountId, amountGbp);
|
||||
rowsInserted += uow.AccountJournalRepository.InsertJournalPost(accountJournalId, creditAccountId, amountGbp * -1);
|
||||
if (rowsInserted != 2)
|
||||
{
|
||||
throw new Exception("Failed to insert two posts for AccountJournalID=" + accountJournalId);
|
||||
}
|
||||
|
||||
// update modified date on journal
|
||||
if (uow.AccountJournalRepository.UpdateJournalEntryModifiedDate(accountJournalId) == false)
|
||||
{
|
||||
throw new Exception("Failed to update LastModified date for AccountJournalID=" + accountJournalId);
|
||||
}
|
||||
|
||||
CommitIfOwned(uow);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Old code needs sorting
|
||||
/// </summary>
|
||||
public bool DeleteJournal(int accountJournalId)
|
||||
{
|
||||
WithUnitOfWork(uow =>
|
||||
{
|
||||
if (accountJournalId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Account journal ID must be greater than zero", nameof(accountJournalId));
|
||||
}
|
||||
// check if the journal entry is locked
|
||||
bool? isLocked = uow.AccountJournalRepository.IsJournalLocked(accountJournalId);
|
||||
if (isLocked == null)
|
||||
{
|
||||
throw new Exception("Journal entry does not exist for AccountJournalID=" + accountJournalId);
|
||||
}
|
||||
else if (isLocked.Value)
|
||||
{
|
||||
throw new Exception("Cannot replace posts for locked journal entry AccountJournalID=" + accountJournalId);
|
||||
}
|
||||
|
||||
// delete posts first
|
||||
uow.AccountJournalRepository.DeleteJournalPostAll(accountJournalId);
|
||||
|
||||
// then delete header record
|
||||
uow.AccountJournalRepository.DeleteJournalHeader(accountJournalId);
|
||||
|
||||
CommitIfOwned(uow);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using FikaAmazonAPI.ConstructFeed.Messages;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -268,45 +268,6 @@ namespace bnhtrade.Core.Logic.Account
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime GetHmrcMaxPeriodAvaible()
|
||||
{
|
||||
// HMRC monthly exchange rates are published on the penultimate Thursday of the month before
|
||||
// For some leeeeeeeeway we'll use the penultimate Friday
|
||||
|
||||
// find penultimate Friday for current month
|
||||
var ukTimeNow = new Logic.Utilities.DateTime().ConvertUtcToUk(DateTime.UtcNow);
|
||||
var monthDayCount = DateTime.DaysInMonth(ukTimeNow.Year, ukTimeNow.Month);
|
||||
var thisMonthPenultimateFriday = DateTime.SpecifyKind(new DateTime(ukTimeNow.Year, ukTimeNow.Month, monthDayCount), DateTimeKind.Unspecified);
|
||||
int count = 0;
|
||||
int fridayCount = 0;
|
||||
while (count != 15)
|
||||
{
|
||||
if (thisMonthPenultimateFriday.DayOfWeek == DayOfWeek.Friday)
|
||||
{
|
||||
fridayCount++;
|
||||
if (fridayCount == 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
thisMonthPenultimateFriday = thisMonthPenultimateFriday.AddDays(-1);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 15)
|
||||
{
|
||||
throw new Exception("Something went wrong here ErrorID:ef7f5d8f-0f7b-4014-aa65-421ecd5d7367");
|
||||
}
|
||||
|
||||
var mostRecentPeriodAvaible = DateTime.SpecifyKind(new DateTime(ukTimeNow.Year, ukTimeNow.Month, 1), DateTimeKind.Unspecified); ;
|
||||
if (ukTimeNow >= thisMonthPenultimateFriday)
|
||||
{
|
||||
mostRecentPeriodAvaible = mostRecentPeriodAvaible.AddMonths(1);
|
||||
}
|
||||
|
||||
return mostRecentPeriodAvaible;
|
||||
}
|
||||
|
||||
public void UpdateHmrcExchageRates()
|
||||
{
|
||||
Init();
|
||||
@@ -381,16 +342,48 @@ namespace bnhtrade.Core.Logic.Account
|
||||
}
|
||||
|
||||
// check if retrival from hmrc is required
|
||||
var hmrcMaxMonthAvaible = GetHmrcMaxPeriodAvaible();
|
||||
if (hmrcMonthToRetrive.Year == hmrcMaxMonthAvaible.Year && hmrcMonthToRetrive.Month > hmrcMaxMonthAvaible.Month)
|
||||
// find penultimate Friday for current month
|
||||
var ukTimeNow = new Logic.Utilities.DateTime().ConvertUtcToUk(DateTime.UtcNow);
|
||||
var monthDayCount = DateTime.DaysInMonth(ukTimeNow.Year, ukTimeNow.Month);
|
||||
var thisMonthPenultimateFriday = DateTime.SpecifyKind(new DateTime(ukTimeNow.Year, ukTimeNow.Month, monthDayCount), DateTimeKind.Unspecified);
|
||||
int dayCount = 0;
|
||||
int fridayCount = 0;
|
||||
while (dayCount < 15)
|
||||
{
|
||||
if (thisMonthPenultimateFriday.DayOfWeek == DayOfWeek.Friday)
|
||||
{
|
||||
fridayCount++;
|
||||
if (fridayCount == 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
thisMonthPenultimateFriday = thisMonthPenultimateFriday.AddDays(-1);
|
||||
dayCount++;
|
||||
}
|
||||
|
||||
if (dayCount == 15)
|
||||
{
|
||||
throw new Exception("Something went wrong here ErrorID:ef7f5d8f-0f7b-4014-aa65-421ecd5d7367");
|
||||
}
|
||||
|
||||
var mostRecentPeriodAvaible = DateTime.SpecifyKind(new DateTime(ukTimeNow.Year, ukTimeNow.Month, 1), DateTimeKind.Unspecified); ;
|
||||
if (ukTimeNow >= thisMonthPenultimateFriday)
|
||||
{
|
||||
mostRecentPeriodAvaible = mostRecentPeriodAvaible.AddMonths(1);
|
||||
}
|
||||
|
||||
if (hmrcMonthToRetrive.Year >= mostRecentPeriodAvaible.Year && hmrcMonthToRetrive.Month > mostRecentPeriodAvaible.Month)
|
||||
{
|
||||
// nothing to retrive
|
||||
_log.LogInformation("Exchange rates curretly up to date, exiting.");
|
||||
int days = (thisMonthPenultimateFriday - DateTime.UtcNow).Days;
|
||||
_log.LogInformation($"Exchange rates up to date, next HMRC update in {days} days for {hmrcMonthToRetrive.ToString("MMM yyyy")}.");
|
||||
_log.LogInformation($"Stopping update database HMRC exchange rates.");
|
||||
return;
|
||||
}
|
||||
|
||||
// get info from hmrc and insert data in db
|
||||
while (hmrcMonthToRetrive <= hmrcMaxMonthAvaible)
|
||||
while (hmrcMonthToRetrive <= mostRecentPeriodAvaible)
|
||||
{
|
||||
count = 0;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace bnhtrade.Core.Logic.Account
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,10 +173,12 @@ namespace bnhtrade.Core.Logic.Export.AccountInvoice
|
||||
null, new List<string> { settlementList[i].MarketPlace.GetMarketplaceUrl() }, true, true, 1);
|
||||
if (completedSettlement.Any())
|
||||
{
|
||||
if (completedSettlement.FirstOrDefault().Value.EndDate != settlementList[i].StartDate)
|
||||
var tempEndDate = completedSettlement.FirstOrDefault().Value.EndDate;
|
||||
|
||||
if (tempEndDate != settlementList[i].StartDate)
|
||||
{
|
||||
string error = (settlementList[i].StartDate - settlementList[i - 1].EndDate).Days + " day gap in "
|
||||
+ settlementList[i].MarketPlace.GetMarketplaceUrl() + " settlement data (" + settlementList[i - 1].EndDate.ToString("dd MMM yyyy")
|
||||
string error = (settlementList[i].StartDate - tempEndDate).Days + " day gap in "
|
||||
+ settlementList[i].MarketPlace.GetMarketplaceUrl() + " settlement data (" + tempEndDate.ToString("dd MMM yyyy")
|
||||
+ " to " + settlementList[i].StartDate.ToString("dd MMM yyyy") + "). Ensure all settlement reports have been imported.";
|
||||
ErrorMessage = error;
|
||||
_log.LogError("Cancelled processing of Amazon settlement data into invoice export queue: " + error);
|
||||
|
||||
+7
-4
@@ -1,13 +1,16 @@
|
||||
using System;
|
||||
using bnhtrade.Core.Data.Database.UnitOfWork;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Transactions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace bnhtrade.Core.Logic.Sku
|
||||
namespace bnhtrade.Core.Logic.Inventory
|
||||
{
|
||||
public class SkuService : UnitOfWorkBase
|
||||
{
|
||||
public SkuService() : base() { }
|
||||
|
||||
internal SkuService(IUnitOfWork unitOfWork) : base(unitOfWork) { }
|
||||
|
||||
/// <summary>
|
||||
/// Used for retriving an SKU ID by parameters. If no match, can create a new SKU if required.
|
||||
/// </summary>
|
||||
@@ -0,0 +1,570 @@
|
||||
using Amazon.Runtime.Internal.Transform;
|
||||
using bnhtrade.Core.Data.Database.UnitOfWork;
|
||||
using bnhtrade.Core.Logic.Account;
|
||||
using bnhtrade.Core.Model.Account;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static System.Formats.Asn1.AsnWriter;
|
||||
|
||||
namespace bnhtrade.Core.Logic.Inventory
|
||||
{
|
||||
public class StockJournalService : UnitOfWorkBase
|
||||
{
|
||||
public StockJournalService() { }
|
||||
|
||||
internal StockJournalService(IUnitOfWork unitOfWork) : base(unitOfWork) { }
|
||||
|
||||
public Dictionary<int, Model.Stock.StockJournal> ReadStockJournal(List<int> stockJournalIds)
|
||||
{
|
||||
return WithUnitOfWork(uow =>
|
||||
{
|
||||
return ReadStockJournal(uow, false, stockJournalIds);
|
||||
});
|
||||
}
|
||||
|
||||
internal Dictionary<int, Model.Stock.StockJournal> ReadStockJournal(IUnitOfWork uow, bool lockJournalEntries, List<int> stockJournalIds)
|
||||
{
|
||||
if (stockJournalIds == null || stockJournalIds.Count == 0)
|
||||
{
|
||||
throw new ArgumentException("Stock journal IDs cannot be null or empty.", nameof(stockJournalIds));
|
||||
}
|
||||
|
||||
// get the stock journal entries from the repository
|
||||
var builderList = uow.StockJournalRepository.ReadStockJournal(lockJournalEntries, stockJournalIds);
|
||||
|
||||
// get the stock status for the journal posts
|
||||
var statusIds = new List<int>();
|
||||
foreach (var journal in builderList.Values)
|
||||
{
|
||||
foreach (var post in journal.StockJournalBuilderPosts)
|
||||
{
|
||||
if (!statusIds.Contains(post.StatusId))
|
||||
{
|
||||
statusIds.Add(post.StatusId);
|
||||
}
|
||||
}
|
||||
}
|
||||
var statusDict = new StockStatusService(uow).GetStatus(statusIds);
|
||||
|
||||
// get the stock journal types for the journal entries
|
||||
var journalTypeIds = new List<int>();
|
||||
foreach (var journal in builderList.Values)
|
||||
{
|
||||
if (!journalTypeIds.Contains(journal.StockJournalTypeId))
|
||||
{
|
||||
journalTypeIds.Add(journal.StockJournalTypeId);
|
||||
}
|
||||
}
|
||||
var journalTypeDict = ReadStockJournalType(uow, journalTypeIds);
|
||||
|
||||
// build the stock journal objects and return them in a dictionary
|
||||
var returnDict = new Dictionary<int, Model.Stock.StockJournal>();
|
||||
foreach (var journal in builderList.Values)
|
||||
{
|
||||
returnDict.Add(journal.StockJournalId, journal.Build(journalTypeDict, statusDict));
|
||||
}
|
||||
|
||||
return returnDict;
|
||||
}
|
||||
|
||||
public Dictionary<int, Model.Stock.StockJournalType> ReadStockJournalType(List<int> stockJournalTypeIds = null)
|
||||
{
|
||||
return WithUnitOfWork(uow =>
|
||||
{
|
||||
return ReadStockJournalType(uow, stockJournalTypeIds);
|
||||
});
|
||||
}
|
||||
|
||||
private Dictionary<int, Model.Stock.StockJournalType> ReadStockJournalType(IUnitOfWork uow, List<int> stockJournalTypeIds = null)
|
||||
{
|
||||
return WithUnitOfWork(uow =>
|
||||
{
|
||||
// get the stock journal types from the repository
|
||||
var tupleList = uow.StockJournalRepository.ReadStockJournalType(stockJournalTypeIds);
|
||||
|
||||
// get the accounts for the stock journal types
|
||||
var statusIds = new List<int>();
|
||||
foreach (var type in tupleList.Values)
|
||||
{
|
||||
if (type.stockStatusIdDebit.HasValue)
|
||||
{
|
||||
statusIds.Add(type.stockStatusIdDebit.Value);
|
||||
}
|
||||
|
||||
if (type.stockStatusIdCredit.HasValue)
|
||||
{
|
||||
statusIds.Add(type.stockStatusIdCredit.Value);
|
||||
}
|
||||
}
|
||||
statusIds = statusIds.Distinct().ToList();
|
||||
var statusDict = new StockStatusService(uow).GetStatus(statusIds);
|
||||
|
||||
// build the stock journal type objects and return them in a dictionary
|
||||
var returnDict = new Dictionary<int, Model.Stock.StockJournalType>();
|
||||
foreach (var type in tupleList.Values)
|
||||
{
|
||||
var debitStatus = type.stockStatusIdDebit.HasValue ? statusDict[type.stockStatusIdDebit.Value] : null;
|
||||
var creditStatus = type.stockStatusIdCredit.HasValue ? statusDict[type.stockStatusIdCredit.Value] : null;
|
||||
|
||||
var stockJournalType = new Model.Stock.StockJournalType(
|
||||
type.id,
|
||||
type.title,
|
||||
debitStatus,
|
||||
creditStatus
|
||||
);
|
||||
|
||||
returnDict.Add(stockJournalType.StockJournalTypeID, stockJournalType);
|
||||
}
|
||||
return returnDict;
|
||||
});
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* Future me here, refactored the code to use a UnitOfWork pattern, wil need to check that this is still the case.
|
||||
*/
|
||||
|
||||
|
||||
// balance and status IsCredit checks made by post insert function
|
||||
|
||||
//consitancy check is required?
|
||||
bool consistencyRequired = true;
|
||||
|
||||
return WithUnitOfWork(uow =>
|
||||
{
|
||||
// get date of most recent debit for status' that I will be crediting
|
||||
if (isNewStock == false)
|
||||
{
|
||||
var debitStatusIds = new List<int>();
|
||||
foreach (var post in journalPosts)
|
||||
{
|
||||
if (post.quantity > 0)
|
||||
{
|
||||
debitStatusIds.Add(post.statusId);
|
||||
}
|
||||
}
|
||||
var mostRecentDebitDate = uow.StockJournalRepository.ReadMostRecentEntryDateForStatusDebit(stockId, debitStatusIds);
|
||||
if (mostRecentDebitDate.HasValue && mostRecentDebitDate >= entryDate)
|
||||
{
|
||||
consistencyRequired = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
consistencyRequired = false;
|
||||
}
|
||||
}
|
||||
|
||||
// create journal entry
|
||||
int stockJournalId = uow.StockJournalRepository.InsertStockJournalHeader(stockId, journalTypeId, entryDate, isNewStock);
|
||||
|
||||
// insert journal posts into database
|
||||
//new Data.Database.Stock
|
||||
var insertCount = StockJournalPostInsert(uow, 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 = WIP_StockJournalConsistencyCheck(uow, stockId, statusIdEffected);
|
||||
}
|
||||
|
||||
if (consistencyResult)
|
||||
{
|
||||
// commit
|
||||
CommitIfOwned(uow);
|
||||
return stockJournalId;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unable to insert stock journal entry, consistancy check failed.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private int StockJournalPostInsert(IUnitOfWork uow, 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 for now, it's 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 statusDict = new StockStatusService(uow).GetStatus(dicStatusQty.Keys.ToList());
|
||||
var dicStatusIsCreditOnly = new Dictionary<int, bool>();
|
||||
foreach (var status in statusDict.Values.ToList())
|
||||
{
|
||||
dicStatusIsCreditOnly.Add(status.StatusId, status.IsCreditOnly);
|
||||
}
|
||||
|
||||
// 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
|
||||
var postIdList = new List<int>();
|
||||
foreach (var post in journalPosts)
|
||||
{
|
||||
postIdList.Add(uow.StockJournalRepository.InsertStockJournalPost(stockJournalId, post.statusId, post.quantity));
|
||||
}
|
||||
return postIdList.Count();
|
||||
}
|
||||
|
||||
public bool StockJournalDelete(int stockJournalId)
|
||||
{
|
||||
return WithUnitOfWork(uow =>
|
||||
{
|
||||
var result = StockJournalDelete(uow, stockJournalId);
|
||||
|
||||
if (result)
|
||||
{
|
||||
CommitIfOwned(uow);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To be used internally (private). Deletes a stock journal entry and performs a consistency check, does not roll back transaction on fail.
|
||||
/// </summary>
|
||||
/// <returns>consistantcy check result, true=good, false=bad</returns>
|
||||
private bool StockJournalDelete(IUnitOfWork uow, int stockJournalId)
|
||||
{
|
||||
// get journal entry
|
||||
var stockJournalDict = uow.StockJournalRepository.ReadStockJournal(true, new List<int> { stockJournalId });
|
||||
if (stockJournalDict.Count == 0)
|
||||
{
|
||||
throw new Exception("StockJournalID=" + stockJournalId + " does not exist!");
|
||||
}
|
||||
var stockJournal = stockJournalDict[stockJournalId];
|
||||
|
||||
// build list of debits to check
|
||||
var debitStatusIds = new List<int>();
|
||||
foreach (var post in stockJournal.StockJournalBuilderPosts)
|
||||
{
|
||||
if (post.IsDebit)
|
||||
{
|
||||
debitStatusIds.Add(post.StatusId);
|
||||
}
|
||||
}
|
||||
|
||||
// get all journal entries for stockId and debit status combination where entryDate >= stockJournal.EntryDate
|
||||
var journalList = uow.StockJournalRepository.ReadStockJournal(
|
||||
true, null, new List<int> { stockJournal.StockId }, null, stockJournal.EntryDate, null, debitStatusIds
|
||||
);
|
||||
|
||||
// check no credits for stockId & debit status combination have been made since delete entry
|
||||
bool consistancyCheckRequired = false;
|
||||
foreach (var item in journalList.Values)
|
||||
{
|
||||
foreach (var post in item.StockJournalBuilderPosts)
|
||||
{
|
||||
if (post.Quantity < 0 && debitStatusIds.Contains(post.StatusId))
|
||||
{
|
||||
consistancyCheckRequired = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make the delete
|
||||
uow.StockJournalRepository.StockJournalDelete(stockJournalId);
|
||||
|
||||
// consistanct check
|
||||
bool consistencyResult = true;
|
||||
if (consistancyCheckRequired)
|
||||
{
|
||||
// run check
|
||||
consistencyResult = WIP_StockJournalConsistencyCheck(uow, stockJournal.StockId, debitStatusIds);
|
||||
}
|
||||
|
||||
if (consistencyResult)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// can be used before commiting an sql insert, update or delete to the stock journal to ensure a status does not fall below 0
|
||||
// (unless the status is enabled to do so)
|
||||
// set empty list or statusIdEffected to null to check entier stock entries for consistency
|
||||
internal bool WIP_StockJournalConsistencyCheck(int stockId, List<int> statusIdsEffected = null)
|
||||
{
|
||||
if (statusIdsEffected == null)
|
||||
{
|
||||
statusIdsEffected = new List<int>();
|
||||
}
|
||||
|
||||
// if no list supplied, build list of all used status' for stockId
|
||||
if (statusIdsEffected.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())
|
||||
{
|
||||
statusIdsEffected.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 < statusIdsEffected.Count; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
sqlString = sqlString + " WHERE tblStockStatus.StockStatusID=" + statusIdsEffected[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlString = sqlString + " OR tblStockStatus.StockStatusID=" + statusIdsEffected[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 statusIdsEffected)
|
||||
{
|
||||
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 statusIdsEffected)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
using bnhtrade.Core.Data.Database.UnitOfWork;
|
||||
using bnhtrade.Core.Logic.Account;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Transactions;
|
||||
using static System.Formats.Asn1.AsnWriter;
|
||||
|
||||
namespace bnhtrade.Core.Logic.Inventory
|
||||
{
|
||||
public class StockService : UnitOfWorkBase
|
||||
{
|
||||
public StockService() : base() { }
|
||||
|
||||
internal StockService(IUnitOfWork unitOfWork) : base(unitOfWork) { }
|
||||
|
||||
public int WIP_StockInsertPurchase(int productId, int conditionId, int accountTaxCodeId, int accountJournalId, int quantity, int statusDebitId)
|
||||
{
|
||||
DateTime stockJournalEntryDate;
|
||||
int stockJournalTypeId = 1;
|
||||
|
||||
return WithUnitOfWork(uow =>
|
||||
{
|
||||
stockJournalEntryDate = new AccountJournalService(uow).ReadJournalEntryDate(accountJournalId);
|
||||
int result = WIP_StockInsertSub(
|
||||
uow, productId, conditionId, accountTaxCodeId, accountJournalId, stockJournalTypeId, stockJournalEntryDate, quantity, statusDebitId);
|
||||
CommitIfOwned(uow);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
public int WIP_StockInsertOwnerIntroduced(decimal amount, int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId)
|
||||
{
|
||||
int accountJournalType = 3;
|
||||
int stockJournalType = 2;
|
||||
string currencyCode = "GBP";
|
||||
|
||||
return WithUnitOfWork(uow =>
|
||||
{
|
||||
int stockId = WIP_StockInsert(uow, accountJournalType, stockJournalType, currencyCode, amount, quantity, productId, conditionId, accountTaxCodeId, entryDate, debitStatusId);
|
||||
CommitIfOwned(uow);
|
||||
return stockId;
|
||||
});
|
||||
}
|
||||
|
||||
private int WIP_StockInsert(IUnitOfWork uow, int accountJournalType, int stockJournalType, string currencyCode, decimal amount,
|
||||
int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId)
|
||||
{
|
||||
// add account journal entry
|
||||
int accountJournalId = new Logic.Account.AccountJournalService(uow).JournalInsert(accountJournalType, entryDate, currencyCode, amount);
|
||||
|
||||
// make the stock insert
|
||||
int stockId = WIP_StockInsertSub(uow, productId, conditionId, accountTaxCodeId,
|
||||
accountJournalId, stockJournalType, entryDate, quantity, debitStatusId);
|
||||
|
||||
return stockId;
|
||||
}
|
||||
|
||||
private int WIP_StockInsertSub(IUnitOfWork uow, int productId, int conditionId, int accountTaxCodeId,
|
||||
int accountJournalId, int stockJournalTypeId, DateTime stockJournalEntryDate, int quantity, int statusDebitId)
|
||||
{
|
||||
stockJournalEntryDate = DateTime.SpecifyKind(stockJournalEntryDate, DateTimeKind.Utc);
|
||||
|
||||
// ensure account journal id hasn't already been added to stock table
|
||||
int count = uow.StockRepository.CountStockTableRecords(new List<int> { accountJournalId });
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
throw new Exception("Add account journal entry already assigned to stock line.");
|
||||
}
|
||||
else if (count > 1)
|
||||
{
|
||||
throw new Exception("Houston we have a problem! An account journal entry is assigned to " + count + " stock lines.");
|
||||
}
|
||||
|
||||
// ensure the debit for the account journal transaction is to an 'Asset' account type
|
||||
bool isIt = uow.AccountJournalRepository.IsJournalDebitAssetType(accountJournalId);
|
||||
if (!isIt)
|
||||
{
|
||||
throw new Exception("Supplied AccountJournal entry must debit an 'Asset' account type.");
|
||||
}
|
||||
|
||||
// get statusCreditId for stock journal type
|
||||
int? statusCreditId = uow.StockJournalRepository.ReadTypeIdStatusCreditId(stockJournalTypeId);
|
||||
|
||||
if (statusCreditId == null)
|
||||
{
|
||||
throw new Exception("Default credit status not set for StockJournalTypeID=" + stockJournalTypeId);
|
||||
}
|
||||
|
||||
// get/set an skuId
|
||||
int skuId = new Logic.Inventory.SkuService(uow).GetSkuId(productId, conditionId, accountTaxCodeId, true);
|
||||
|
||||
// add the entry to the stock table (minus stockJournalId)
|
||||
int stockId = uow.StockRepository.InsertNewStock(skuId, accountJournalId);
|
||||
|
||||
// insert stock journal entry
|
||||
var journalPosts = new List<(int statusId, int quantity)>();
|
||||
journalPosts.Add((statusDebitId, quantity));
|
||||
journalPosts.Add((statusCreditId.Value, (quantity * -1)));
|
||||
int stockJournalId = new StockJournalService(uow).StockJournalInsert(stockJournalTypeId, stockId, journalPosts, stockJournalEntryDate, true);
|
||||
|
||||
// update the stock table
|
||||
count = uow.StockRepository.UpdateStockJournalId(stockId, stockJournalId);
|
||||
if (count < 1)
|
||||
{
|
||||
throw new Exception("New stock insert cancelled, failed to update StockJournalID");
|
||||
}
|
||||
|
||||
return stockId;
|
||||
}
|
||||
|
||||
public void WIP_StockDeletePurchase(int stockId)
|
||||
{
|
||||
WithUnitOfWork(uow =>
|
||||
{
|
||||
if (stockId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId));
|
||||
}
|
||||
WIP_StockDelete(uow, stockId);
|
||||
CommitIfOwned(uow);
|
||||
});
|
||||
}
|
||||
|
||||
public void WIP_StockDeleteOwnerIntroduced(int stockId)
|
||||
{
|
||||
WithUnitOfWork(uow =>
|
||||
{
|
||||
if (stockId <= 0)
|
||||
{
|
||||
throw new ArgumentException("Stock ID must be greater than zero", nameof(stockId));
|
||||
}
|
||||
WIP_StockDelete(uow, stockId);
|
||||
CommitIfOwned(uow);
|
||||
});
|
||||
}
|
||||
|
||||
private void WIP_StockDelete(IUnitOfWork uow, int stockId)
|
||||
{
|
||||
int stockJournalType = 0;
|
||||
|
||||
// ensure stockId is owner-introduced
|
||||
stockJournalType = uow.StockJournalRepository.ReadJournalTypeIdByStockId(stockId);
|
||||
|
||||
// check stock journal type is not restricted
|
||||
// owner inventory introduced
|
||||
if (stockJournalType == 2)
|
||||
{
|
||||
// no dramas
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Manual delete of this stock type is not supported, use the method that created it!");
|
||||
}
|
||||
|
||||
// check there is only one stock journal entry for stock item (i.e. the source entry)
|
||||
int count = uow.StockJournalRepository.ReadJournalEntryCountByStockId(stockId);
|
||||
|
||||
if (count > 1)
|
||||
{
|
||||
throw new Exception("Delete " + count + " stock journal entries (other than source entry), before peforming this operation.");
|
||||
}
|
||||
|
||||
// remove account journal entry
|
||||
WIP_StockDeleteSubAccountJournalEntry(uow, stockId);
|
||||
|
||||
// remove stock
|
||||
WIP_StockDeleteSub(uow, stockId);
|
||||
}
|
||||
|
||||
private void WIP_StockDeleteSub(IUnitOfWork uow, int stockId)
|
||||
{
|
||||
// check for accountJournalId on stock table
|
||||
int? accountJournalId = uow.StockRepository.ReadAccountJournalId(stockId);
|
||||
if (accountJournalId.HasValue)
|
||||
{
|
||||
throw new Exception("StockID=" + stockId + " remove account journal entry using method that created it first.");
|
||||
}
|
||||
|
||||
// get stockJournalId
|
||||
int stockJournalId = uow.StockRepository.ReadStockJournalId(stockId) ?? throw new Exception("StockJournalID not found for StockID=" + stockId);
|
||||
|
||||
// remove stockJournalId from stock table
|
||||
int count = uow.StockRepository.UpdateStockJournalId(stockId, null);
|
||||
if (count != 2) // we need to count the LastUpdated trigger!
|
||||
{
|
||||
throw new Exception("Failed to remove StockJournalID from stock table StockID=" + stockId);
|
||||
}
|
||||
|
||||
// delete stock journal entry
|
||||
new StockJournalService(uow).StockJournalDelete(stockJournalId);
|
||||
|
||||
// delete stock table entry
|
||||
count = uow.StockRepository.DeleteStock(stockId);
|
||||
if (count != 1)
|
||||
{
|
||||
throw new Exception("StockID = " + stockId + " delete failed");
|
||||
}
|
||||
}
|
||||
|
||||
// to be used by other methods within a transaction scope
|
||||
private void WIP_StockDeleteSubAccountJournalEntry(IUnitOfWork uow, int stockId)
|
||||
{
|
||||
// get the account journal id
|
||||
int accountJournalId = uow.StockRepository.ReadAccountJournalId(stockId) ?? throw new Exception("AccountJournalID not found for StockID=" + stockId);
|
||||
|
||||
// remove entry from stock table
|
||||
int count = uow.StockRepository.UpdateAccountJournalId(stockId, null);
|
||||
|
||||
if (count != 2) // must include last modified trigger
|
||||
{
|
||||
throw new Exception("Failed to set AccountJournalID to NULL on stock table for StockID=" + stockId);
|
||||
}
|
||||
|
||||
// delete account journal entry
|
||||
new AccountJournalService(uow).DeleteJournal(accountJournalId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
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) { }
|
||||
|
||||
public Dictionary<int, Model.Stock.Status> GetStatus(List<int> statusIds = null, List<int> statusTypeIds = null)
|
||||
{
|
||||
return WithUnitOfWork(uow =>
|
||||
{
|
||||
var builderList = uow.StockStatusRepository.ReadStatus(statusIds, statusTypeIds).Values.ToList();
|
||||
|
||||
var satusTypeIdList = new List<int>();
|
||||
foreach (var status in builderList)
|
||||
{
|
||||
satusTypeIdList.Add(status.StatusTypeId);
|
||||
}
|
||||
satusTypeIdList = satusTypeIdList.Distinct().ToList();
|
||||
var statusTypeDict = GetStatusType(uow, satusTypeIdList);
|
||||
|
||||
var retrunDict = new Dictionary<int, Model.Stock.Status>();
|
||||
foreach (var status in builderList)
|
||||
{
|
||||
retrunDict.Add(status.StatusId, status.Build(statusTypeDict));
|
||||
}
|
||||
return retrunDict;
|
||||
});
|
||||
}
|
||||
|
||||
private Dictionary<int, Model.Stock.StatusType> GetStatusType(IUnitOfWork uow, List<int> statusTypeIds = null)
|
||||
{
|
||||
// get the status types from the repository
|
||||
var typeBuilderList = uow.StockStatusRepository.ReadStatusType(statusTypeIds);
|
||||
|
||||
// get the accounts for the status types
|
||||
var accountIds = new List<int>();
|
||||
foreach (var type in typeBuilderList.Values)
|
||||
{
|
||||
accountIds.Add(type.AccountId);
|
||||
}
|
||||
accountIds = accountIds.Distinct().ToList();
|
||||
var accountDict = uow.AccountCodeRepository.ReadAccountCode(accountIds);
|
||||
|
||||
// build the status type objects and return them in a dictionary
|
||||
var returnDict = new Dictionary<int, Model.Stock.StatusType>();
|
||||
foreach (var type in typeBuilderList.Values)
|
||||
{
|
||||
returnDict.Add(type.StockStatusTypeID, type.Build(accountDict));
|
||||
}
|
||||
return returnDict;
|
||||
}
|
||||
|
||||
public Dictionary<int, Model.Stock.StatusType> GetStatusType(List<int> statusTypeIds = null)
|
||||
{
|
||||
return WithUnitOfWork(uow =>
|
||||
{
|
||||
return GetStatusType(uow, statusTypeIds);
|
||||
});
|
||||
}
|
||||
|
||||
/// <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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using bnhtrade.Core.Data.Database.Repository.Implementation;
|
||||
using bnhtrade.Core.Data.Database.UnitOfWork;
|
||||
using bnhtrade.Core.Logic.Account;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Transactions;
|
||||
|
||||
namespace bnhtrade.Core.Logic.Purchase
|
||||
{
|
||||
public class PurchaseService : UnitOfWorkBase
|
||||
{
|
||||
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 PurchaseService() : base() { }
|
||||
|
||||
internal PurchaseService(IUnitOfWork unitOfWork) : base(unitOfWork) { }
|
||||
|
||||
public void WIP_PurchaseLineTransactionNetInsert(int purchaseLineId, string currencyCode, decimal amountNet, DateTime entryDate, int? debitAccountId = null)
|
||||
{
|
||||
// default to 'Inventory, Receivable/Processing'
|
||||
if (debitAccountId == null)
|
||||
{
|
||||
debitAccountId = defaultAccountId;
|
||||
}
|
||||
|
||||
WithUnitOfWork(uow =>
|
||||
{
|
||||
int journalId = new AccountJournalService(uow).JournalInsert(accountJournalTypeIdNet, entryDate, currencyCode, amountNet, debitAccountId.Value);
|
||||
uow.PurchaseRepository.InsertPurchaseLineTransaction(journalId, purchaseLineId);
|
||||
CommitIfOwned(uow);
|
||||
});
|
||||
}
|
||||
|
||||
public void WIP_PurchaseLineTransactionNetUpdate(int accountJouranlId, string currencyCode, decimal amountNet, int debitAccountId)
|
||||
{
|
||||
WithUnitOfWork(uow =>
|
||||
{
|
||||
// stock accountId check
|
||||
if (debitAccountId == 86)
|
||||
{
|
||||
int? stockId = uow.StockRepository.ReadStockIdByAccountJournalId(accountJouranlId);
|
||||
|
||||
if (stockId.HasValue == false)
|
||||
{
|
||||
throw new Exception("Add account journal entry to stock before attempting this operation.");
|
||||
}
|
||||
}
|
||||
|
||||
// make the update
|
||||
new AccountJournalService(uow).AccountJournalPostReplace(accountJouranlId, currencyCode, amountNet, debitAccountId, creditAccountId);
|
||||
CommitIfOwned(uow);
|
||||
});
|
||||
}
|
||||
|
||||
public void WIP_PurchaseLineTransactionDelete(int purchaseLineId, int accountJournalId)
|
||||
{
|
||||
WithUnitOfWork(uow =>
|
||||
{
|
||||
// check accountJournalId does not exist in stock table
|
||||
int? stockId = uow.StockRepository.ReadStockIdByAccountJournalId(accountJournalId);
|
||||
if (stockId.HasValue)
|
||||
{
|
||||
throw new Exception("Delete stock first before proceeding, AccountJournalID=" + accountJournalId);
|
||||
}
|
||||
|
||||
// delete line in purchase line transaction table
|
||||
int deleted = uow.PurchaseRepository.DeletePurchaseLineTransaction(accountJournalId);
|
||||
|
||||
if (deleted != 1)
|
||||
{
|
||||
throw new Exception("Operation cancelled, failed to delete entry in tblPurchaseLineTransaction WHERE AccountJournalID=" + accountJournalId);
|
||||
}
|
||||
|
||||
// delete account journal entry
|
||||
new AccountJournalService(uow).DeleteJournal(accountJournalId);
|
||||
|
||||
CommitIfOwned(uow);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using CsvHelper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Transactions;
|
||||
|
||||
namespace bnhtrade.Core.Logic.Sku.Price
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using bnhtrade.Core.Data.Database;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
@@ -3,7 +3,7 @@ using bnhtrade.Core.Model.Stock;
|
||||
using FikaAmazonAPI.AmazonSpApiSDK.Models.Restrictions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using bnhtrade.Core.Data.Database;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -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>
|
||||
/// 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>
|
||||
/// <param name="skuNumber">SKU number</param>
|
||||
/// <param name="statusId">Status ID</param>
|
||||
@@ -113,7 +100,7 @@ namespace bnhtrade.Core.Logic.Stock
|
||||
var sku = readSku.BySkuNumber(statusTransaction.SkuNumber);
|
||||
|
||||
// get the status obj
|
||||
var status = uow.StockRepository.ReadStatus(new List<int> { statusTransaction.StockStatusId })[0];
|
||||
var status = new Logic.Inventory.StockStatusService(uow).GetStatus(new List<int> { statusTransaction.StockStatusId }).Values.First();
|
||||
|
||||
return new Model.Stock.StatusBalance(status, sku, entryList);
|
||||
}
|
||||
@@ -131,7 +118,7 @@ namespace bnhtrade.Core.Logic.Stock
|
||||
/// <returns>Dictionary of SKUs and the repective balance of each</returns>
|
||||
public Dictionary<string, int> GetSkuQuantity(int statusId)
|
||||
{
|
||||
return new Data.Database.Stock.ReadStatusBalance().ByStatusId(statusId);
|
||||
return new Data.Database.Stock.ReadStatusBalance().ReadStatusBalanceByStatusId(statusId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,20 @@ namespace bnhtrade.Core.Logic.Validate
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that a stock number string is in the format 'STK#000000' (six digits).
|
||||
/// </summary>
|
||||
/// <param name="stockNumber"></param>
|
||||
/// <returns></returns>
|
||||
public static bool StockNumber(string stockNumber)
|
||||
{
|
||||
if (string.IsNullOrEmpty(stockNumber))
|
||||
return false;
|
||||
|
||||
// Check for exact match: STK# followed by 6 digits
|
||||
return System.Text.RegularExpressions.Regex.IsMatch(stockNumber, @"^STK#\d{6}$");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks the datetime is not default and is utc
|
||||
/// </summary>
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace bnhtrade.Core.Model.Account
|
||||
{
|
||||
public Account(int id, int accountCode, string accountName, string description, string type, string basicType, int multiplier)
|
||||
{
|
||||
Id = id;
|
||||
AccountId = id;
|
||||
AccountCode = accountCode;
|
||||
AccountName = accountName;
|
||||
Description = description;
|
||||
@@ -23,18 +23,18 @@ namespace bnhtrade.Core.Model.Account
|
||||
/// <summary>
|
||||
/// Database record id
|
||||
/// </summary>
|
||||
public int Id { get; private set; }
|
||||
public int AccountId { get; }
|
||||
|
||||
public int AccountCode { get; private set; }
|
||||
public int AccountCode { get; }
|
||||
|
||||
public string AccountName { get; private set; }
|
||||
public string AccountName { get; }
|
||||
|
||||
public string Description { get; private set; }
|
||||
public string Description { get; }
|
||||
|
||||
public string Type { get; private set; }
|
||||
public string Type { get; }
|
||||
|
||||
public string BasicType { get; private set; }
|
||||
public string BasicType { get; }
|
||||
|
||||
public int Multiplier { get; private set; }
|
||||
public int Multiplier { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Microsoft.VisualBasic;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bnhtrade.Core.Model.Account
|
||||
{
|
||||
public class JournalBuilder
|
||||
{
|
||||
// Setters for each property
|
||||
public int JournalId { get; set; }
|
||||
public int JournalTypeId { get; set; }
|
||||
public List<JournalPostBuilder> JournalBuilderPosts { get; set; }
|
||||
public DateTime EntryDate { get; set; }
|
||||
public DateTime PostDate { get; set; }
|
||||
public DateTime LastModified { get; set; }
|
||||
public bool IsLocked { get; set; }
|
||||
|
||||
public class JournalPostBuilder
|
||||
{
|
||||
public int AccountId { get; set; }
|
||||
public int PostId { get; set; }
|
||||
public decimal AmountGbp { get; set; }
|
||||
}
|
||||
|
||||
public Journal Build(Dictionary<int, Model.Account.JournalType> journalTypeDict, Dictionary<int, Model.Account.Account> accountDict)
|
||||
{
|
||||
if (journalTypeDict == null || !journalTypeDict.ContainsKey(JournalTypeId))
|
||||
{
|
||||
throw new ArgumentException($"Journal type with ID {JournalTypeId} does not exist.");
|
||||
}
|
||||
if (JournalBuilderPosts == null || JournalBuilderPosts.Count == 0)
|
||||
{
|
||||
throw new ArgumentException("Journal posts cannot be null or empty.");
|
||||
}
|
||||
if (accountDict == null || accountDict.Any() == false)
|
||||
{
|
||||
throw new ArgumentException("Account dictionary cannot be null or empty");
|
||||
}
|
||||
|
||||
// build lines
|
||||
var journalPosts = new List<Journal.Post>();
|
||||
foreach (var post in JournalBuilderPosts)
|
||||
{
|
||||
if (!accountDict.ContainsKey(post.AccountId))
|
||||
{
|
||||
throw new ArgumentException($"Account with ID {post.AccountId} does not exist.");
|
||||
}
|
||||
journalPosts.Add(new Journal.Post(post.PostId, accountDict[post.AccountId], post.AmountGbp));
|
||||
}
|
||||
|
||||
return new Journal(
|
||||
JournalId
|
||||
, journalTypeDict[JournalTypeId]
|
||||
, journalPosts
|
||||
, EntryDate
|
||||
, PostDate
|
||||
, LastModified
|
||||
, IsLocked);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,24 +16,18 @@ namespace bnhtrade.Core.Model.Account
|
||||
DefaultDebitAccount = defaultDebitAccount;
|
||||
}
|
||||
|
||||
internal void AddDefaultAccounts(Model.Account.Account defaultCreditAccount = null, Model.Account.Account defaultDebitAccount = null)
|
||||
{
|
||||
DefaultCreditAccount = defaultCreditAccount;
|
||||
DefaultDebitAccount = defaultDebitAccount;
|
||||
}
|
||||
public int JournalTypeId { get; }
|
||||
|
||||
public int JournalTypeId { get ; private set; }
|
||||
public string Title { get; }
|
||||
|
||||
public string Title { get; private set; }
|
||||
|
||||
public Model.Account.Account DefaultDebitAccount { get; private set; }
|
||||
public Model.Account.Account DefaultDebitAccount { get; }
|
||||
|
||||
public bool IsSetDefaultDebitAccount
|
||||
{
|
||||
get { return DefaultDebitAccount != null; }
|
||||
}
|
||||
|
||||
public Model.Account.Account DefaultCreditAccount { get; private set; }
|
||||
public Model.Account.Account DefaultCreditAccount { get; }
|
||||
|
||||
public bool IsSetDefaultCreditAccount
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace bnhtrade.Core.Model.Credentials
|
||||
{
|
||||
return "Data Source=" + DataSource + ";Initial Catalog=" + InitialCatalog + ";Persist Security Info=" + PersistSecurityInfo.ToString()
|
||||
+ ";User ID=" + UserId + ";Password=" + UserPassword + ";MultipleActiveResultSets=" + MultipleActiveResultSets.ToString()
|
||||
+ ";Connect Timeout=" + ConnectionTimeout + ";Encrypt=True;TrustServerCertificate=True";
|
||||
+ ";Connect Timeout=" + ConnectionTimeout + ";Encrypt=True";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bnhtrade.Core.Model.Stock
|
||||
{
|
||||
public class JournalEntry : IValidatableObject
|
||||
{
|
||||
public string TypeTitle { get; set; }
|
||||
|
||||
public int StockNumber { get; set; }
|
||||
|
||||
public DateTime EntryDate { get; set; }
|
||||
|
||||
public DateTime PostDate { get; set; }
|
||||
|
||||
public DateTime LastModified { get; set; }
|
||||
|
||||
public bool IsLocked { get; set; }
|
||||
|
||||
public List<JournalEntryPost> JournalPosts { get; set; } = new List<JournalEntryPost>();
|
||||
|
||||
public class JournalEntryPost
|
||||
{
|
||||
public int JournalPostId { get; set; }
|
||||
|
||||
public int StockStatusId { get; set; }
|
||||
|
||||
[Required()]
|
||||
public string StockStatus { get; set; }
|
||||
|
||||
[Required()]
|
||||
public int Quantity { get; set; }
|
||||
}
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,22 +21,32 @@ namespace bnhtrade.Core.Model.Stock
|
||||
RecordCreated = recordCreated;
|
||||
}
|
||||
|
||||
public int StatusId { get; private set; }
|
||||
public int StatusId { get; }
|
||||
|
||||
public int? StatusCode { get; private set; }
|
||||
public int? StatusCode { get; }
|
||||
|
||||
public string StatusTitle { get; private set; }
|
||||
public bool StatusCodeIsSet
|
||||
{
|
||||
get { return StatusCode.HasValue; }
|
||||
}
|
||||
|
||||
public Model.Stock.StatusType StatusType { get; private set; }
|
||||
public string StatusTitle { get; }
|
||||
|
||||
public string Reference { get; private set; }
|
||||
public Model.Stock.StatusType StatusType { get; }
|
||||
|
||||
public int? ForeignKeyID { get; private set; }
|
||||
public string Reference { get; }
|
||||
|
||||
public bool IsCreditOnly { get; private set; }
|
||||
public int? ForeignKeyID { get; }
|
||||
|
||||
public bool IsClosed { get; private set; }
|
||||
public bool ForeignKeyIDIsSet
|
||||
{
|
||||
get { return ForeignKeyID.HasValue; }
|
||||
}
|
||||
|
||||
public DateTime RecordCreated { get; private set; }
|
||||
public bool IsCreditOnly { get; }
|
||||
|
||||
public bool IsClosed { get; }
|
||||
|
||||
public DateTime RecordCreated { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bnhtrade.Core.Model.Stock
|
||||
{
|
||||
internal class StatusBuilder
|
||||
{
|
||||
public int StatusId { get; set; }
|
||||
|
||||
public int? StatusCode { get; set; }
|
||||
|
||||
public string StatusTitle { get; set; }
|
||||
|
||||
public int StatusTypeId { get; set; }
|
||||
|
||||
public string Reference { get; set; }
|
||||
|
||||
public int? ForeignKeyID { get; set; }
|
||||
|
||||
public bool IsCreditOnly { get; set; }
|
||||
|
||||
public bool IsClosed { get; set; }
|
||||
|
||||
public DateTime RecordCreated { get; set; }
|
||||
|
||||
public Status Build(Dictionary<int, StatusType> statusTypeDict)
|
||||
{
|
||||
if (!statusTypeDict.ContainsKey(StatusTypeId))
|
||||
{
|
||||
throw new InvalidOperationException($"Status type with ID {StatusTypeId} does not exist.");
|
||||
}
|
||||
return new Status(
|
||||
StatusId,
|
||||
StatusCode,
|
||||
StatusTitle,
|
||||
statusTypeDict[StatusTypeId],
|
||||
Reference,
|
||||
ForeignKeyID,
|
||||
IsCreditOnly,
|
||||
IsClosed,
|
||||
RecordCreated
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,10 +17,10 @@ namespace bnhtrade.Core.Model.Stock
|
||||
ReferenceType = referenceType;
|
||||
Account = account;
|
||||
}
|
||||
public int StockStatusTypeID { get; private set; }
|
||||
public string StatusTypeName { get; private set; }
|
||||
public string ForeignKeyType { get; private set; }
|
||||
public string ReferenceType { get; private set; }
|
||||
public Model.Account.Account Account { get; private set; }
|
||||
public int StockStatusTypeID { get; }
|
||||
public string StatusTypeName { get; }
|
||||
public string ForeignKeyType { get; }
|
||||
public string ReferenceType { get; }
|
||||
public Model.Account.Account Account { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bnhtrade.Core.Model.Stock
|
||||
{
|
||||
internal class StatusTypeBuilder
|
||||
{
|
||||
public int StockStatusTypeID { get; set; }
|
||||
public string StatusTypeName { get; set; }
|
||||
public string ForeignKeyType { get; set; }
|
||||
public string ReferenceType { get; set; }
|
||||
public int AccountId { get; set; }
|
||||
|
||||
public StatusType Build(Dictionary<int, Model.Account.Account> accountDict)
|
||||
{
|
||||
if (!accountDict.ContainsKey(AccountId))
|
||||
{
|
||||
throw new InvalidOperationException($"Account with ID {AccountId} does not exist.");
|
||||
}
|
||||
return new StatusType(
|
||||
StockStatusTypeID,
|
||||
StatusTypeName,
|
||||
ForeignKeyType,
|
||||
ReferenceType,
|
||||
accountDict[AccountId]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
using bnhtrade.Core.Logic.Validate;
|
||||
using bnhtrade.Core.Model.Account;
|
||||
using FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentInboundv20240320;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bnhtrade.Core.Model.Stock
|
||||
{
|
||||
public class StockJournal : IValidatableObject
|
||||
{
|
||||
public StockJournal(int stockJournalId, StockJournalType stockJournalType, int stockId, string stockNumber, DateTime entryDate, DateTime postDate, DateTime lastModified, bool isLocked, List<StockJournalPost> journalPosts)
|
||||
{
|
||||
StockJournalId = stockJournalId;
|
||||
StockJournalType = stockJournalType;
|
||||
StockId = stockId;
|
||||
StockNumber = stockNumber;
|
||||
EntryDate = entryDate;
|
||||
PostDate = postDate;
|
||||
LastModified = lastModified;
|
||||
IsLocked = isLocked;
|
||||
StockJournalPosts = journalPosts ?? throw new ArgumentNullException(nameof(journalPosts), "Journal posts cannot be null.");
|
||||
}
|
||||
|
||||
[Required()]
|
||||
[Range(1, int.MaxValue, ErrorMessage = "StockJournalId must be greater than 0.")]
|
||||
public int StockJournalId { get; }
|
||||
|
||||
public StockJournalType StockJournalType { get; }
|
||||
|
||||
[Required()]
|
||||
[Range(1, int.MaxValue, ErrorMessage = "StockId must be greater than 0.")]
|
||||
public int StockId { get; }
|
||||
|
||||
[Required(ErrorMessage = "Stock number is required.")]
|
||||
public string StockNumber { get; }
|
||||
|
||||
public DateTime EntryDate { get; }
|
||||
|
||||
public DateTime PostDate { get; }
|
||||
|
||||
public DateTime LastModified { get; }
|
||||
|
||||
public bool IsLocked { get; }
|
||||
|
||||
public List<StockJournalPost> StockJournalPosts { get; }
|
||||
|
||||
public class StockJournalPost : IValidatableObject
|
||||
{
|
||||
public StockJournalPost(int journalPostId, Status status, int quantity)
|
||||
{
|
||||
StockJournalPostId = journalPostId;
|
||||
Status = status;
|
||||
Quantity = quantity;
|
||||
}
|
||||
public int StockJournalPostId { get; }
|
||||
|
||||
[Required()]
|
||||
public Status Status { get; }
|
||||
|
||||
[Required()]
|
||||
public int Quantity { get; }
|
||||
|
||||
public bool IsCredit
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Quantity < 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (Quantity > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Quantity cannot be zero for a journal post.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDebit
|
||||
{
|
||||
get
|
||||
{
|
||||
return !IsCredit;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
var validationResults = new List<ValidationResult>();
|
||||
|
||||
if (Quantity == 0)
|
||||
{
|
||||
validationResults.Add(new ValidationResult("Quantity cannot be zero for a journal post.", new[] { nameof(Quantity) }));
|
||||
}
|
||||
|
||||
return validationResults;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
var validationResults = new List<ValidationResult>();
|
||||
|
||||
// dates are in UTC format
|
||||
if (EntryDate.Kind != DateTimeKind.Utc || EntryDate == default(DateTime))
|
||||
{
|
||||
validationResults.Add(new ValidationResult("Entry Date must be in UTC format and not a default value.", new[] { nameof(EntryDate) }));
|
||||
}
|
||||
if (PostDate.Kind != DateTimeKind.Utc || PostDate == default(DateTime))
|
||||
{
|
||||
validationResults.Add(new ValidationResult("PostDate must be in UTC format and not a default value.", new[] { nameof(PostDate) }));
|
||||
}
|
||||
if (LastModified.Kind != DateTimeKind.Utc || LastModified == default(DateTime))
|
||||
{
|
||||
validationResults.Add(new ValidationResult("LastModified must be in UTC format and not a default value.", new[] { nameof(LastModified) }));
|
||||
}
|
||||
|
||||
if (Format.StockNumber(StockNumber) == false)
|
||||
{
|
||||
validationResults.Add(new ValidationResult("StockNumber must be in the format 'STK#000000'.", new[] { nameof(StockNumber) }));
|
||||
}
|
||||
|
||||
// Validate each StockJournalPost using its own context and Validate method
|
||||
int sum = 0;
|
||||
for (int i = 0; i < StockJournalPosts.Count; i++)
|
||||
{
|
||||
sum += StockJournalPosts[i].Quantity;
|
||||
|
||||
var post = StockJournalPosts[i];
|
||||
var postContext = new ValidationContext(post, validationContext, validationContext.Items);
|
||||
foreach (var result in post.Validate(postContext))
|
||||
{
|
||||
// Prefix property name with the index for clarity
|
||||
var memberNames = result.MemberNames.Select(name => $"StockJournalPosts[{i}].{name}");
|
||||
validationResults.Add(new ValidationResult(result.ErrorMessage, memberNames));
|
||||
}
|
||||
}
|
||||
if (sum != 0)
|
||||
{
|
||||
validationResults.Add(new ValidationResult("The sum of all journal posts must equal zero.", new[] { nameof(StockJournalPosts) }));
|
||||
}
|
||||
|
||||
return validationResults;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static bnhtrade.Core.Data.Database.Constants;
|
||||
using static bnhtrade.Core.Model.Stock.StockJournal;
|
||||
|
||||
namespace bnhtrade.Core.Model.Stock
|
||||
{
|
||||
internal class StockJournalBuilder
|
||||
{
|
||||
public int StockJournalId { get; set; }
|
||||
|
||||
public int StockJournalTypeId { get; set; }
|
||||
|
||||
public int StockId { get; set; }
|
||||
|
||||
public string StockNumber { get; set; }
|
||||
|
||||
public DateTime EntryDate { get; set; }
|
||||
|
||||
public DateTime PostDate { get; set; }
|
||||
|
||||
public DateTime LastModified { get; set; }
|
||||
|
||||
public bool IsLocked { get; set; }
|
||||
|
||||
public bool AccountIsProcessed { get; set; }
|
||||
|
||||
public List<StockJournalBuilderPost> StockJournalBuilderPosts { get; set; }
|
||||
|
||||
public class StockJournalBuilderPost
|
||||
{
|
||||
public int StockJournalPostId { get; set; }
|
||||
|
||||
public int StatusId { get; set; }
|
||||
|
||||
public int Quantity { get; set; }
|
||||
|
||||
public bool IsCredit
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Quantity < 0)
|
||||
{
|
||||
return true; // Negative quantity indicates a credit post
|
||||
}
|
||||
else if (Quantity > 0)
|
||||
{
|
||||
return false; // Positive quantity indicates a debit post
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Quantity cannot be zero for a stock journal post.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDebit
|
||||
{
|
||||
get
|
||||
{
|
||||
return !IsCredit; // Debit is the opposite of credit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public StockJournal Build(Dictionary<int, StockJournalType> stockJournalTypeDict, Dictionary<int, Status> stockStatusDict)
|
||||
{
|
||||
if (StockJournalBuilderPosts == null || !StockJournalBuilderPosts.Any())
|
||||
{
|
||||
throw new InvalidOperationException("At least one journal post is required.");
|
||||
}
|
||||
|
||||
var posts = new List<StockJournalPost>();
|
||||
foreach (var builderPost in StockJournalBuilderPosts)
|
||||
{
|
||||
var post = new StockJournalPost(
|
||||
builderPost.StockJournalPostId,
|
||||
stockStatusDict[builderPost.StockJournalPostId],
|
||||
builderPost.Quantity
|
||||
);
|
||||
posts.Add(post);
|
||||
}
|
||||
|
||||
return new StockJournal(
|
||||
StockJournalId,
|
||||
stockJournalTypeDict[StockJournalTypeId],
|
||||
StockId,
|
||||
StockNumber,
|
||||
EntryDate,
|
||||
PostDate,
|
||||
LastModified,
|
||||
IsLocked,
|
||||
posts
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace bnhtrade.Core.Model.Stock
|
||||
{
|
||||
public class StockJournalType
|
||||
{
|
||||
public StockJournalType(int stockJournalTypeId, string stockJournalTypeTitle, Status defaultDebitStatus, Status defaultCreditStatus)
|
||||
{
|
||||
StockJournalTypeID = stockJournalTypeId;
|
||||
StockJournalTypeTitle = stockJournalTypeTitle ?? throw new ArgumentNullException(nameof(stockJournalTypeTitle), "Stock journal type title cannot be null.");
|
||||
DefaultDebitStatus = defaultDebitStatus;
|
||||
DefaultCreditStatus = defaultCreditStatus;
|
||||
}
|
||||
|
||||
public int StockJournalTypeID { get; }
|
||||
|
||||
public string StockJournalTypeTitle { get; }
|
||||
|
||||
public Status DefaultDebitStatus { get; }
|
||||
|
||||
public bool DefaultDebitStatusIsSet
|
||||
{
|
||||
get { return DefaultDebitStatus != null; }
|
||||
}
|
||||
|
||||
public Status DefaultCreditStatus { get; }
|
||||
|
||||
public bool DefaultCreditStatusIsSet
|
||||
{
|
||||
get { return DefaultCreditStatus != null; }
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1288
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms.Design;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
|
||||
<!--Added the line below to copy all dll from .nuget folder to build output folder-->
|
||||
<!--CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies-->
|
||||
</PropertyGroup>
|
||||
@@ -40,6 +38,7 @@
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.0.2" />
|
||||
<PackageReference Include="RestSharp" Version="112.1.0" />
|
||||
<PackageReference Include="RestSharp.Serializers.NewtonsoftJson" Version="112.1.0" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.4" />
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.9.0" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
</ItemGroup>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user