Bug fix in ExportSalesInvoice and converted more code over to repository and service pattern

This commit is contained in:
2025-07-07 15:22:21 +01:00
parent 5900a6e6e4
commit 5cd653d700
64 changed files with 2623 additions and 2517 deletions

View File

@@ -1,44 +0,0 @@
using System;
using System.Collections.Generic;
//using System.Data.SqlClient;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database.Account
{
public class CreateInvoiceLineItem : Connection
{
public CreateInvoiceLineItem()
{
}
public int CreateDefault(string itemCode)
{
using (var conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(@"
INSERT INTO tblAccountInvoiceLineItem ( ItemName, ItemCode )
OUTPUT INSERTED.AccountInvoiceLineItemID
VALUES ( @itemName, @itemCode )
", conn))
{
cmd.Parameters.AddWithValue("@itemName", itemCode);
cmd.Parameters.AddWithValue("@itemCode", itemCode);
object obj = cmd.ExecuteScalar();
if (obj == null || obj == DBNull.Value)
{
throw new Exception("Error inserting new defalt invoice line item into database");
}
return (int)obj;
}
}
}
}
}

View File

@@ -1,64 +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 DeleteJournal : Connection
{
/// <summary>
/// Old code needs sorting
/// </summary>
public bool AccountJournalDelete(int accountJournalId)
{
// check if journal entry is locked
using (TransactionScope scope = new TransactionScope())
{
bool IsLocked = new Data.Database.Account.ReadJournal().EntryIsLocked(accountJournalId);
if (IsLocked == true)
{
return false;
}
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
// make the delete
using (SqlCommand cmd = new SqlCommand(@"
DELETE FROM tblAccountJournalPost
WHERE AccountJournalID=@accountJournalId;
", conn))
{
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 = new SqlCommand(@"
DELETE FROM tblAccountJournal
WHERE AccountJournalID=@accountJournalId;
", conn))
{
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
cmd.ExecuteNonQuery();
}
scope.Complete();
return true;
}
}
}
}
}

View File

@@ -1,126 +0,0 @@
using System;
using System.Collections.Generic;
using Microsoft.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database.Account
{
public class ReadAccountCode : Connection
{
private Data.Database.SqlWhereBuilder sqlWhere = new SqlWhereBuilder();
public ReadAccountCode()
{
}
/// <summary>
/// Gets the full chart of accounts
/// </summary>
/// <returns>Dictionary where the database record id is the key</returns>
public Dictionary<uint, Model.Account.Account> All()
{
Innit();
var list = Execute(null, null);
var dictionary = new Dictionary<uint, Model.Account.Account>();
foreach (var item in list)
{
dictionary.Add(item.Value.Id, item.Value);
}
return dictionary;
}
public Dictionary<uint, Model.Account.Account> ByAccountId(List<uint> accountIdList)
{
Innit();
var resultDict = new Dictionary<uint, Model.Account.Account>();
if (accountIdList == null || !accountIdList.Any())
{
return resultDict;
}
sqlWhere.In("tblAccountChartOf.AccountChartOfID", accountIdList, " WHERE ");
resultDict = Execute(sqlWhere.SqlWhereString, sqlWhere.ParameterList);
return resultDict;
}
public Dictionary<uint, Model.Account.Account> ByAccountCode(List<int> accountCodeList)
{
Innit();
var resultDict = new Dictionary<uint, Model.Account.Account>();
if (accountCodeList == null || !accountCodeList.Any())
{
return resultDict;
}
sqlWhere.In("tblAccountChartOf.AccountCode", accountCodeList, " WHERE ");
resultDict = Execute(sqlWhere.SqlWhereString, sqlWhere.ParameterList);
return resultDict;
}
private Dictionary<uint, Model.Account.Account> Execute(string sqlWhere, Dictionary<string, object> parameters)
{
var resultDict = new Dictionary<uint, Model.Account.Account>();
//build sql query
string sqlString = @"
SELECT tblAccountChartOf.AccountChartOfID
,tblAccountChartOf.AccountCode
,tblAccountChartOf.AccountName
,tblAccountChartOf.Description
,tblAccountChartOfType.AccountChartOfType
,tblAccountChartOfType.BasicType
,tblAccountChartOfType.Multiplier
FROM tblAccountChartOf
INNER JOIN tblAccountChartOfType ON tblAccountChartOf.AccountChartOfTypeID = tblAccountChartOfType.AccountChartOfTypeID
" + sqlWhere;
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sqlString, conn))
{
if (parameters != null)
{
foreach (var parameter in parameters)
{
cmd.Parameters.AddWithValue(parameter.Key, parameter.Value);
}
}
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
uint tablePk = (uint)reader.GetInt32(0);
uint accountCode = (uint)reader.GetInt32(1);
string title = reader.GetString(2);
string description = null;
if (!reader.IsDBNull(3)) { description = reader.GetString(3); }
string type = reader.GetString(4);
string basicType = reader.GetString(5);
int multiplier = reader.GetInt32(6);
var result = new Model.Account.Account(tablePk, accountCode, title, description, type, basicType, multiplier);
resultDict.Add(tablePk, result);
}
}
}
}
}
return resultDict;
}
private void Innit()
{
sqlWhere.Init();
}
}
}

View File

@@ -1,123 +0,0 @@
using System;
using System.Collections.Generic;
using Microsoft.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace bnhtrade.Core.Data.Database.Account
{
internal class ReadInvoiceLineItem : Connection
{
public ReadInvoiceLineItem()
{
}
/// <summary>
/// Reads all invoice line items from the database.
/// </summary>
/// <returns>dictionary where key=id, value=object</returns>
internal Dictionary<int, Model.Account.InvoiceLineItem> All()
{
return Execute();
}
/// <summary>
/// Read list of invoice line items by item code.
/// </summary>
/// <param name="itemCodes">List of item coeds to query db against</param>
/// <returns>dictionary where key=id, value=object</returns>
/// <exception cref="ArgumentException"></exception>
internal Dictionary<int, Model.Account.InvoiceLineItem> ByItemCode(List<string> itemCodes)
{
if (itemCodes == null || !itemCodes.Any())
{
throw new ArgumentException("Item codes list cannot be null or empty.");
}
var sqlwhere = new SqlWhereBuilder();
sqlwhere.In("ItemCode", itemCodes, "AND");
return Execute(sqlwhere);
}
private Dictionary<int, Model.Account.InvoiceLineItem> Execute(SqlWhereBuilder sqlwhere = null)
{
var resultList = new Dictionary<int, Model.Account.InvoiceLineItem>();
var accountCodeIdList = new Dictionary<int, uint>(); // key=LineItemID, value=AccountChartOfID
var taxCodeIdList = new Dictionary<int, int>(); // key=LineItemID, value=AccountTaxCodeID
string sql = @"
SELECT [AccountInvoiceLineItemID]
,[ItemName]
,[ItemCode]
,[ItemDescription]
,[IsNewReviewRequired]
,[InvoiceLineEntryEnable]
,[AccountChartOfID_Default]
,[AccountTaxCodeID_Default]
FROM [e2A].[dbo].[tblAccountInvoiceLineItem]
WHERE 1=1 ";
if (sqlwhere != null)
{
sql += sqlwhere.SqlWhereString;
}
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
if (sqlwhere != null)
{
sqlwhere.AddParametersToSqlCommand(cmd);
}
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var lineItem = new Model.Account.InvoiceLineItem();
int lineItemId = reader.GetInt32(0);
lineItem.Name = reader.GetString(1);
lineItem.ItemCode = reader.GetString(2);
if (!reader.IsDBNull(3)) { lineItem.Description = reader.GetString(3); }
lineItem.IsNewReviewRequired = reader.GetBoolean(4);
lineItem.InvoiceLineEntryEnabled = reader.GetBoolean(5);
if (!reader.IsDBNull(6))
{
accountCodeIdList.Add(lineItemId, (uint)reader.GetInt32(6));
}
if (!reader.IsDBNull(7))
{
taxCodeIdList.Add(lineItemId, reader.GetInt32(7));
}
resultList.Add(lineItemId, lineItem);
}
}
}
// get account codes and add to result list
var accountCodeDictionary = new Data.Database.Account.ReadAccountCode().ByAccountId(accountCodeIdList.Values.ToList());
foreach (var accountCode in accountCodeIdList)
{
resultList[accountCode.Key].DefaultAccountCode = accountCodeDictionary[accountCode.Value];
}
// get tax codes
var taxCodeDictionary = new Data.Database.Account.ReadTaxCode().GetByTaxCodeId(taxCodeIdList.Values.ToList());
foreach (var taxCode in taxCodeIdList)
{
resultList[taxCode.Key].DefaultTaxCode = taxCodeDictionary[taxCode.Value];
}
return resultList;
}
}
}
}

View File

@@ -1,242 +0,0 @@
using FikaAmazonAPI.AmazonSpApiSDK.Models.CatalogItems;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Runtime.InteropServices.Marshalling;
using System.Text;
using System.Threading.Tasks;
using static System.ComponentModel.Design.ObjectSelectorEditor;
namespace bnhtrade.Core.Data.Database.Account
{
internal class ReadJournal : Connection
{
private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder;
/// <summary>
/// Filter the read results
/// </summary>
public List<uint> AccountJournalId { get; set; }
public ReadJournal()
{
Init();
}
public void Init()
{
sqlBuilder = new SqlWhereBuilder();
AccountJournalId = new List<uint>();
}
/// <summary>
///
/// </summary>
/// <returns>Dictionary were key is the table primary key</returns>
public Dictionary<uint, Core.Model.Account.Journal> Read()
{
sqlBuilder.Init();
//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 (AccountJournalId.Any())
{
sqlBuilder.In("tblAccountJournal.AccountJournalID", AccountJournalId, "AND");
}
// append where string to the sql
if (sqlBuilder.IsSetSqlWhereString)
{
sql = sql + sqlBuilder.SqlWhereString;
}
// build tuple list
var dbJournalList = new List<(
uint AccountJournalId
, uint AccountJournalTypeId
, DateTime EntryDate
, DateTime PostDate
, DateTime LastModified
, bool IsLocked
)>();
var dbJournalPostList = new List<(
uint AccountJournalId
, uint AccountJournalPostId
, uint AccountChartOfId
, decimal AmountGbp
)>();
bool hasRows = false;
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
sqlBuilder.AddParametersToSqlCommand(cmd);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
hasRows = true;
uint lastJournalId = 0;
while (reader.Read())
{
// read journal header
uint journalId = (uint)reader.GetInt32(0);
if (journalId != lastJournalId)
{
lastJournalId = journalId;
(uint AccountJournalId
, uint AccountJournalTypeId
, DateTime EntryDate
, DateTime PostDate
, DateTime LastModified
, bool IsLocked
)
journal =
( journalId
, (uint)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
(uint AccountJournalId
, uint AccountJournalPostId
, uint AccountChartOfId
, decimal AmountGbp
)
journalPost =
( journalId
, (uint)reader.GetInt32(6)
, (uint)reader.GetInt32(7)
, reader.GetDecimal(8)
);
dbJournalPostList.Add(journalPost);
}
}
}
}
}
var returnList = new Dictionary<uint, Core.Model.Account.Journal>();
if (hasRows)
{
// build lists to filter db results by
var journalTypeIdList = new List<uint>();
var accountIdList = new List<uint>();
foreach (var item in dbJournalList)
{
journalTypeIdList.Add(item.AccountJournalTypeId);
}
foreach (var item in dbJournalPostList)
{
accountIdList.Add(item.AccountChartOfId);
}
// get journalTypes from db
var dbJournalType = new Data.Database.Account.ReadJournalType();
dbJournalType.IdList = journalTypeIdList;
var journalTypeDict = dbJournalType.Read();
// get accounts from db
var dbAccount = new Data.Database.Account.ReadAccountCode();
var accountDict = dbAccount.ByAccountId(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 EntryIsLocked(int journalId)
{
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(@"
SELECT
tblAccountJournal.IsLocked
FROM
tblAccountJournal
WHERE
tblAccountJournal.AccountJournalID=@accountJournalId;
", conn))
{
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;
}
}
}
}
}
}

View File

@@ -1,144 +0,0 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database.Account
{
internal class ReadJournalType : Connection
{
private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder;
/// <summary>
/// Results filter
/// </summary>
public List<uint> IdList { get; set; }
/// <summary>
/// Searches for the specificed phases within the item description. Uses the LIKE AND sql function
/// </summary>
public List<string> TitleList { get; set; }
public ReadJournalType()
{
Init();
}
public void Init()
{
sqlBuilder = new SqlWhereBuilder();
IdList = new List<uint>();
TitleList = new List<string>();
}
/// <summary>
///
/// </summary>
/// <returns>Dictionary where key is the table primary key</returns>
public Dictionary<uint, Model.Account.JournalType> Read()
{
// create the return (emptyP list) here
var returnList = new Dictionary<uint, 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 (IdList.Any())
{
sqlBuilder.In("AccountJournalTypeID", IdList, "AND");
}
if (TitleList.Any())
{
sqlBuilder.In("TypeTitle", TitleList, "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<uint, uint>();
var debitDict = new Dictionary<uint, uint>();
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
sqlBuilder.AddParametersToSqlCommand(cmd);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
// read from db and create object
uint journalTypeId = (uint)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, (uint)debitAccountId);
}
if (creditAccountId != null)
{
creditDict.Add(journalTypeId, (uint)creditAccountId);
}
}
}
}
}
}
// get account objects from db
var accountIdList = debitDict.Values.ToList();
accountIdList.AddRange(creditDict.Values.ToList());
var dbaccount = new Data.Database.Account.ReadAccountCode();
var dbDict = dbaccount.ByAccountId(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;
}
}
}

View File

@@ -1,178 +0,0 @@
using System;
using System.Collections.Generic;
using Microsoft.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.ComponentModel.Design.ObjectSelectorEditor;
namespace bnhtrade.Core.Data.Database.Account
{
internal class ReadPurchaseInvoice : Connection
{
private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder;
public IEnumerable<int> PurchaseInvoiceIdList { get; set; }
public ReadPurchaseInvoice()
{
Init();
}
public void Init()
{
sqlBuilder = new SqlWhereBuilder();
PurchaseInvoiceIdList = new List<int>();
}
public Dictionary<int, Model.Account.PurchaseInvoice> Read()
{
var returnList = new Dictionary<int, Model.Account.PurchaseInvoice>();
sqlBuilder.Init();
//build sql query
string sql = @"
SELECT tblPurchase.PurchaseID
,tblPurchase.PurchaseNumber
,tblPurchase.RecordID
,tblPurchase.PurchaseDate
,tblPurchase.ContactID
,tblPurchase.SupplierRef
,tblPurchase.PurchaseTotalAmount
,tblPurchase.VatInclusiveAmounts
,tblPurchase.RecordCreated
,tblPurchase.RecordModified
,tblPurchase.IsActive
,tblAccountCurrency.CurrencyCode
,tblPurchaseChannel.PurchaseChannelName
,tblPurchaseStatus.PurchaseStatus
FROM tblPurchase
LEFT OUTER JOIN tblAccountCurrency ON tblPurchase.AccountCurrencyID = tblAccountCurrency.AccountCurrencyID
LEFT OUTER JOIN tblPurchaseStatus ON tblPurchase.PurchaseStatusID = tblPurchaseStatus.PurchaseStatusID
LEFT OUTER JOIN tblPurchaseChannel ON tblPurchase.PurchaseChannelID = tblPurchaseChannel.PurchaseChannelID
WHERE 1 = 1
";
// build the where statments
if (PurchaseInvoiceIdList.Any())
{
sqlBuilder.In("[PurchaseID]", PurchaseInvoiceIdList, "AND");
}
// append where string to the sql
if (sqlBuilder.IsSetSqlWhereString)
{
sql = sql + sqlBuilder.SqlWhereString;
}
// dictionary so we can fill in details afterwards
var invoiceContactDict = new Dictionary<int, int>();
var purchaseIdList = new List<int>();
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
sqlBuilder.AddParametersToSqlCommand(cmd);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
int purchaseID = reader.GetInt32(0);
int purchaseNumber = reader.GetInt32(1);
int? recordID = null;
if (!reader.IsDBNull(2)) { recordID = reader.GetInt32(2); }
DateTime purchaseDate = DateTime.SpecifyKind(reader.GetDateTime(3), DateTimeKind.Utc);
int? contactID = null;
if (!reader.IsDBNull(4)) { contactID = reader.GetInt32(4);}
string supplierRef = null;
if (!reader.IsDBNull(5)) { supplierRef = reader.GetString(5);}
decimal? purchaseTotalAmount = null;
if (!reader.IsDBNull(6)) { purchaseTotalAmount = reader.GetDecimal(6);}
bool vatInclusiveAmounts = reader.GetBoolean(7);
DateTime recordCreated = DateTime.SpecifyKind(reader.GetDateTime(8), DateTimeKind.Utc);
DateTime recordModified = DateTime.SpecifyKind(reader.GetDateTime(9), DateTimeKind.Utc);
bool isActive = reader.GetBoolean(10);
string currencyCode = reader.GetString(11);
string purchaseChannelName = reader.GetString(12);
string purchaseStatus = null;
if (!reader.IsDBNull(13)) { purchaseStatus = reader.GetString(13);}
var invoice = new Model.Account.PurchaseInvoice();
invoice.PurchaseID = purchaseID;
invoice.PurchaseNumber = purchaseNumber;
invoice.RecordID = recordID;
invoice.PurchaseDate = purchaseDate;
invoice.SupplierRef = supplierRef;
//invoice.PurchaseTotalAmount = purchaseTotalAmount;
invoice.VatInclusiveAmounts = vatInclusiveAmounts;
invoice.RecordCreated = recordCreated;
invoice.RecordModified = recordModified;
invoice.IsActive = isActive;
invoice.CurrencyCode = currencyCode;
invoice.PurchaseChannel = purchaseChannelName;
// is there contact info that needs to be added?
if (contactID != null)
{
invoiceContactDict.Add(purchaseID, (int)contactID);
}
purchaseIdList.Add(purchaseID);
returnList.Add(purchaseID, invoice);
}
}
}
}
}
// add contact info
if (invoiceContactDict.Any())
{
var readContact = new Data.Database.Account.ReadContact();
readContact.ContactIdList = invoiceContactDict.Values.ToList();
var contactDict = readContact.Read();
if (contactDict.Any())
{
foreach ( var invoice in returnList)
{
if (invoiceContactDict.ContainsKey(invoice.Value.PurchaseID))
{
int contactId = invoiceContactDict[invoice.Value.PurchaseID];
invoice.Value.Contact = contactDict[contactId];
}
}
}
}
// add invoice lines
var readLines = new Data.Database.Account.ReadPurchaseInvoiceLine();
readLines.InvoiceIdList = purchaseIdList;
var lines = readLines.Read();
foreach(var invoice in returnList.Values)
{
foreach(var line in lines.Values)
{
if (line.PurchaseId == invoice.PurchaseID)
{
if (invoice.InvoiceLines == null)
{
invoice.InvoiceLines = new List<Model.Account.PurchaseInvoice.Line>();
}
invoice.InvoiceLines.Add(line);
}
}
}
return returnList;
}
}
}

View File

@@ -1,212 +0,0 @@
using Amazon.Runtime.Internal.Transform;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.ComponentModel.Design.ObjectSelectorEditor;
namespace bnhtrade.Core.Data.Database.Account
{
internal class ReadPurchaseInvoiceLine : Connection
{
private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder;
/// <summary>
/// Results filter
/// </summary>
public List<int> InvoiceIdList { get; set; }
/// <summary>
/// Results filter
/// </summary>
public List<int> InvoiceLineIdList { get; set; }
/// <summary>
/// Results filter
/// </summary>
public List<string> StatusList { get; set; }
/// <summary>
/// Searches for the specificed phases within the item description. Uses the LIKE AND sql function
/// </summary>
public List<string> ItemDescription { get; set; }
public ReadPurchaseInvoiceLine()
{
Init();
}
public void Init()
{
sqlBuilder = new SqlWhereBuilder();
InvoiceIdList = new List<int>();
InvoiceLineIdList = new List<int>();
StatusList = new List<string>();
ItemDescription = new List<string>();
}
public Dictionary<int, Model.Account.PurchaseInvoice.Line> Read()
{
var returnList = new Dictionary<int, Model.Account.PurchaseInvoice.Line>();
sqlBuilder.Init();
//build sql query
string sql = @"
SELECT tblPurchaseLine.PurchaseLineID
,tblPurchaseLine.PurchaseID
,tblPurchaseLineStatus.PurchaseLineStatus
,tblPurchaseLine.SupplierRef
,tblPurchaseLine.CheckedIn
,tblPurchaseLine.ItemDescription
,tblPurchaseLine.ItemQuantity
,tblPurchaseLine.ItemGross
,tblPurchaseLine.ItemTax
,tblPurchaseLine.ShippingGross
,tblPurchaseLine.ShippingTax
,tblPurchaseLine.OtherGross
,tblPurchaseLine.OtherTax
,tblPurchaseLine.AccountTaxCodeID
,tblPurchaseLine.Tax_AccountTransactionID
,tblPurchaseLine.Net_AccountChartOfID
,tblPurchaseLine.Net_AccountTransactionID
,tblPurchaseLine.RecordCreated
,tblPurchaseLine.RecordModified
,tblPurchaseLine.IsActive
,tblAccountTaxCode.TaxCode
FROM tblPurchaseLine
INNER JOIN tblPurchaseLineStatus ON tblPurchaseLine.PurchaseLineStatusID = tblPurchaseLineStatus.PurchaseLineStatusID
LEFT OUTER JOIN tblAccountTaxCode ON tblPurchaseLine.AccountTaxCodeID = tblAccountTaxCode.AccountTaxCodeID
WHERE 1 = 1 ";
// build the where statments
if (InvoiceIdList.Any())
{
sqlBuilder.In("PurchaseID", InvoiceLineIdList, "AND");
}
if (InvoiceLineIdList.Any())
{
sqlBuilder.In("PurchaseLineID", InvoiceLineIdList, "AND");
}
if (StatusList.Any())
{
sqlBuilder.In("PurchaseLineStatus", InvoiceLineIdList, "AND");
}
if (ItemDescription.Any())
{
sqlBuilder.LikeAnd("ItemDescription", ItemDescription, "AND");
}
// append where string to the sql
if (sqlBuilder.IsSetSqlWhereString)
{
sql = sql + sqlBuilder.SqlWhereString;
}
// catch taxcode to add in after db read
var lineTaxCodeDict = new Dictionary<int, string>();
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
sqlBuilder.AddParametersToSqlCommand(cmd);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
int purchaseLineID = reader.GetInt32(0);
int purchaseID = reader.GetInt32(1);
string purchaseLineStatus = reader.GetString(2);
string supplierRef = null;
if (!reader.IsDBNull(3)) { supplierRef = reader.GetString(3); }
DateTime? checkedIn = null;
if (!reader.IsDBNull(4)) { checkedIn = DateTime.SpecifyKind(reader.GetDateTime(4), DateTimeKind.Utc); }
string itemDescription = null;
if (!reader.IsDBNull(5)) { itemDescription = reader.GetString(5); }
int itemQuantity = reader.GetInt32(6);
decimal itemGross = 0;
if (!reader.IsDBNull(7)) { itemGross = reader.GetDecimal(7); }
decimal itemTax = 0;
if (!reader.IsDBNull(8)) { itemTax = reader.GetDecimal(8); }
decimal shippingGross = 0;
if (!reader.IsDBNull(9)) { shippingGross = reader.GetDecimal(9); }
decimal shippingTax = 0;
if (!reader.IsDBNull(10)) { shippingTax = reader.GetDecimal(10); }
decimal otherGross = 0;
if (!reader.IsDBNull(11)) { otherGross = reader.GetDecimal(11); }
decimal otherTax = 0;
if (!reader.IsDBNull(12)) { otherTax = reader.GetDecimal(12); }
int accountTaxCodeID = reader.GetInt32(13);
int? tax_AccountTransactionID = null;
if (!reader.IsDBNull(14)) { tax_AccountTransactionID = reader.GetInt32(14); }
int net_AccountChartOfID = reader.GetInt32(15);
int? net_AccountTransactionID = null;
if (!reader.IsDBNull(16)) { net_AccountTransactionID = reader.GetInt32(16); }
DateTime recordModified;
DateTime recordCreated = DateTime.SpecifyKind(reader.GetDateTime(17), DateTimeKind.Utc);
if (reader.IsDBNull(18)) { recordModified = recordCreated; }
else { recordModified = DateTime.SpecifyKind(reader.GetDateTime(18), DateTimeKind.Utc); }
bool isActive = reader.GetBoolean(19);
string accountTaxCode = reader.GetString(20);
var line = new Model.Account.PurchaseInvoice.Line();
line.PurchaseLineId = purchaseLineID;
line.PurchaseId = purchaseID;
line.Status = purchaseLineStatus;
line.SupplierRef = supplierRef;
line.CheckedIn = checkedIn;
line.ItemDescription = itemDescription;
line.ItemQuantity = itemQuantity;
line.ItemGross = itemGross;
line.ItemTax = itemTax;
line.ShippingGross = shippingGross;
line.ShippingTax = shippingTax;
line.OtherGross = otherGross;
line.OtherTax = otherTax;
line.Tax_AccountTransactionId = tax_AccountTransactionID;
line.Net_AccountChartOfId = net_AccountChartOfID;
line.Net_AccountTransactionId = net_AccountTransactionID;
line.RecordModified = recordModified;
line.RecordCreated = recordCreated;
line.IsActive = isActive;
returnList.Add(purchaseLineID, line);
lineTaxCodeDict.Add(purchaseLineID, accountTaxCode);
}
}
}
}
}
// read tax codes form db and add to return object
var taxcodeList = new Data.Database.Account.ReadTaxCode().GetByTaxCode(lineTaxCodeDict.Values.ToList());
foreach (var line in returnList.Values)
{
foreach(var taxcode in taxcodeList)
{
if (taxcode.TaxCode == lineTaxCodeDict[line.PurchaseLineId])
{
line.AccountTaxCode = taxcode;
break;
}
}
if (line.AccountTaxCode == null)
{
throw new Exception("Fail safe, this really shouodn't happen");
}
}
// all done
return returnList;
}
}
}

View File

@@ -1,54 +0,0 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database.Account
{
internal class ReadPurchaseInvoiceLineStatus : Connection
{
public Dictionary<int, Model.Account.PurchaseInvoiceLineStatus> Read()
{
var returnList = new Dictionary<int, Model.Account.PurchaseInvoiceLineStatus>();
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(@"
SELECT [PurchaseLineStatusID]
,[PurchaseLineStatus]
,[ListSort]
,[TimeStamp]
FROM [e2A].[dbo].[tblPurchaseLineStatus]
ORDER BY [ListSort]
", conn))
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (!reader.HasRows)
{
// do something
}
else
{
while (reader.Read())
{
int id = reader.GetInt32(0);
string name = reader.GetString(1);
int lineSort = reader.GetInt32(2);
var returnItem = new Model.Account.PurchaseInvoiceLineStatus(id, name,lineSort);
returnList.Add(id, returnItem );
}
}
}
}
}
return returnList;
}
}
}

View File

@@ -1,91 +0,0 @@
using FikaAmazonAPI.AmazonSpApiSDK.Models.ProductFees;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.ComponentModel.Design.ObjectSelectorEditor;
namespace bnhtrade.Core.Data.Database.Account
{
internal class ReadPurchaseInvoiceLineSummary : Connection
{
public List<Model.Account.PurchaseInvoiceLineSummary> Read(DateTime periodTo, string lineStatus, List<string> descriptionSearch)
{
var returnList = new List<Model.Account.PurchaseInvoiceLineSummary>();
var sqlBuilder = new bnhtrade.Core.Data.Database.SqlWhereBuilder();
//build sql query
string sql = @"
SELECT tblPurchase.PurchaseDate
,tblPurchase.PurchaseID
,tblPurchase.PurchaseNumber
,tblPurchaseLine.PurchaseLineID
,tblPurchaseLine.ItemDescription
,tblPurchaseLineStatus.PurchaseLineStatus
FROM tblPurchase
INNER JOIN tblPurchaseLine ON tblPurchase.PurchaseID = tblPurchaseLine.PurchaseID
INNER JOIN tblPurchaseLineStatus ON tblPurchaseLine.PurchaseLineStatusID = tblPurchaseLineStatus.PurchaseLineStatusID
WHERE tblPurchase.PurchaseDate <= @purchaseDate
";
if (lineStatus != null)
{
sql = sql + " AND PurchaseLineStatus = @purchaseLineStatus ";
}
// build the where statments
if (descriptionSearch.Any())
{
sqlBuilder.LikeAnd("ItemDescription", descriptionSearch, "AND");
}
// append where string to the sql
if (sqlBuilder.IsSetSqlWhereString)
{
sql = sql + sqlBuilder.SqlWhereString;
}
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("@purchaseDate", periodTo);
if (lineStatus != null)
{
cmd.Parameters.AddWithValue("@purchaseLineStatus", lineStatus);
}
sqlBuilder.AddParametersToSqlCommand(cmd);
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
DateTime purchaseDate = DateTime.SpecifyKind(reader.GetDateTime(0), DateTimeKind.Utc);
int purchaseID = reader.GetInt32(1);
int purchaseNumber = reader.GetInt32(2);
int purchaseLineID = reader.GetInt32(3);
string itemDescription = reader.GetString(4);
string purchaseLineStatus = reader.GetString(5);
var item = new Model.Account.PurchaseInvoiceLineSummary();
item.PurchaseDate = purchaseDate;
item.PurchaseId = purchaseID;
item.PurchaseNumber = purchaseNumber;
item.PurchaseLineId = purchaseLineID;
item.ItemDescription = itemDescription;
item.LineStatus = purchaseLineStatus;
returnList.Add(item);
}
}
}
}
return returnList;
}
}
}

View File

@@ -1,242 +0,0 @@
using System;
using System.Collections.Generic;
using Microsoft.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database.Account
{
internal class ReadTaxCode : Connection
{
private Data.Database.SqlWhereBuilder whereBuilder = new SqlWhereBuilder();
public ReadTaxCode()
{
}
private Dictionary<int, Model.Account.TaxCodeInfo> Execute(string sqlWhere, Dictionary<string, object> parameters)
{
var resultList = new Dictionary<int, Model.Account.TaxCodeInfo>();
//build sql query
string sqlString = @"
SELECT
AccountTaxCodeID
,TaxCode
,TaxCodeName
,TaxCodeDescription
,TaxRatePercent
,IsMarginScheme
,IsValidOnExpense
,IsVailidOnIncome
,IsActive
,TaxType
FROM tblAccountTaxCode";
sqlString += sqlWhere;
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sqlString, conn))
{
foreach (var paramter in parameters)
{
cmd.Parameters.AddWithValue(paramter.Key, paramter.Value);
}
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
int taxCodeId = reader.GetByte(0);
string taxCode = reader.GetString(1);
string name = reader.GetString(2);
string description = null;
if (!reader.IsDBNull(3)) { description = reader.GetString(3); }
decimal rate = reader.GetDecimal(4);
bool isMargin = reader.GetBoolean(5);
bool isValidOnExpense = reader.GetBoolean(6);
bool isValidOnIncome = reader.GetBoolean(7);
bool isActive = reader.GetBoolean(8);
string taxType = reader.GetString(9);
var result = new Model.Account.TaxCodeInfo(
taxCode,
name,
description,
rate,
isMargin,
isValidOnExpense,
isValidOnIncome,
taxType,
isActive);
resultList.Add(taxCodeId, result);
}
}
}
}
}
return resultList;
}
public List<Model.Account.TaxCodeInfo> GetByTaxCode(List<string> taxcodeList)
{
var resultList = new List<Model.Account.TaxCodeInfo>();
if (taxcodeList == null || !taxcodeList.Any())
{
return resultList;
}
taxcodeList = taxcodeList.Distinct().ToList();
whereBuilder.Init();
whereBuilder.In("TaxCode", taxcodeList, "WHERE");
var dic = Execute(whereBuilder.SqlWhereString, whereBuilder.ParameterList);
return dic.Values.ToList();
}
public Dictionary<int, Model.Account.TaxCodeInfo> GetByTaxCodeId(List<int> taxcodeIdList)
{
var resultList = new Dictionary<int, Model.Account.TaxCodeInfo>();
if (taxcodeIdList == null || !taxcodeIdList.Any())
{
return resultList;
}
taxcodeIdList = taxcodeIdList.Distinct().ToList();
whereBuilder.Init();
whereBuilder.In("AccountTaxCodeID", taxcodeIdList, "WHERE");
return Execute(whereBuilder.SqlWhereString, whereBuilder.ParameterList);
}
/// <summary>
/// Gets all active Tax Code objects
/// </summary>
/// <returns>Dictionary where database record ID is the key</returns>
public Dictionary<int, Model.Account.TaxCodeInfo> GetAllActive()
{
string sqlWhere = @"
WHERE IsActive=@isActive;";
var parameters = new Dictionary<string, object>();
parameters.Add("@isActive", true);
return Execute(sqlWhere, parameters);
}
public Dictionary<string, string> GetTaxCodeBySkuNumber(List<string> skuNumberList)
{
var resultList = new Dictionary<string, string>();
if (skuNumberList == null || !skuNumberList.Any())
{
return resultList;
}
skuNumberList = skuNumberList.Distinct().ToList();
string sql = @"
SELECT tblSku.skuSkuNumber
,tblAccountTaxCode.TaxCode
FROM tblSku
INNER JOIN tblAccountTaxCode ON tblSku.AccountTaxCodeID = tblAccountTaxCode.AccountTaxCodeID ";
whereBuilder.Init();
whereBuilder.In("tblSku.skuSkuNumber", skuNumberList, "WHERE");
sql += whereBuilder.SqlWhereString;
using (var conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (var cmd = new SqlCommand(sql, conn))
{
foreach (var param in whereBuilder.ParameterList)
{
cmd.Parameters.AddWithValue(param.Key, param.Value);
}
using (var reader = cmd.ExecuteReader())
{
if (!reader.HasRows)
{
return resultList;
}
while (reader.Read())
{
resultList.Add(reader.GetString(0), reader.GetString(1));
}
}
}
}
return resultList;
}
public Dictionary<string, string> GetTaxCodeByInvoiceLineItemCode(List<string> lineItemCode)
{
var resultList = new Dictionary<string, string>();
if (lineItemCode == null || !lineItemCode.Any())
{
return resultList;
}
lineItemCode = lineItemCode.Distinct().ToList();
string sql = @"
SELECT tblAccountInvoiceLineItem.ItemCode
,tblAccountTaxCode.TaxCode
FROM tblAccountInvoiceLineItem
LEFT OUTER JOIN tblAccountTaxCode ON tblAccountInvoiceLineItem.AccountTaxCodeID_Default = tblAccountTaxCode.AccountTaxCodeID
";
whereBuilder.Init();
whereBuilder.In("tblAccountInvoiceLineItem.ItemCode", lineItemCode, "WHERE");
sql += whereBuilder.SqlWhereString;
using (var conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (var cmd = new SqlCommand(sql, conn))
{
foreach (var param in whereBuilder.ParameterList)
{
cmd.Parameters.AddWithValue(param.Key, param.Value);
}
using (var reader = cmd.ExecuteReader())
{
if (!reader.HasRows)
{
return resultList;
}
while (reader.Read())
{
if (reader.IsDBNull(1)) { resultList.Add(reader.GetString(0), null); }
else { resultList.Add(reader.GetString(0), reader.GetString(1)); }
}
}
}
}
return resultList;
}
}
}

View File

@@ -0,0 +1,82 @@
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 AccountCodeRepository : _Base, IAccountCodeRepository
{
public AccountCodeRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
{
}
public Dictionary<int, Model.Account.Account> ReadAccountCode(List<int> accountIdList = null, List<int> accountCodeList = null)
{
var resultDict = new Dictionary<int, Model.Account.Account>();
var sqlWhere = new SqlWhereBuilder();
//build sql query
string sqlString = @"
SELECT tblAccountChartOf.AccountChartOfID
,tblAccountChartOf.AccountCode
,tblAccountChartOf.AccountName
,tblAccountChartOf.Description
,tblAccountChartOfType.AccountChartOfType
,tblAccountChartOfType.BasicType
,tblAccountChartOfType.Multiplier
FROM tblAccountChartOf
INNER JOIN tblAccountChartOfType ON tblAccountChartOf.AccountChartOfTypeID = tblAccountChartOfType.AccountChartOfTypeID
WHERE 1=1 ";
if (accountIdList != null && accountIdList.Any())
{
sqlWhere.In("tblAccountChartOf.AccountChartOfID", accountIdList, " AND ");
}
if (accountCodeList != null && accountCodeList.Any())
{
sqlWhere.In("tblAccountChartOf.AccountCode", accountCodeList, " AND ");
}
if (sqlWhere.IsSetSqlWhereString)
{
sqlString = sqlString + sqlWhere.SqlWhereString;
}
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = sqlString;
cmd.Transaction = _transaction as SqlTransaction;
if (sqlWhere.ParameterListIsSet)
{
sqlWhere.AddParametersToSqlCommand(cmd);
}
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
int tablePk = reader.GetInt32(0);
int accountCode = reader.GetInt32(1);
string title = reader.GetString(2);
string description = null;
if (!reader.IsDBNull(3)) { description = reader.GetString(3); }
string type = reader.GetString(4);
string basicType = reader.GetString(5);
int multiplier = reader.GetInt32(6);
var result = new Model.Account.Account(tablePk, accountCode, title, description, type, basicType, multiplier);
resultDict.Add(tablePk, result);
}
}
}
return resultDict;
}
}
}

View File

@@ -0,0 +1,201 @@
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 AccountTaxRepository : _Base, IAccountTaxRepository
{
public AccountTaxRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
{
}
public Dictionary<int, Model.Account.TaxCodeInfo> ReadTaxCodeInfo(bool? IsActive = null, List<string> taxcodeList = null, List<int> taxcodeIdList = null)
{
var resultList = new Dictionary<int, Model.Account.TaxCodeInfo>();
Data.Database.SqlWhereBuilder whereBuilder = new SqlWhereBuilder();
//build sql query
string sqlString = @"
SELECT
AccountTaxCodeID
,TaxCode
,TaxCodeName
,TaxCodeDescription
,TaxRatePercent
,IsMarginScheme
,IsValidOnExpense
,IsVailidOnIncome
,IsActive
,TaxType
FROM tblAccountTaxCode
WHERE 1=1 ";
// add where clauses
if (IsActive.HasValue)
{
whereBuilder.IsEqualTo("IsActive", IsActive.Value, "AND");
}
if (taxcodeList != null && taxcodeList.Count > 0)
{
whereBuilder.In("TaxCode", taxcodeList, "AND");
}
if (taxcodeIdList != null && taxcodeIdList.Count > 0)
{
whereBuilder.In("AccountTaxCodeID", taxcodeIdList, "AND");
}
if (whereBuilder.IsSetSqlWhereString)
{
sqlString = sqlString + whereBuilder.SqlWhereString;
}
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = sqlString;
cmd.Transaction = _transaction as SqlTransaction;
if (whereBuilder.ParameterListIsSet)
{
whereBuilder.AddParametersToSqlCommand(cmd);
}
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
int taxCodeId = reader.GetByte(0);
string taxCode = reader.GetString(1);
string name = reader.GetString(2);
string description = null;
if (!reader.IsDBNull(3)) { description = reader.GetString(3); }
decimal rate = reader.GetDecimal(4);
bool isMargin = reader.GetBoolean(5);
bool isValidOnExpense = reader.GetBoolean(6);
bool isValidOnIncome = reader.GetBoolean(7);
bool isActive = reader.GetBoolean(8);
string taxType = reader.GetString(9);
var result = new Model.Account.TaxCodeInfo(
taxCode,
name,
description,
rate,
isMargin,
isValidOnExpense,
isValidOnIncome,
taxType,
isActive);
resultList.Add(taxCodeId, result);
}
}
}
return resultList;
}
public Dictionary<string, string> GetTaxCodeBySkuNumber(List<string> skuNumberList)
{
var resultList = new Dictionary<string, string>();
if (skuNumberList == null || !skuNumberList.Any())
{
return resultList;
}
skuNumberList = skuNumberList.Distinct().ToList();
string sql = @"
SELECT tblSku.skuSkuNumber
,tblAccountTaxCode.TaxCode
FROM tblSku
INNER JOIN tblAccountTaxCode ON tblSku.AccountTaxCodeID = tblAccountTaxCode.AccountTaxCodeID ";
var whereBuilder = new Data.Database.SqlWhereBuilder();
whereBuilder.In("tblSku.skuSkuNumber", skuNumberList, "WHERE");
sql += whereBuilder.SqlWhereString;
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = sql;
cmd.Transaction = _transaction as SqlTransaction;
if (whereBuilder.ParameterListIsSet)
{
whereBuilder.AddParametersToSqlCommand(cmd);
}
using (var reader = cmd.ExecuteReader())
{
if (!reader.HasRows)
{
return resultList;
}
while (reader.Read())
{
resultList.Add(reader.GetString(0), reader.GetString(1));
}
}
}
return resultList;
}
public Dictionary<string, string> ReadTaxCodeByInvoiceLineItemCode(List<string> lineItemCode)
{
var resultList = new Dictionary<string, string>();
if (lineItemCode == null || !lineItemCode.Any())
{
return resultList;
}
lineItemCode = lineItemCode.Distinct().ToList();
string sql = @"
SELECT tblAccountInvoiceLineItem.ItemCode
,tblAccountTaxCode.TaxCode
FROM tblAccountInvoiceLineItem
LEFT OUTER JOIN tblAccountTaxCode ON tblAccountInvoiceLineItem.AccountTaxCodeID_Default = tblAccountTaxCode.AccountTaxCodeID
";
var whereBuilder = new Data.Database.SqlWhereBuilder();
whereBuilder.In("tblAccountInvoiceLineItem.ItemCode", lineItemCode, "WHERE");
sql += whereBuilder.SqlWhereString;
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = sql;
cmd.Transaction = _transaction as SqlTransaction;
if (whereBuilder.ParameterListIsSet)
{
whereBuilder.AddParametersToSqlCommand(cmd);
}
using (var reader = cmd.ExecuteReader())
{
if (!reader.HasRows)
{
return resultList;
}
while (reader.Read())
{
if (reader.IsDBNull(1)) { resultList.Add(reader.GetString(0), null); }
else { resultList.Add(reader.GetString(0), reader.GetString(1)); }
}
}
}
return resultList;
}
}
}

View File

@@ -14,11 +14,11 @@ using System.Transactions;
namespace bnhtrade.Core.Data.Database.Repository.Implementation
{
internal class ImportAmazonRepository : _Base, IImportAmazonRepository
internal class AmazonSettlementRepository : _Base, IAmazonSettlementRepository
{
Logic.Log.LogEvent _log = new Logic.Log.LogEvent();
public ImportAmazonRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
public AmazonSettlementRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
{
}
@@ -368,13 +368,39 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
// Update Amazon Settlement Report
//
/// <summary>
/// Update the settlement report marketplace name by settlement Id (not table id)
/// </summary>
/// <param name="settlementId">Settlement id (not table/record id) of the settlement to update</param>
/// <param name="marketPlaceName">marketplace name</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public bool UpdateAmazonSettlementMarketPlaceName (string settlementId, Model.Amazon.MarketPlaceEnum marketPlace)
{
if (string.IsNullOrWhiteSpace(settlementId) || marketPlace == null)
{
throw new Exception("Settlement id or market place is invalid.");
}
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = @"
UPDATE tblImportAmazonSettlementReport
SET [marketplace-name] = @marketPlaceName
WHERE [settlement-id] = @settlementId;";
cmd.Parameters.AddWithValue("@marketPlaceName", marketPlace.GetMarketplaceUrl());
cmd.Parameters.AddWithValue("@settlementId", settlementId);
cmd.Transaction = _transaction as SqlTransaction;
return cmd.ExecuteNonQuery() > 0;
}
}
/// <summary>
/// Set the IsProcessed flag to true or false for the specified settlement Ids.
/// </summary>
/// <param name="settlementIdList">List of settlement id (not table id)</param>
/// <param name="isProcessed">value to set the isProcessed to</param>
/// <returns>Number of rows effected</returns>
public int SetAmazonSettlementIsProcessed(List<string> settlementIdList, bool isProcessed)
public int UpdateAmazonSettlementIsProcessed(List<string> settlementIdList, bool isProcessed)
{
if (settlementIdList == null || !settlementIdList.Any())
{

View File

@@ -1,4 +1,5 @@
using bnhtrade.Core.Data.Database.Repository.Interface;
using bnhtrade.Core.Logic.Account;
using bnhtrade.Core.Logic.Validate;
using Microsoft.Data.SqlClient;
using System;
@@ -164,7 +165,7 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
//
/// <summary>
/// Returns list of invoice numbers that have not yet been exported (i.e. IsComplete=True)
/// Returns list of invoice numbers that have not yet been exported (i.e. IsComplete=True), in InvoiceNumber asending order.
/// </summary>
/// <param name="invoiceType">Sales or Purchase</param>
/// <returns>Dictionary where key=ExportAccountInvoiceID, value=InvoiceNumber</returns>
@@ -176,7 +177,8 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
SELECT tblExportAccountInvoice.ExportAccountInvoiceID, [InvoiceNumber]
FROM tblExportAccountInvoice
WHERE (tblExportAccountInvoice.IsComplete = 0)
AND (tblExportAccountInvoice.ExportAccountInvoiceTypeID = @invoiceType);";
AND (tblExportAccountInvoice.ExportAccountInvoiceTypeID = @invoiceType)
ORDER BY [InvoiceNumber];";
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
@@ -211,35 +213,35 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
}
// get the account and tax code objects
var taxcode = new Data.Database.Account.ReadTaxCode().GetAllActive();
var account = new Data.Database.Account.ReadAccountCode().All();
//var taxcode = new Data.Database.Account.ReadTaxCode().GetAllActive();
//var account = new Data.Database.Account.ReadAccountCode().All();
var taxcodeIds = new Dictionary<int, int>();
var accountIds = new Dictionary<int, int>();
var lineItemIds = new Dictionary<int, int>();
// build sql string
string sql = @"
SELECT tblExportAccountInvoice.ExportAccountInvoiceID
, tblExportAccountInvoice.ExportAccountInvoiceTypeID
, tblExportAccountInvoice.Contact
, tblExportAccountInvoice.InvoiceNumber
, tblExportAccountInvoice.InvoiceDate
, tblExportAccountInvoice.InvoiceDueDate
, tblExportAccountInvoice.Reference
, tblExportAccountInvoice.CurrencyCode
, tblExportAccountInvoice.InvoiceAmount
, tblExportAccountInvoice.IsComplete
, tblExportAccountInvoiceLine.ExportAccountInvoiceLineID
, tblAccountInvoiceLineItem.ItemName
, tblExportAccountInvoiceLine.AccountChartOfID
, tblExportAccountInvoiceLine.NetAmount
, tblExportAccountInvoiceLine.AccountTaxCodeID
, tblExportAccountInvoiceLine.TaxAmount
, tblExportAccountInvoice.LineUnitAmountIsTaxExclusive
FROM tblExportAccountInvoice
INNER JOIN
tblExportAccountInvoiceLine
ON tblExportAccountInvoice.ExportAccountInvoiceID = tblExportAccountInvoiceLine.ExportAccountInvoiceID
INNER JOIN
tblAccountInvoiceLineItem
ON tblExportAccountInvoiceLine.AccountInvoiceLineItemID = tblAccountInvoiceLineItem.AccountInvoiceLineItemID
SELECT tblExportAccountInvoice.ExportAccountInvoiceID,
tblExportAccountInvoice.ExportAccountInvoiceTypeID,
tblExportAccountInvoice.Contact,
tblExportAccountInvoice.InvoiceNumber,
tblExportAccountInvoice.InvoiceDate,
tblExportAccountInvoice.InvoiceDueDate,
tblExportAccountInvoice.Reference,
tblExportAccountInvoice.CurrencyCode,
tblExportAccountInvoice.InvoiceAmount,
tblExportAccountInvoice.IsComplete,
tblExportAccountInvoiceLine.ExportAccountInvoiceLineID,
tblExportAccountInvoiceLine.AccountInvoiceLineItemID,
tblExportAccountInvoiceLine.AccountChartOfID,
tblExportAccountInvoiceLine.NetAmount,
tblExportAccountInvoiceLine.AccountTaxCodeID,
tblExportAccountInvoiceLine.TaxAmount,
tblExportAccountInvoice.LineUnitAmountIsTaxExclusive
FROM tblExportAccountInvoice
INNER JOIN
tblExportAccountInvoiceLine
ON tblExportAccountInvoice.ExportAccountInvoiceID = tblExportAccountInvoiceLine.ExportAccountInvoiceID
";
var sqlWhere = new Data.Database.SqlWhereBuilder();
@@ -247,6 +249,7 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
sql = sql + sqlWhere.SqlWhereString + " ORDER BY tblExportAccountInvoice.ExportAccountInvoiceID, tblExportAccountInvoiceLine.ExportAccountInvoiceLineID; ";
int i = 0;
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = sql;
@@ -265,8 +268,10 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
int? previousInvoiceId = null;
Model.Account.SalesInvoice invoice = null;
i = -1;
while (reader.Read())
{
i++;
invoiceId = reader.GetInt32(0);
// test for first/next invoice
@@ -301,11 +306,11 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
// add line info
var invoiceLine = new Model.Account.SalesInvoice.InvoiceLine(invoice);
int lineId = reader.GetInt32(10);
invoiceLine.ItemCode = reader.GetString(11);
invoiceLine.Account = account[Convert.ToUInt32(reader.GetInt32(12))];
lineItemIds.Add(i, reader.GetInt32(11));
accountIds.Add(i, reader.GetInt32(12));
invoiceLine.UnitAmount = reader.GetDecimal(13);
invoiceLine.Quantity = 1;
invoiceLine.TaxCode = taxcode[reader.GetByte(14)];
taxcodeIds.Add(i, reader.GetByte(14));
invoiceLine.SetTaxAdjustmentByTaxTotal(reader.GetDecimal(15));
invoice.InvoiceLineList.Add(invoiceLine);
@@ -316,6 +321,30 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
returnList.Add(invoiceId.Value, invoice);
}
}
// get and add account/tax/item objects to invoice
var dbTaxCodes = new AccountTaxRepository(_connection, _transaction).ReadTaxCodeInfo(null, null, taxcodeIds.Values.ToList());
var dbAccountCodes = new AccountCodeRepository(_connection, _transaction).ReadAccountCode(accountIds.Values.ToList());
var dbLineItems = new InvoiceRepository(_connection, _transaction).GetInvoiceLineItem(lineItemIds.Values.ToList());
i = -1;
foreach (var invoice in returnList.Values)
{
foreach (var line in invoice.InvoiceLineList)
{
i++;
line.TaxCode = dbTaxCodes[taxcodeIds[i]];
line.Account = dbAccountCodes[accountIds[i]];
// fill in missing data for line item, if required
var invoiceLineItem = dbLineItems[lineItemIds[i]];
line.ItemCode = invoiceLineItem.ItemCode;
if (string.IsNullOrEmpty(line.Description))
{
line.Description = invoiceLineItem.Name;
}
}
}
return returnList;
}
@@ -323,57 +352,36 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
// invoice update methods
//
/// <summary>
/// Update the 'IsComplete' field by invoice id
/// </summary>
/// <param name="updateDictionary">key=ExportAccountInvoiceTypeID, value=IsComplete</param>
/// <returns>Number of row effected</returns>
public int SetInvoiceIsCompleteValue(Dictionary<int, bool> updateDictionary)
public int UpdateInvoiceHeaderDetail(int invoiceId, string invoiceNumber = null, bool? isComplete = null)
{
int returnCount = 0;
foreach (var item in updateDictionary)
if (invoiceNumber == null && isComplete == null)
{
string sql = @"
UPDATE
tblExportAccountInvoice
SET
IsComplete = @isComplete
WHERE
ExportAccountInvoiceID = @id
";
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = sql;
cmd.Transaction = _transaction as SqlTransaction;
cmd.Parameters.AddWithValue("@id", item.Key);
cmd.Parameters.AddWithValue("@isComplete", item.Value);
returnCount = returnCount + cmd.ExecuteNonQuery();
}
throw new ArgumentException("At least one of the parameters must be set to update invoice header details.");
}
// build the statement with my helper
var sqlupdate = new Core.Data.Database.SqlUpdateBuilder();
sqlupdate.SetTableName("tblExportAccountInvoice");
if (invoiceNumber != null)
sqlupdate.AddUpdateArugment("InvoiceNumber", invoiceNumber);
if (isComplete.HasValue)
sqlupdate.AddUpdateArugment("IsComplete", isComplete);
sqlupdate.AddWhereArugment("ExportAccountInvoiceID", invoiceId);
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.Transaction = _transaction as SqlTransaction;
cmd.CommandText = sqlupdate.GetSqlString();
sqlupdate.AddParametersToSqlCommand(cmd);
return cmd.ExecuteNonQuery();
}
return returnCount;
}
//
// Invoice Delete Methods
//
public int DeleteInvoiceLine(int invoiceLineId)
{
// only being able to delete one line at a time is a design/safety decision
// otherwise, delete whole invoice
if (invoiceLineId <= 0)
{
throw new ArgumentException("InvoiceLineId must be greater than zero.");
}
Core.Data.Database.SqlWhereBuilder sqlWhereBuilder = new Core.Data.Database.SqlWhereBuilder();
sqlWhereBuilder.In("ExportAccountInvoiceLineID", new List<int> { invoiceLineId });
return DeleteInvoiceExecuteInvoiceLine(sqlWhereBuilder);
}
public int DeleteInvoice(IEnumerable<int> invoiceIdList)
{
if (invoiceIdList == null || invoiceIdList.Count() == 0)
@@ -406,6 +414,19 @@ namespace bnhtrade.Core.Data.Database.Repository.Implementation
}
}
public int DeleteInvoiceLine(int invoiceLineId)
{
// only being able to delete one line at a time is a design/safety decision
// otherwise, delete whole invoice
if (invoiceLineId <= 0)
{
throw new ArgumentException("InvoiceLineId must be greater than zero.");
}
Core.Data.Database.SqlWhereBuilder sqlWhereBuilder = new Core.Data.Database.SqlWhereBuilder();
sqlWhereBuilder.In("ExportAccountInvoiceLineID", new List<int> { invoiceLineId });
return DeleteInvoiceExecuteInvoiceLine(sqlWhereBuilder);
}
/// <summary>
/// Helper method Only intended for use with ExecuteInvoice() or ExecuteInvoiceLine()
/// </summary>

View File

@@ -0,0 +1,585 @@
using bnhtrade.Core.Data.Database.Repository.Interface;
using FikaAmazonAPI.AmazonSpApiSDK.Models.EasyShip20220323;
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 InvoiceRepository : _Base, IInvoiceRepository
{
public InvoiceRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
{
}
public int CreateDefaultInvoiceLineItem(string itemCode)
{
string sql = @"
INSERT INTO tblAccountInvoiceLineItem ( ItemName, ItemCode )
OUTPUT INSERTED.AccountInvoiceLineItemID
VALUES ( @itemName, @itemCode )
";
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = sql;
cmd.Transaction = _transaction as SqlTransaction;
cmd.Parameters.AddWithValue("@itemName", itemCode);
cmd.Parameters.AddWithValue("@itemCode", itemCode);
object obj = cmd.ExecuteScalar();
if (obj == null || obj == DBNull.Value)
{
throw new Exception("Error inserting new defalt invoice line item into database");
}
return (int)obj;
}
}
/// <summary>
/// Retrieves a collection of invoice line items, optionally including account and tax information.
/// </summary>
/// <remarks>This method queries the database to retrieve invoice line items. If <paramref
/// name="includeAccountInfo"/> or <paramref name="includeTaxInfo"/> is set to <see langword="true"/>,
/// additional queries are performed to fetch the corresponding account and tax information, which may impact
/// performance.</remarks>
/// <param name="itemCodes">An optional collection of item codes to filter the results. If <see langword="null"/> or empty, all invoice
/// line items are retrieved.</param>
/// <param name="includeAccountInfo">A value indicating whether to include account information for each invoice line item. If <see
/// langword="true"/>, the default account code is populated for each item. Defaults to <see langword="true"/>.</param>
/// <param name="includeTaxInfo">A value indicating whether to include tax information for each invoice line item. If <see
/// langword="true"/>, the default tax code is populated for each item. Defaults to <see langword="true"/>.</param>
/// <returns>A dictionary where the key is the table record id of the invoice line item, and the value is the
/// corresponding <see cref="Model.Account.InvoiceLineItem"/> object. The dictionary will be empty if no
/// matching items are found.</returns>
public Dictionary<int, Model.Account.InvoiceLineItem> GetInvoiceLineItem(
IEnumerable<int> itemIds = null, IEnumerable<string> itemCodes = null, bool includeAccountInfo = true, bool includeTaxInfo = true
)
{
var sqlwhere = new SqlWhereBuilder();
var returnList = new Dictionary<int, Model.Account.InvoiceLineItem>();
var accountCodeIdList = new Dictionary<int, int>(); // key=LineItemID, value=AccountChartOfID
var taxCodeIdList = new Dictionary<int, int>(); // key=LineItemID, value=AccountTaxCodeID
string sql = @"
SELECT [AccountInvoiceLineItemID]
,[ItemName]
,[ItemCode]
,[ItemDescription]
,[IsNewReviewRequired]
,[InvoiceLineEntryEnable]
,[AccountChartOfID_Default]
,[AccountTaxCodeID_Default]
FROM [e2A].[dbo].[tblAccountInvoiceLineItem]
WHERE 1=1 ";
if (itemCodes != null && itemCodes.Any())
{
sqlwhere.In("ItemCode", itemCodes, "AND");
sql += sqlwhere.SqlWhereString;
}
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = sql;
cmd.Transaction = _transaction as SqlTransaction;
sqlwhere.AddParametersToSqlCommand(cmd);
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var lineItem = new Model.Account.InvoiceLineItem();
int recordId = reader.GetInt32(0);
lineItem.Name = reader.GetString(1);
lineItem.ItemCode = reader.GetString(2);
if (!reader.IsDBNull(3)) { lineItem.Description = reader.GetString(3); }
lineItem.IsNewReviewRequired = reader.GetBoolean(4);
lineItem.InvoiceLineEntryEnabled = reader.GetBoolean(5);
if (!reader.IsDBNull(6))
{
accountCodeIdList.Add(recordId, reader.GetInt32(6));
}
if (!reader.IsDBNull(7))
{
taxCodeIdList.Add(recordId, reader.GetInt32(7));
}
returnList.Add(recordId, lineItem);
}
}
}
// get account codes and add to result list
if (includeAccountInfo)
{
var accountCodeDictionary = new AccountCodeRepository(_connection, _transaction).ReadAccountCode(accountCodeIdList.Values.ToList());
foreach (var accountCode in accountCodeIdList)
{
returnList[accountCode.Key].DefaultAccountCode = accountCodeDictionary[accountCode.Value];
}
}
// get tax codes
if (includeTaxInfo)
{
var taxCodeDictionary = new AccountTaxRepository(_connection, _transaction).ReadTaxCodeInfo(null, null, taxCodeIdList.Values.ToList());
foreach (var taxCode in taxCodeIdList)
{
returnList[taxCode.Key].DefaultTaxCode = taxCodeDictionary[taxCode.Value];
}
}
return returnList;
}
public Dictionary<int, Model.Account.PurchaseInvoice> ReadPurchaseInvoice(IEnumerable<int> purchaseInvoiceIdList)
{
var returnList = new Dictionary<int, Model.Account.PurchaseInvoice>();
SqlWhereBuilder sqlBuilder = new SqlWhereBuilder();
//build sql query
string sql = @"
SELECT tblPurchase.PurchaseID
,tblPurchase.PurchaseNumber
,tblPurchase.RecordID
,tblPurchase.PurchaseDate
,tblPurchase.ContactID
,tblPurchase.SupplierRef
,tblPurchase.PurchaseTotalAmount
,tblPurchase.VatInclusiveAmounts
,tblPurchase.RecordCreated
,tblPurchase.RecordModified
,tblPurchase.IsActive
,tblAccountCurrency.CurrencyCode
,tblPurchaseChannel.PurchaseChannelName
,tblPurchaseStatus.PurchaseStatus
FROM tblPurchase
LEFT OUTER JOIN tblAccountCurrency ON tblPurchase.AccountCurrencyID = tblAccountCurrency.AccountCurrencyID
LEFT OUTER JOIN tblPurchaseStatus ON tblPurchase.PurchaseStatusID = tblPurchaseStatus.PurchaseStatusID
LEFT OUTER JOIN tblPurchaseChannel ON tblPurchase.PurchaseChannelID = tblPurchaseChannel.PurchaseChannelID
WHERE 1 = 1
";
// build the where statments
if (purchaseInvoiceIdList.Any())
{
sqlBuilder.In("[PurchaseID]", purchaseInvoiceIdList, "AND");
}
// append where string to the sql
if (sqlBuilder.IsSetSqlWhereString)
{
sql = sql + sqlBuilder.SqlWhereString;
}
// dictionary so we can fill in details afterwards
var invoiceContactDict = new Dictionary<int, int>();
var purchaseIdList = new List<int>();
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = sql;
cmd.Transaction = _transaction as SqlTransaction;
sqlBuilder.AddParametersToSqlCommand(cmd);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
int purchaseID = reader.GetInt32(0);
int purchaseNumber = reader.GetInt32(1);
int? recordID = null;
if (!reader.IsDBNull(2)) { recordID = reader.GetInt32(2); }
DateTime purchaseDate = DateTime.SpecifyKind(reader.GetDateTime(3), DateTimeKind.Utc);
int? contactID = null;
if (!reader.IsDBNull(4)) { contactID = reader.GetInt32(4); }
string supplierRef = null;
if (!reader.IsDBNull(5)) { supplierRef = reader.GetString(5); }
decimal? purchaseTotalAmount = null;
if (!reader.IsDBNull(6)) { purchaseTotalAmount = reader.GetDecimal(6); }
bool vatInclusiveAmounts = reader.GetBoolean(7);
DateTime recordCreated = DateTime.SpecifyKind(reader.GetDateTime(8), DateTimeKind.Utc);
DateTime recordModified = DateTime.SpecifyKind(reader.GetDateTime(9), DateTimeKind.Utc);
bool isActive = reader.GetBoolean(10);
string currencyCode = reader.GetString(11);
string purchaseChannelName = reader.GetString(12);
string purchaseStatus = null;
if (!reader.IsDBNull(13)) { purchaseStatus = reader.GetString(13); }
var invoice = new Model.Account.PurchaseInvoice();
invoice.PurchaseID = purchaseID;
invoice.PurchaseNumber = purchaseNumber;
invoice.RecordID = recordID;
invoice.PurchaseDate = purchaseDate;
invoice.SupplierRef = supplierRef;
//invoice.PurchaseTotalAmount = purchaseTotalAmount;
invoice.VatInclusiveAmounts = vatInclusiveAmounts;
invoice.RecordCreated = recordCreated;
invoice.RecordModified = recordModified;
invoice.IsActive = isActive;
invoice.CurrencyCode = currencyCode;
invoice.PurchaseChannel = purchaseChannelName;
// is there contact info that needs to be added?
if (contactID != null)
{
invoiceContactDict.Add(purchaseID, (int)contactID);
}
purchaseIdList.Add(purchaseID);
returnList.Add(purchaseID, invoice);
}
}
}
}
// add contact info
if (invoiceContactDict.Any())
{
var readContact = new Data.Database.Account.ReadContact();
readContact.ContactIdList = invoiceContactDict.Values.ToList();
var contactDict = readContact.Read();
if (contactDict.Any())
{
foreach (var invoice in returnList)
{
if (invoiceContactDict.ContainsKey(invoice.Value.PurchaseID))
{
int contactId = invoiceContactDict[invoice.Value.PurchaseID];
invoice.Value.Contact = contactDict[contactId];
}
}
}
}
// add invoice lines
var lines = ReadPurchaseInvoiceLine(purchaseIdList);
foreach (var invoice in returnList.Values)
{
foreach (var line in lines.Values)
{
if (line.PurchaseId == invoice.PurchaseID)
{
if (invoice.InvoiceLines == null)
{
invoice.InvoiceLines = new List<Model.Account.PurchaseInvoice.Line>();
}
invoice.InvoiceLines.Add(line);
}
}
}
return returnList;
}
/// <summary>
/// Retrieves purchase invoice lines based on specified filters.
/// </summary>
/// <remarks>This method queries the database to retrieve purchase invoice line details that match
/// the provided filters. The filters include invoice IDs, invoice line IDs, statuses, and item descriptions.
/// The returned dictionary maps the purchase line ID to its corresponding <see
/// cref="Model.Account.PurchaseInvoice.Line"/> object.</remarks>
/// <param name="invoiceIdList">A list of purchase invoice IDs to filter the results. If empty, no filtering is applied.</param>
/// <param name="invoiceLineIdList">A list of purchase invoice line IDs to filter the results. If empty, no filtering is applied.</param>
/// <param name="statusList">A list of statuses to filter the results. If empty, no filtering is applied.</param>
/// <param name="itemDescription">Searches for the specificed phases within the item description. Uses the LIKE AND sql function. Partial matches are supported. If empty, no filtering is
/// applied.</param>
/// <returns>A dictionary where the key is the purchase line ID and the value is the corresponding
/// Model.Account.PurchaseInvoice.Line object containing detailed information about the purchase invoice line.</returns>
/// <exception cref="Exception">Thrown if a fail-safe condition is triggered, indicating an unexpected issue with tax code assignment.</exception>
public Dictionary<int, Model.Account.PurchaseInvoice.Line> ReadPurchaseInvoiceLine
(List<int> invoiceIdList = null, List<int> invoiceLineIdList = null, List<string> statusList = null, List<string> itemDescriptionList = null)
{
var returnList = new Dictionary<int, Model.Account.PurchaseInvoice.Line>();
var sqlBuilder = new SqlWhereBuilder();
//build sql query
string sql = @"
SELECT tblPurchaseLine.PurchaseLineID
,tblPurchaseLine.PurchaseID
,tblPurchaseLineStatus.PurchaseLineStatus
,tblPurchaseLine.SupplierRef
,tblPurchaseLine.CheckedIn
,tblPurchaseLine.ItemDescription
,tblPurchaseLine.ItemQuantity
,tblPurchaseLine.ItemGross
,tblPurchaseLine.ItemTax
,tblPurchaseLine.ShippingGross
,tblPurchaseLine.ShippingTax
,tblPurchaseLine.OtherGross
,tblPurchaseLine.OtherTax
,tblPurchaseLine.AccountTaxCodeID
,tblPurchaseLine.Tax_AccountTransactionID
,tblPurchaseLine.Net_AccountChartOfID
,tblPurchaseLine.Net_AccountTransactionID
,tblPurchaseLine.RecordCreated
,tblPurchaseLine.RecordModified
,tblPurchaseLine.IsActive
,tblAccountTaxCode.TaxCode
FROM tblPurchaseLine
INNER JOIN tblPurchaseLineStatus ON tblPurchaseLine.PurchaseLineStatusID = tblPurchaseLineStatus.PurchaseLineStatusID
LEFT OUTER JOIN tblAccountTaxCode ON tblPurchaseLine.AccountTaxCodeID = tblAccountTaxCode.AccountTaxCodeID
WHERE 1 = 1 ";
// build the where statments
if (invoiceIdList != null || invoiceIdList.Any())
{
sqlBuilder.In("PurchaseID", invoiceLineIdList, "AND");
}
if (invoiceLineIdList != null || invoiceLineIdList.Any())
{
sqlBuilder.In("PurchaseLineID", invoiceLineIdList, "AND");
}
if (statusList != null || statusList.Any())
{
sqlBuilder.In("PurchaseLineStatus", invoiceLineIdList, "AND");
}
if (itemDescriptionList != null || itemDescriptionList.Any())
{
sqlBuilder.LikeAnd("ItemDescription", itemDescriptionList, "AND");
}
// append where string to the sql
if (sqlBuilder.IsSetSqlWhereString)
{
sql = sql + sqlBuilder.SqlWhereString;
}
// catch taxcode to add in after db read
var lineTaxCodeDict = new Dictionary<int, string>();
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = sql;
cmd.Transaction = _transaction as SqlTransaction;
sqlBuilder.AddParametersToSqlCommand(cmd);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
int purchaseLineID = reader.GetInt32(0);
int purchaseID = reader.GetInt32(1);
string purchaseLineStatus = reader.GetString(2);
string supplierRef = null;
if (!reader.IsDBNull(3)) { supplierRef = reader.GetString(3); }
DateTime? checkedIn = null;
if (!reader.IsDBNull(4)) { checkedIn = DateTime.SpecifyKind(reader.GetDateTime(4), DateTimeKind.Utc); }
string itemDescription = null;
if (!reader.IsDBNull(5)) { itemDescription = reader.GetString(5); }
int itemQuantity = reader.GetInt32(6);
decimal itemGross = 0;
if (!reader.IsDBNull(7)) { itemGross = reader.GetDecimal(7); }
decimal itemTax = 0;
if (!reader.IsDBNull(8)) { itemTax = reader.GetDecimal(8); }
decimal shippingGross = 0;
if (!reader.IsDBNull(9)) { shippingGross = reader.GetDecimal(9); }
decimal shippingTax = 0;
if (!reader.IsDBNull(10)) { shippingTax = reader.GetDecimal(10); }
decimal otherGross = 0;
if (!reader.IsDBNull(11)) { otherGross = reader.GetDecimal(11); }
decimal otherTax = 0;
if (!reader.IsDBNull(12)) { otherTax = reader.GetDecimal(12); }
int accountTaxCodeID = reader.GetInt32(13);
int? tax_AccountTransactionID = null;
if (!reader.IsDBNull(14)) { tax_AccountTransactionID = reader.GetInt32(14); }
int net_AccountChartOfID = reader.GetInt32(15);
int? net_AccountTransactionID = null;
if (!reader.IsDBNull(16)) { net_AccountTransactionID = reader.GetInt32(16); }
DateTime recordModified;
DateTime recordCreated = DateTime.SpecifyKind(reader.GetDateTime(17), DateTimeKind.Utc);
if (reader.IsDBNull(18)) { recordModified = recordCreated; }
else { recordModified = DateTime.SpecifyKind(reader.GetDateTime(18), DateTimeKind.Utc); }
bool isActive = reader.GetBoolean(19);
string accountTaxCode = reader.GetString(20);
var line = new Model.Account.PurchaseInvoice.Line();
line.PurchaseLineId = purchaseLineID;
line.PurchaseId = purchaseID;
line.Status = purchaseLineStatus;
line.SupplierRef = supplierRef;
line.CheckedIn = checkedIn;
line.ItemDescription = itemDescription;
line.ItemQuantity = itemQuantity;
line.ItemGross = itemGross;
line.ItemTax = itemTax;
line.ShippingGross = shippingGross;
line.ShippingTax = shippingTax;
line.OtherGross = otherGross;
line.OtherTax = otherTax;
line.Tax_AccountTransactionId = tax_AccountTransactionID;
line.Net_AccountChartOfId = net_AccountChartOfID;
line.Net_AccountTransactionId = net_AccountTransactionID;
line.RecordModified = recordModified;
line.RecordCreated = recordCreated;
line.IsActive = isActive;
returnList.Add(purchaseLineID, line);
lineTaxCodeDict.Add(purchaseLineID, accountTaxCode);
}
}
}
}
// read tax codes form db and add to return object
var taxcodeList = new AccountTaxRepository(_connection, _transaction).ReadTaxCodeInfo(null, lineTaxCodeDict.Values.ToList()).Values.ToList();
foreach (var line in returnList.Values)
{
foreach (var taxcode in taxcodeList)
{
if (taxcode.TaxCode == lineTaxCodeDict[line.PurchaseLineId])
{
line.AccountTaxCode = taxcode;
break;
}
}
if (line.AccountTaxCode == null)
{
throw new Exception("Fail safe, this really shouodn't happen");
}
}
// all done
return returnList;
}
public Dictionary<int, Model.Account.PurchaseInvoiceLineStatus> ReadPurchaseInvoiceLineStatus()
{
var returnList = new Dictionary<int, Model.Account.PurchaseInvoiceLineStatus>();
string sql = @"
SELECT [PurchaseLineStatusID]
,[PurchaseLineStatus]
,[ListSort]
,[TimeStamp]
FROM [e2A].[dbo].[tblPurchaseLineStatus]
ORDER BY [ListSort]";
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = sql;
cmd.Transaction = _transaction as SqlTransaction;
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (!reader.HasRows)
{
// do something
}
else
{
while (reader.Read())
{
int id = reader.GetInt32(0);
string name = reader.GetString(1);
int lineSort = reader.GetInt32(2);
var returnItem = new Model.Account.PurchaseInvoiceLineStatus(id, name, lineSort);
returnList.Add(id, returnItem);
}
}
}
}
return returnList;
}
public List<Model.Account.PurchaseInvoiceLineSummary> ReadPurchaseInvoiceLineSummary(DateTime periodTo, string lineStatus, List<string> descriptionSearch)
{
var returnList = new List<Model.Account.PurchaseInvoiceLineSummary>();
var sqlBuilder = new bnhtrade.Core.Data.Database.SqlWhereBuilder();
//build sql query
string sql = @"
SELECT tblPurchase.PurchaseDate
,tblPurchase.PurchaseID
,tblPurchase.PurchaseNumber
,tblPurchaseLine.PurchaseLineID
,tblPurchaseLine.ItemDescription
,tblPurchaseLineStatus.PurchaseLineStatus
FROM tblPurchase
INNER JOIN tblPurchaseLine ON tblPurchase.PurchaseID = tblPurchaseLine.PurchaseID
INNER JOIN tblPurchaseLineStatus ON tblPurchaseLine.PurchaseLineStatusID = tblPurchaseLineStatus.PurchaseLineStatusID
WHERE tblPurchase.PurchaseDate <= @purchaseDate
";
if (lineStatus != null)
{
sql = sql + " AND PurchaseLineStatus = @purchaseLineStatus ";
}
// build the where statments
if (descriptionSearch.Any())
{
sqlBuilder.LikeAnd("ItemDescription", descriptionSearch, "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;
cmd.Parameters.AddWithValue("@purchaseDate", periodTo);
if (lineStatus != null)
{
cmd.Parameters.AddWithValue("@purchaseLineStatus", lineStatus);
}
sqlBuilder.AddParametersToSqlCommand(cmd);
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
DateTime purchaseDate = DateTime.SpecifyKind(reader.GetDateTime(0), DateTimeKind.Utc);
int purchaseID = reader.GetInt32(1);
int purchaseNumber = reader.GetInt32(2);
int purchaseLineID = reader.GetInt32(3);
string itemDescription = reader.GetString(4);
string purchaseLineStatus = reader.GetString(5);
var item = new Model.Account.PurchaseInvoiceLineSummary();
item.PurchaseDate = purchaseDate;
item.PurchaseId = purchaseID;
item.PurchaseNumber = purchaseNumber;
item.PurchaseLineId = purchaseLineID;
item.ItemDescription = itemDescription;
item.LineStatus = purchaseLineStatus;
returnList.Add(item);
}
}
}
return returnList;
}
}
}

View File

@@ -0,0 +1,372 @@
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;
}
}
}

View File

@@ -0,0 +1,117 @@
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 SkuRepository : _Base, ISkuRepository
{
public SkuRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
{
}
public int? ReadSkuId(int productId, int conditionId, int accountTaxCodeId)
{
int? returnId = null;
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = @"
SELECT
tblSku.skuSkuID
FROM
tblSku
WHERE
(((tblSku.skuProductID)=@productId) AND ((tblSku.skuSkuConditionID)=@conditionId) AND ((tblSku.AccountTaxCodeID)=@accountTaxCodeId));
";
cmd.Transaction = _transaction as SqlTransaction;
cmd.Parameters.AddWithValue("@productId", productId);
cmd.Parameters.AddWithValue("@conditionId", conditionId);
cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId);
object obj = cmd.ExecuteScalar();
if (obj != null || obj == DBNull.Value)
{
returnId = (int)obj;
}
}
return returnId;
}
public int InsertNewSku(int productId, int conditionId, int accountTaxCodeId)
{
// check tax code id is a valid for SKU
var taxCodeList = new AccountTaxRepository(_connection, _transaction).ReadTaxCodeInfo(null, null, new List<int> { accountTaxCodeId });
if (taxCodeList.ContainsKey(accountTaxCodeId) == false)
{
throw new Exception("AccountTaxCodeID=" + accountTaxCodeId + " doesn't exist!");
}
else if (taxCodeList[accountTaxCodeId].IsValidOnIncome == false)
{
throw new Exception("AccountTaxCodeID=" + accountTaxCodeId + " is not a valid type for an SKU.");
}
// get info to create sku number
int skuCount;
int skuSuffix;
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = "SELECT NEXT VALUE FOR SkuCountSequence;";
cmd.Transaction = _transaction as SqlTransaction;
skuCount = (int)cmd.ExecuteScalar();
}
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = @"
SELECT tblSkuCondition.scnSkuNumberSuffix
FROM tblSkuCondition
WHERE (((tblSkuCondition.scnSkuConditionID)=@conditionId));";
cmd.Transaction = _transaction as SqlTransaction;
cmd.Parameters.AddWithValue("@conditionId", conditionId);
try
{
skuSuffix = (int)cmd.ExecuteScalar();
}
catch (Exception ex)
{
throw new Exception("Error retriving SKU number suffix for SkuConditionID=" + conditionId + "." +
System.Environment.NewLine + "Error Message: " + ex.Message);
}
}
string skuNumber = skuCount.ToString("D6") + "-" + skuSuffix.ToString("D2");
// insert new sku
int skuId;
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = @"
INSERT INTO tblSku
(skuSkuNumber, skuProductID, skuSkuConditionID, AccountTaxCodeID)
OUTPUT INSERTED.skuSkuID
VALUES
(@skuNumber, @productId, @conditionId, @accountTaxCodeId)";
cmd.Transaction = _transaction as SqlTransaction;
cmd.Parameters.AddWithValue("@skuNumber", skuNumber);
cmd.Parameters.AddWithValue("@productId", productId);
cmd.Parameters.AddWithValue("@conditionId", conditionId);
cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId);
skuId = (int)cmd.ExecuteScalar();
}
return skuId;
}
}
}

View File

@@ -0,0 +1,141 @@
using bnhtrade.Core.Data.Database._BoilerPlate;
using bnhtrade.Core.Data.Database.Repository.Interface;
using Microsoft.Data.SqlClient;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database.Repository.Implementation
{
internal class StockRepository : _Base, IStockRepository
{
public StockRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction)
{
}
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>();
//build sql query
string sql = @"
SELECT [StockStatusID]
,[StatusCode]
,[StockStatus]
,[StockStatusTypeID]
,[Reference]
,[ForeignKeyID]
,[IsCreditOnly]
,[IsClosed]
,[RecordCreated]
FROM [e2A].[dbo].[tblStockStatus]
WHERE 1=1 ";
// build the where statments
if (statusIds.Any())
{
sqlBuilder.In("StockStatusID", statusIds, "AND");
}
if (statusTypeIds.Any())
{
sqlBuilder.In("StockStatusTypeID", statusTypeIds, "AND");
}
// append where string to the sql
if (sqlBuilder.IsSetSqlWhereString)
{
sql = sql + sqlBuilder.SqlWhereString;
}
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = sql;
cmd.Transaction = _transaction as SqlTransaction;
if (sqlBuilder.ParameterListIsSet)
{
sqlBuilder.AddParametersToSqlCommand(cmd);
}
using (SqlDataReader reader = cmd.ExecuteReader())
{
var typeDict = new 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 returnList;
}
public Dictionary<int, Model.Stock.StatusType> ReadStatusType()
{
var returnDict = new Dictionary<int, Model.Stock.StatusType>();
// get all account info before we start
var accountDict = new AccountCodeRepository(_connection, _transaction).ReadAccountCode();
using (SqlCommand cmd = _connection.CreateCommand() as SqlCommand)
{
cmd.CommandText = @"
SELECT [StockStatusTypeID]
,[StatusTypeName]
,[ForeignKeyType]
,[ReferenceType]
,[AccountChartOfID]
FROM [e2A].[dbo].[tblStockStatusType]";
cmd.Transaction = _transaction as SqlTransaction;
using (SqlDataReader reader = cmd.ExecuteReader())
{
var accountIdDict = new Dictionary<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);
}
}
}
return returnDict;
}
}
}

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database.Repository.Implementation
{
abstract class _Base
public abstract class _Base
{
protected readonly IDbConnection _connection;
protected readonly IDbTransaction _transaction;

View File

@@ -0,0 +1,13 @@
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 IAccountCodeRepository
{
Dictionary<int, Model.Account.Account> ReadAccountCode(List<int> accountIdList = null, List<int> accountCodeList = null);
}
}

View File

@@ -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 IAccountTaxRepository
{
Dictionary<int, Model.Account.TaxCodeInfo> ReadTaxCodeInfo(bool? IsActive = null, List<string> taxcodeList = null, List<int> taxcodeIdList = null);
Dictionary<string, string> GetTaxCodeBySkuNumber(List<string> skuNumberList);
Dictionary<string, string> ReadTaxCodeByInvoiceLineItemCode(List<string> lineItemCode);
}
}

View File

@@ -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 IAmazonSettlementRepository
{
List<Model.Import.AmazonSettlementHeader> ReadAmazonSettlementHeaderInfoBySettlementId(List<string> settlementIdList);
List<Model.Import.AmazonSettlementHeader> ReadAmazonSettlementHeaderInfoBySpapiReportId(List<string> spapiReportIdList);
Dictionary<int, Model.Import.AmazonSettlement> ReadAmazonSettlements(
List<string> settlementIdList = null, List<string> marketPlaceNameList = null, bool? isProcessed = null,
bool descendingOrder = false, int? returnTop = null);
bool UpdateAmazonSettlementMarketPlaceName(string settlementId, Model.Amazon.MarketPlaceEnum marketPlace);
int UpdateAmazonSettlementIsProcessed(List<string> settlementIdList, bool isProcessed);
bool CreateAmazonSettlements(string filePath, string reportId);
int SetSpapiReportId(string settlementId, string spapiReportId);
}
}

View File

@@ -8,11 +8,11 @@ namespace bnhtrade.Core.Data.Database.Repository.Interface
{
internal interface IExportInvoiceRepository
{
internal Dictionary<int, Model.Account.SalesInvoice> InsertSalesInvoices(IEnumerable<Model.Account.SalesInvoice> invoiceList);
internal Dictionary<int, string> GetNewInvoiceNumbers(Model.Account.InvoiceType invoiceType);
internal Dictionary<int, Model.Account.SalesInvoice> GetSalesInvoiceById(IEnumerable<int> idList);
internal int SetInvoiceIsCompleteValue(Dictionary<int, bool> updateDictionary);
internal int DeleteInvoiceLine(int invoiceLineId);
internal int DeleteInvoice(IEnumerable<int> invoiceIdList);
Dictionary<int, Model.Account.SalesInvoice> InsertSalesInvoices(IEnumerable<Model.Account.SalesInvoice> invoiceList);
Dictionary<int, string> GetNewInvoiceNumbers(Model.Account.InvoiceType invoiceType);
Dictionary<int, Model.Account.SalesInvoice> GetSalesInvoiceById(IEnumerable<int> idList);
int UpdateInvoiceHeaderDetail(int invoiceId, string invoiceNumber = null, bool? isComplete = null);
int DeleteInvoiceLine(int invoiceLineId);
int DeleteInvoice(IEnumerable<int> invoiceIdList);
}
}

View File

@@ -1,25 +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 IImportAmazonRepository
{
public List<Model.Import.AmazonSettlementHeader> ReadAmazonSettlementHeaderInfoBySettlementId(List<string> settlementIdList);
public List<Model.Import.AmazonSettlementHeader> ReadAmazonSettlementHeaderInfoBySpapiReportId(List<string> spapiReportIdList);
public Dictionary<int, Model.Import.AmazonSettlement> ReadAmazonSettlements(
List<string> settlementIdList = null, List<string> marketPlaceNameList = null, bool? isProcessed = null,
bool descendingOrder = false, int? returnTop = null);
public int SetAmazonSettlementIsProcessed(List<string> settlementIdList, bool isProcessed);
public bool CreateAmazonSettlements(string filePath, string reportId);
public int SetSpapiReportId(string settlementId, string spapiReportId);
}
}

View File

@@ -0,0 +1,21 @@
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 IInvoiceRepository
{
int CreateDefaultInvoiceLineItem(string itemCode);
Dictionary<int, Model.Account.InvoiceLineItem> GetInvoiceLineItem(
IEnumerable<int> itemIds = null, IEnumerable<string> itemCodes = null, bool includeAccountInfo = true, bool includeTaxInfo = true
);
Dictionary<int, Model.Account.PurchaseInvoice> ReadPurchaseInvoice(IEnumerable<int> purchaseInvoiceIdList);
Dictionary<int, Model.Account.PurchaseInvoice.Line> ReadPurchaseInvoiceLine
(List<int> invoiceIdList, List<int> invoiceLineIdList, List<string> statusList, List<string> itemDescriptionList);
Dictionary<int, Model.Account.PurchaseInvoiceLineStatus> ReadPurchaseInvoiceLineStatus();
List<Model.Account.PurchaseInvoiceLineSummary> ReadPurchaseInvoiceLineSummary(DateTime periodTo, string lineStatus, List<string> descriptionSearch);
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database.Repository.Interface
{
internal interface 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);
}
}

View File

@@ -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 ISkuRepository
{
int? ReadSkuId(int productId, int conditionId, int accountTaxCodeId);
int InsertNewSku(int productId, int conditionId, int accountTaxCodeId);
}
}

View File

@@ -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 IStockRepository
{
List<Model.Stock.Status> ReadStatus(List<int> statusIds = null, List<int> statusTypeIds = null);
Dictionary<int, Model.Stock.StatusType> ReadStatusType();
}
}

View File

@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using Microsoft.Data.SqlClient;
namespace bnhtrade.Core.Data.Database.Sku
{
@@ -102,33 +102,7 @@ namespace bnhtrade.Core.Data.Database.Sku
/// <exception cref="Exception"></exception>
public int? ByParameters(int productId, int conditionId, int accountTaxCodeId)
{
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
int? returnId = null;
conn.Open();
using (SqlCommand cmd = new SqlCommand(@"
SELECT
tblSku.skuSkuID
FROM
tblSku
WHERE
(((tblSku.skuProductID)=@productId) AND ((tblSku.skuSkuConditionID)=@conditionId) AND ((tblSku.AccountTaxCodeID)=@accountTaxCodeId));
", conn))
{
cmd.Parameters.AddWithValue("@productId", productId);
cmd.Parameters.AddWithValue("@conditionId", conditionId);
cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId);
object obj = cmd.ExecuteScalar();
if (obj != null || obj == DBNull.Value)
{
returnId = (int)obj;
}
}
return returnId;
}
throw new NotSupportedException("This method is not supported in GetSkuId. Use SkuRepository instead.");
}
}
}

View File

@@ -1,85 +0,0 @@
using FikaAmazonAPI.AmazonSpApiSDK.Models.ProductPricing;
using System;
using System.Collections.Generic;
using Microsoft.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace bnhtrade.Core.Data.Database.Sku
{
internal class InsertSku : Connection
{
public int InsertNew(int productId, int conditionId, int accountTaxCodeId)
{
using (TransactionScope scope = new TransactionScope())
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
// check tax code id is a valid for SKU
var dbTax = new Data.Database.Account.ReadTaxCode();
var taxCodeList = dbTax.GetByTaxCodeId(new List<int> { accountTaxCodeId });
if (taxCodeList.ContainsKey(accountTaxCodeId) == false)
{
throw new Exception("AccountTaxCodeID=" + accountTaxCodeId + " doesn't exist!");
}
else if (taxCodeList[accountTaxCodeId].IsValidOnIncome == false)
{
throw new Exception("AccountTaxCodeID=" + accountTaxCodeId + " is not a valid type for an SKU.");
}
// get info to create sku number
int skuCount;
int skuSuffix;
using (SqlCommand cmd = new SqlCommand("SELECT NEXT VALUE FOR SkuCountSequence;", conn))
{
skuCount = (int)cmd.ExecuteScalar();
}
using (SqlCommand cmd = new SqlCommand(@"
SELECT tblSkuCondition.scnSkuNumberSuffix
FROM tblSkuCondition
WHERE (((tblSkuCondition.scnSkuConditionID)=@conditionId));
", conn))
{
cmd.Parameters.AddWithValue("@conditionId", conditionId);
try
{
skuSuffix = (int)cmd.ExecuteScalar();
}
catch (Exception ex)
{
throw new Exception("Error retriving SKU number suffix for SkuConditionID=" + conditionId + "." +
System.Environment.NewLine + "Error Message: " + ex.Message);
}
}
string skuNumber = skuCount.ToString("D6") + "-" + skuSuffix.ToString("D2");
// insert new sku
int skuId;
using (SqlCommand cmd = new SqlCommand(@"
INSERT INTO tblSku
(skuSkuNumber, skuProductID, skuSkuConditionID, AccountTaxCodeID)
OUTPUT INSERTED.skuSkuID
VALUES
(@skuNumber, @productId, @conditionId, @accountTaxCodeId)
", conn))
{
cmd.Parameters.AddWithValue("@skuNumber", skuNumber);
cmd.Parameters.AddWithValue("@productId", productId);
cmd.Parameters.AddWithValue("@conditionId", conditionId);
cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId);
skuId = (int)cmd.ExecuteScalar();
}
scope.Complete();
return skuId;
}
}
}
}

View File

@@ -0,0 +1,132 @@
using bnhtrade.Core.Data.Database._BoilerPlate;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database
{
internal class SqlUpdateBuilder
{
private Dictionary<string, int> _usedUpdateFields = new Dictionary<string, int>();
private Dictionary<string, object> _parameterList = new Dictionary<string, object>();
private string _tableName = string.Empty;
private int _parameterCount = 0;
private string _sqlUpdate = string.Empty;
private string _sqlWhere = string.Empty;
private bool _updateIsSet = false;
private bool _whereIsSet = false;
public SqlUpdateBuilder() { }
public void Innit()
{
_usedUpdateFields.Clear();
_parameterList.Clear();
_tableName = string.Empty;
_parameterCount = 0;
_sqlUpdate = string.Empty;
_sqlWhere = string.Empty;
_updateIsSet = false;
_whereIsSet = false;
}
public void SetTableName(string tableName)
{
if (string.IsNullOrEmpty(tableName))
{
throw new ArgumentException("Table name cannot be null or empty.", nameof(tableName));
}
_tableName = tableName;
}
public void AddUpdateArugment(string columnName, object newValue)
{
if (string.IsNullOrEmpty(columnName) || newValue == null)
{
throw new ArgumentException("Column name and new value cannot be null or empty.");
}
if (_usedUpdateFields.ContainsKey(columnName))
{
throw new ArgumentException($"Column '{columnName}' already exists in the update arguments.", nameof(columnName));
}
// add the update arguments to sql string and parameter list
if (_updateIsSet)
{
_sqlUpdate += @",
";
}
else
{
_updateIsSet = true;
}
_parameterCount++;
_sqlUpdate += columnName + " = @parameter" + _parameterCount;
_parameterList.Add("@parameter" + _parameterCount, newValue);
}
public void AddWhereArugment(string columnName, object value)
{
if (string.IsNullOrEmpty(columnName) || value == null)
{
throw new ArgumentException("Column name and new value cannot be null or empty.");
}
// add the where arguments to sql string and parameter list
if (_whereIsSet)
{
_sqlWhere += @",
";
}
else
{
_whereIsSet = true;
}
_parameterCount++;
_sqlWhere += columnName + " = @parameter" + _parameterCount;
_parameterList.Add("@parameter" + _parameterCount, value);
}
public string GetSqlString()
{
if (_updateIsSet == false || _whereIsSet == false || string.IsNullOrEmpty(_tableName))
{
throw new InvalidOperationException("Table name, update arguments, and where arguments must be set before generating SQL string.");
}
string sql = @"
UPDATE "+ _tableName + @"
SET " + _sqlUpdate + @"
WHERE " + _sqlWhere + ";";
return sql;
}
public void AddParametersToSqlCommand(System.Data.SqlClient.SqlCommand cmd)
{
if (_parameterList != null)
{
foreach (var item in _parameterList)
{
cmd.Parameters.AddWithValue(item.Key, item.Value);
}
}
}
public void AddParametersToSqlCommand(Microsoft.Data.SqlClient.SqlCommand cmd)
{
if (_parameterList != null)
{
foreach (var item in _parameterList)
{
cmd.Parameters.AddWithValue(item.Key, item.Value);
}
}
}
}
}

View File

@@ -63,6 +63,21 @@ namespace bnhtrade.Core.Data.Database
}
}
public bool ParameterListIsSet
{
get
{
if (ParameterList == null || ParameterList.Any() == false)
{
return false;
}
else
{
return true;
}
}
}
/// <summary>
/// Initialises the class
/// </summary>
@@ -154,7 +169,7 @@ namespace bnhtrade.Core.Data.Database
int listCount = distinctList.Count();
for (int i = 0; i < listCount; i++, parameterCount++)
for (int i = 0; i < listCount; i++)
{
if (i > 0)
{
@@ -170,15 +185,58 @@ namespace bnhtrade.Core.Data.Database
sqlWhere += " ( " + columnReference + " LIKE '%' + ";
string param = "@parameter" + parameterCount;
sqlWhere += param;
ParameterList.Add(param, distinctList[i]);
sqlWhere += " + '%' ) ";
sqlWhere = sqlWhere + GetSetParameter(distinctList[i]) + " + '%' ) ";
}
SqlWhereString = SqlWhereString + sqlWhere;
}
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;
}
public void IsEqualTo(string columnReference, string stringValue, string wherePrefix = null)
{
if (string.IsNullOrEmpty(stringValue) || string.IsNullOrEmpty(columnReference))
{
throw new Exception(wherePrefix + " IsEqualTo method requires a valid column reference and string value.");
}
string sqlWhereString = @"
";
if (wherePrefix != null)
{
sqlWhereString += wherePrefix;
}
sqlWhereString += " ( " + columnReference + " = " + GetSetParameter(stringValue) + " ) ";
SqlWhereString = SqlWhereString + sqlWhereString;
}
/// <summary>
/// Append an 'In' statement and parameter list to the class properties
/// </summary>
@@ -205,16 +263,14 @@ namespace bnhtrade.Core.Data.Database
sqlWhere += " " + columnReference + " IN ( ";
int listCount = distinctList.Count();
for (int i = 0; i < listCount; i++, parameterCount++)
for (int i = 0; i < listCount; i++)
{
if (i > 0)
{
sqlWhere += ", ";
}
string param = "@parameter" + parameterCount;
sqlWhere += param;
ParameterList.Add(param, distinctList[i]);
sqlWhere = sqlWhere + GetSetParameter(distinctList[i].ToString());
}
sqlWhere += " ) ";
@@ -298,5 +354,19 @@ namespace bnhtrade.Core.Data.Database
In(columnReference, objectList, wherePrefix);
}
/// <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>
/// <returns></returns>
private string GetSetParameter(string value)
{
parameterCount++;
string parameterString = "@parameter" + parameterCount;
ParameterList.Add(parameterString, value);
return parameterString;
}
}
}

View File

@@ -1,115 +0,0 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static bnhtrade.Core.Data.Database.Constants;
namespace bnhtrade.Core.Data.Database.Stock
{
internal class Status : Connection
{
private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder;
public List<int> StatusIds { get; set; }
public List<int> StatusTypeIds { get; set; }
public Status ()
{
Init();
}
public void Init()
{
sqlBuilder = new SqlWhereBuilder();
StatusIds = new List<int>();
StatusTypeIds = new List<int>();
}
public List<Model.Stock.Status> Read()
{
var returnList = new List<Model.Stock.Status>();
sqlBuilder.Init();
//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 (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
sqlBuilder.AddParametersToSqlCommand(cmd);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
var typeDict = new Data.Database.Stock.StatusType().Read();
while (reader.Read())
{
int statusId = reader.GetInt32(0);
int? statusCode = null;
if (!reader.IsDBNull(1)) { statusCode = reader.GetInt32(1); }
string stockStatus = reader.GetString(2);
int typeId = reader.GetInt32(3);
string reference = null;
if (!reader.IsDBNull(4)) { reference = reader.GetString(4); }
int? foreignKeyId = null;
if (!reader.IsDBNull(5)) { foreignKeyId = reader.GetInt32(5); }
bool isCreditOnly = reader.GetBoolean(6);
bool isClosed = reader.GetBoolean(7);
DateTime recordCreated = DateTime.SpecifyKind(reader.GetDateTime(8), DateTimeKind.Utc);
var newItem = new Model.Stock.Status(statusId
, statusCode
, stockStatus
, typeDict[typeId]
, reference
, foreignKeyId
, isCreditOnly
, isClosed
, recordCreated
);
returnList.Add(newItem);
}
}
}
}
}
return returnList;
}
}
}

View File

@@ -1,63 +0,0 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database.Stock
{
public class StatusType : Connection
{
public StatusType()
{
}
/// <summary>
/// Reads all Status Types from database
/// </summary>
/// <returns></returns>
public Dictionary<int, Model.Stock.StatusType> Read()
{
var returnDict = new Dictionary<int, Model.Stock.StatusType>();
// get all account info before we start
var accountDict = new Data.Database.Account.ReadAccountCode().All();
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(@"
SELECT [StockStatusTypeID]
,[StatusTypeName]
,[ForeignKeyType]
,[ReferenceType]
,[AccountChartOfID]
FROM [e2A].[dbo].[tblStockStatusType]
", conn))
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
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[accountId]);
returnDict.Add(statusTypeId, statusType);
}
}
}
}
return returnDict;
}
}
}

View File

@@ -8,7 +8,7 @@ using System.Configuration;
namespace bnhtrade.Core.Data.Database.UnitOfWork
{
internal class Connection
public class Connection
{
//protected readonly string SqlConnectionString;
private Model.Credentials.bnhtradeDB _dbCredentials;

View File

@@ -10,10 +10,16 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
internal interface IUnitOfWork : IDisposable
{
// Properties for repositories, add here for each repository
public ICurrencyRepository CurrencyRepository { get; }
IAccountCodeRepository AccountCodeRepository { get; }
IAccountTaxRepository AccountTaxRepository { get; }
ICurrencyRepository CurrencyRepository { get; }
IExportInvoiceRepository ExportInvoiceRepository { get; }
IImportAmazonRepository ImportAmazonRepository { get; }
IAmazonSettlementRepository AmazonSettlementRepository { get; }
IInvoiceRepository InvoiceRepository { get; }
IJournalRepository JournalRepository { get; }
ISequenceGenerator SequenceGenerator { get; }
ISkuRepository SkuRepository { get; }
IStockRepository StockRepository { get; }
// Methods to manage the transaction
void Commit();

View File

@@ -18,18 +18,60 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
private bool _disposed;
// Private field for lazy loading, add here for each repository
private IAccountCodeRepository _accountCodeRepository;
private IAccountTaxRepository _accountTaxRepository;
private IAmazonSettlementRepository _amazonSettlementRepository;
private ICurrencyRepository _currencyRepository;
private IExportInvoiceRepository _exportInvoiceRepository;
private IImportAmazonRepository _importAmazonRepository;
private IInvoiceRepository _invoiceRepository;
private IJournalRepository _journalRepository;
private ISequenceGenerator _sequenceGenerator;
private ISkuRepository _skuRepository;
private IStockRepository _stockRepository;
public UnitOfWork()
internal UnitOfWork()
{
_connection = new SqlConnection(this.SqlConnectionString);
_connection.Open();
_transaction = _connection.BeginTransaction();
}
public IAccountCodeRepository AccountCodeRepository
{
get
{
if (_accountCodeRepository == null)
{
_accountCodeRepository = new AccountCodeRepository(_connection, _transaction);
}
return _accountCodeRepository;
}
}
public IAccountTaxRepository AccountTaxRepository
{
get
{
if (_accountTaxRepository == null)
{
_accountTaxRepository = new AccountTaxRepository(_connection, _transaction);
}
return _accountTaxRepository;
}
}
public IAmazonSettlementRepository AmazonSettlementRepository
{
get
{
if (_amazonSettlementRepository == null)
{
_amazonSettlementRepository = new AmazonSettlementRepository(_connection, _transaction);
}
return _amazonSettlementRepository;
}
}
// Properties for repositories, add here for each repository
public ICurrencyRepository CurrencyRepository
{
@@ -55,15 +97,26 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
}
}
public IImportAmazonRepository ImportAmazonRepository
public IInvoiceRepository InvoiceRepository {
get
{
if (_invoiceRepository == null)
{
_invoiceRepository = new InvoiceRepository(_connection, _transaction);
}
return _invoiceRepository;
}
}
public IJournalRepository JournalRepository
{
get
{
if (_importAmazonRepository == null)
if (_journalRepository == null)
{
_importAmazonRepository = new ImportAmazonRepository(_connection, _transaction);
_journalRepository = new JournalRepository(_connection, _transaction);
}
return _importAmazonRepository;
return _journalRepository;
}
}
@@ -79,6 +132,30 @@ namespace bnhtrade.Core.Data.Database.UnitOfWork
}
}
public ISkuRepository SkuRepository
{
get
{
if (_skuRepository == null)
{
_skuRepository = new SkuRepository(_connection, _transaction);
}
return _skuRepository;
}
}
public IStockRepository StockRepository
{
get
{
if (_stockRepository == null)
{
_stockRepository = new StockRepository(_connection, _transaction);
}
return _stockRepository;
}
}
public void Commit()
{
try

View File

@@ -94,10 +94,8 @@ namespace bnhtrade.Core.Data.Xero
public string BrandingTheme { get; set; }
}
internal void ExportToCsv(List<Core.Model.Account.SalesInvoice> salesInvoiceList, int startingInvoiceNumber, string savePath, bool unitAmountIsTaxExclusive = true)
internal void ExportToCsv(List<Core.Model.Account.SalesInvoice> salesInvoiceList, string savePath, bool unitAmountIsTaxExclusive = true)
{
int invoiceNumberCount = startingInvoiceNumber;
// convert invoice to unitAmountIsTaxExclusive = true
foreach (var invoice in salesInvoiceList)
{
@@ -123,7 +121,7 @@ namespace bnhtrade.Core.Data.Xero
}
string contactName = invoice.ContactName;
string invoiceNumber = "INV-" + invoiceNumberCount.ToString("000000");
string invoiceNumber = invoice.InvoiceNumber;
string reference = invoice.InvoiceReference;
string invoiceDate = invoice.InvoiceDate.GetValueOrDefault().ToString("dd MMM yyyy", CultureInfo.InvariantCulture);
string dueDate = invoice.InvoiceDueDate.GetValueOrDefault().ToString("dd MMM yyyy", CultureInfo.InvariantCulture);
@@ -153,8 +151,6 @@ namespace bnhtrade.Core.Data.Xero
csvLineList.Add(csvLine);
}
invoiceNumberCount++;
}
var config = new CsvHelper.Configuration.CsvConfiguration(CultureInfo.CurrentCulture);

View File

@@ -6,18 +6,18 @@ using System.Threading.Tasks;
namespace bnhtrade.Core.Logic.Account
{
public class GetAccountCodeInfo
public class AccountCodeService : UnitOfWorkBase
{
private Data.Database.Account.ReadAccountCode readAccountCode;
public GetAccountCodeInfo()
public AccountCodeService()
{
readAccountCode = new Data.Database.Account.ReadAccountCode();
}
public Dictionary<uint, Model.Account.Account> GetAll()
public Dictionary<int, Model.Account.Account> GetAll()
{
return readAccountCode.All();
return WithUnitOfWork(uow =>
{
return uow.AccountCodeRepository.ReadAccountCode();
});
}
public Model.Account.Account ByAccountCode(int accountCode)
@@ -35,7 +35,10 @@ namespace bnhtrade.Core.Logic.Account
public List<Model.Account.Account> ByAccountCode(List<int> accountCodeList)
{
return readAccountCode.ByAccountCode(accountCodeList).Values.ToList();
return WithUnitOfWork(uow =>
{
return uow.AccountCodeRepository.ReadAccountCode(null, accountCodeList).Values.ToList();
});
}
public Dictionary<int, Model.Account.Account> ConvertToDictionary(List<Model.Account.Account> accountCodeList)

View File

@@ -3,21 +3,22 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace bnhtrade.Core.Logic.Account
{
public class GetTaxCodeInfo
public class GetTaxCodeInfo : UnitOfWorkBase
{
private Data.Database.Account.ReadTaxCode dbRead;
public GetTaxCodeInfo()
{
dbRead = new Data.Database.Account.ReadTaxCode();
}
public List<Model.Account.TaxCodeInfo> GetByTaxCode(List<string> taxCodeList)
{
return dbRead.GetByTaxCode(taxCodeList);
return WithUnitOfWork(uow =>
{
return uow.AccountTaxRepository.ReadTaxCodeInfo(null, taxCodeList).Values.ToList();
});
}
public Model.Account.TaxCodeInfo GetByTaxCode(string taxCode)
@@ -48,7 +49,11 @@ namespace bnhtrade.Core.Logic.Account
}
// get db list
var dbList = dbRead.GetTaxCodeBySkuNumber(skuNumberList);
var dbList = WithUnitOfWork(uow =>
{
return uow.AccountTaxRepository.GetTaxCodeBySkuNumber(skuNumberList);
});
// build dictionary
foreach (var item in dbList)

View File

@@ -1,4 +1,5 @@
using System;
using bnhtrade.Core.Data.Database.UnitOfWork;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -6,9 +7,17 @@ using System.Threading.Tasks;
namespace bnhtrade.Core.Logic.Account
{
public class InvoiceLineItemService
public class InvoiceLineItemService : UnitOfWorkBase
{
private Logic.Log.LogEvent log = new Logic.Log.LogEvent();
private Logic.Log.LogEvent _log = new Logic.Log.LogEvent();
public InvoiceLineItemService()
{
}
internal InvoiceLineItemService(IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
/// <summary>
/// Creates new 'default' item code entry. The item code and title are set, will require updating by user before use.
@@ -17,25 +26,32 @@ namespace bnhtrade.Core.Logic.Account
/// <returns></returns>
public Model.Account.InvoiceLineItem CreateNew(string itemCode)
{
new Data.Database.Account.CreateInvoiceLineItem().CreateDefault(itemCode);
var item = new Data.Database.Account.ReadInvoiceLineItem().ByItemCode(new List<string> { itemCode });
if (item == null || item.Count == 0)
return WithUnitOfWork(uow =>
{
log.LogError("InvoiceLineItemService.CreateNew", "Error creating new invoice line item in database for item code: " + itemCode);
throw new Exception("Error creating new invoice line item in database");
}
return item[0];
uow.InvoiceRepository.CreateDefaultInvoiceLineItem(itemCode);
var item = uow.InvoiceRepository.GetInvoiceLineItem(null, new List<string> { itemCode });
if (item == null || item.Count == 0)
{
_log.LogError("InvoiceLineItemService.CreateNew", "Error creating new invoice line item in database for item code: " + itemCode);
throw new Exception("Error creating new invoice line item in database");
}
CommitIfOwned(uow);
return item[0];
});
}
public Dictionary<string, Model.Account.InvoiceLineItem> GetLineItems(List<string> itemCodes)
{
var dbResult = new Data.Database.Account.ReadInvoiceLineItem().ByItemCode(itemCodes);
var returnDict = new Dictionary<string, Model.Account.InvoiceLineItem>();
foreach ( var item in dbResult)
return WithUnitOfWork(uow =>
{
returnDict.Add(item.Value.ItemCode, item.Value);
}
return returnDict;
var dbResult = uow.InvoiceRepository.GetInvoiceLineItem(null, itemCodes);
var returnDict = new Dictionary<string, Model.Account.InvoiceLineItem>();
foreach (var item in dbResult)
{
returnDict.Add(item.Value.ItemCode, item.Value);
}
return returnDict;
});
}
}
}

View File

@@ -8,7 +8,7 @@ using System.Transactions;
namespace bnhtrade.Core.Logic.Account
{
public class Journal
public class Journal : UnitOfWorkBase
{
public int AccountJournalInsert(int journalTypeId, DateTime entryDate, string currencyCode,
decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false)
@@ -19,7 +19,12 @@ namespace bnhtrade.Core.Logic.Account
public bool AccountJournalDelete(int accountJournalId)
{
return new Data.Database.Account.DeleteJournal().AccountJournalDelete(accountJournalId);
return WithUnitOfWork(uow =>
{
bool result = uow.JournalRepository.DeleteJournal(accountJournalId);
CommitIfOwned(uow);
return result;
});
}
}
}

View File

@@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Logic.Account
{
public class PurchaseInvoice
{
/// <summary>
/// Get purchase invoices by id
/// </summary>
/// <param name="purchaseIdList">purchase id list</param>
/// <returns>dictionary where key=id, value=purchaseinvoice</returns>
public Dictionary<int, Model.Account.PurchaseInvoice> GetPurchaseInvoice(IEnumerable<int> purchaseIdList)
{
var dbRead = new Data.Database.Account.ReadPurchaseInvoice();
dbRead.PurchaseInvoiceIdList = purchaseIdList;
return dbRead.Read();
}
}
}

View File

@@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Logic.Account
{
public class PurchaseInvoiceMisc
{
public List<Model.Account.PurchaseInvoiceLineStatus> ReadLineStatusToList()
{
return new Data.Database.Account.ReadPurchaseInvoiceLineStatus().Read().Values.ToList();
}
public List<Model.Account.PurchaseInvoiceLineSummary> GetLineSummary(DateTime maxDate, string lineStatus, List<string> wordSearchList)
{
return new Data.Database.Account.ReadPurchaseInvoiceLineSummary().Read(maxDate,lineStatus, wordSearchList);
}
}
}

View File

@@ -0,0 +1,55 @@
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.Account
{
public class PurchaseInvoiceService : UnitOfWorkBase
{
public PurchaseInvoiceService() { }
internal PurchaseInvoiceService(IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
/// <summary>
/// Get purchase invoices by id
/// </summary>
/// <param name="purchaseIdList">purchase id list</param>
/// <returns>dictionary where key=id, value=purchaseinvoice</returns>
public Dictionary<int, Model.Account.PurchaseInvoice> GetPurchaseInvoice(IEnumerable<int> purchaseIdList)
{
return WithUnitOfWork(uow =>
{
var invoiceRepository = uow.InvoiceRepository;
var returnList = invoiceRepository.ReadPurchaseInvoice(purchaseIdList);
return returnList;
});
}
public List<Model.Account.PurchaseInvoiceLineStatus> ReadLineStatusToList()
{
return WithUnitOfWork(uow =>
{
var invoiceRepository = uow.InvoiceRepository;
var returnList = invoiceRepository.ReadPurchaseInvoiceLineStatus().Values.ToList();
return returnList;
});
}
public List<Model.Account.PurchaseInvoiceLineSummary> GetLineSummary(DateTime maxDate, string lineStatus, List<string> wordSearchList)
{
return WithUnitOfWork(uow =>
{
var invoiceRepository = uow.InvoiceRepository;
var returnList = invoiceRepository.ReadPurchaseInvoiceLineSummary(maxDate, lineStatus, wordSearchList);
return returnList;
});
}
}
}

View File

@@ -1,5 +1,6 @@
using Amazon.SQS.Model.Internal.MarshallTransformations;
using bnhtrade.Core.Data.Database.UnitOfWork;
using bnhtrade.Core.Model.Account;
using bnhtrade.Core.Model.Amazon;
using bnhtrade.Core.Test.Export;
using FikaAmazonAPI.ReportGeneration.ReportDataTable;
@@ -17,24 +18,18 @@ using static bnhtrade.Core.Model.Import.AmazonSettlement;
namespace bnhtrade.Core.Logic.Export.AccountInvoice
{
internal class AmazonSettlement : Data.Database.Connection
internal class AmazonSettlement : UnitOfWorkBase
{
private readonly IUnitOfWork _providedUnitOfWork = null;
private readonly bool _ownsUnitOfWork = false;
private Logic.Log.LogEvent _log = new Logic.Log.LogEvent();
private List<string> _lineItemCodeList = new List<string>();
private bool _settlementAmountIsTaxExclusive = false; // i.e. they're tax inclusive
public AmazonSettlement()
{
_ownsUnitOfWork = true;
}
internal AmazonSettlement(IUnitOfWork unitOfWork)
internal AmazonSettlement(IUnitOfWork unitOfWork) : base(unitOfWork)
{
_providedUnitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
_ownsUnitOfWork = false;
}
public string ErrorMessage { get; private set; }
@@ -53,34 +48,34 @@ namespace bnhtrade.Core.Logic.Export.AccountInvoice
Init();
_log.LogInformation("Starting processing of Amazon settlement data into export invoice table...");
// get list of unprocessed settlement reports to export
var settlementList = GetListOfUnprocessedSettlementReports();
if (settlementList == null)
return WithUnitOfWork(uow =>
{
return false;
}
// get list of unprocessed settlement reports to export
var settlementList = GetUnprocessedSettlementReports(uow, true);
if (settlementList == null)
{
return false;
}
// create list of settlement ids for later use
var settlementIdList = new List<string>();
foreach (var settlement in settlementList)
{
settlementIdList.Add(settlement.SettlementId);
}
// create list of settlement ids for later use
var settlementIdList = new List<string>();
foreach (var settlement in settlementList)
{
settlementIdList.Add(settlement.SettlementId);
}
// create list of invoices from settlement reports
var invoiceList = CreateInvoices(settlementList, convertToGbp);
if (invoiceList == null || invoiceList.Any() == false)
{
return false;
}
// create list of invoices from settlement reports
var invoiceList = CreateInvoices(settlementList, convertToGbp);
if (invoiceList == null || invoiceList.Any() == false)
{
return false;
}
// add invoice to export queue and set settlements as processed
Console.Write("\rWriting to database... ");
using (UnitOfWork unitOfWork = new UnitOfWork())
{
// add invoice to export queue and set settlements as processed
Console.Write("\rWriting to database... ");
try
{
var queueService = new Logic.Export.AccountInvoice.QueueService(unitOfWork);
var queueService = new Logic.Export.AccountInvoice.QueueService(uow);
// add temp invoice numbers
queueService.AddTempInvoiceNumber(invoiceList, true);
@@ -89,12 +84,15 @@ namespace bnhtrade.Core.Logic.Export.AccountInvoice
if (queueService.ErrorMessageIsSet == false && queueInsertResult.Count() == invoiceList.Count())
{
// set settlements to isprocessed
unitOfWork.ImportAmazonRepository.SetAmazonSettlementIsProcessed(settlementIdList, true);
unitOfWork.Commit();
uow.AmazonSettlementRepository.UpdateAmazonSettlementIsProcessed(settlementIdList, true);
uow.Commit();
Console.Write("\r");
_log.LogInformation("\rFinished processing of Amazon settlement data. " + invoiceList.Count() + " invoices created from " + settlementIdList.Count() + " Amazon settlement reports.");
return true;
}
else
{
unitOfWork.Rollback();
uow.Rollback();
string error = queueService.ErrorMessage;
ErrorMessage = "Cancelled processing of Amazon settlement data into export invoice table. " + error;
_log.LogInformation("Cancelled processing of Amazon settlement data into export invoice table...");
@@ -109,115 +107,115 @@ namespace bnhtrade.Core.Logic.Export.AccountInvoice
_log.LogInformation("Cancelled processing of Amazon settlement data into export invoice table...");
return false;
}
}
Console.Write("\r");
_log.LogInformation("\rFinished processing of Amazon settlement data. " + invoiceList.Count() + " invoices created from " + settlementIdList.Count() + " Amazon settlement reports.");
return true;
});
}
/// <summary>
/// Retrives a list of unprocessed settlement reports from the database, checks for gaps in settlement periods, and validates
/// the settlement data.
/// </summary>
/// <param name="newMarketplaceNameList">Import will fail on new marketplace, add here to bypass this check</param>
/// <param name="updateNullMarketplaceByCurrency">Insert 'Amazon.co.uk' if the market place name is missing and the currecy is GBP</param>
/// <returns></returns>
private List<Model.Import.AmazonSettlement> GetListOfUnprocessedSettlementReports()
private List<Model.Import.AmazonSettlement> GetUnprocessedSettlementReports(IUnitOfWork uow, bool updateNullMarketplaceByCurrency = true)
{
List<Model.Import.AmazonSettlement> settlementList = null;
IUnitOfWork currentUow = null;
if (_ownsUnitOfWork)
// get list of unprocessed settlement reports to export
settlementList = uow.AmazonSettlementRepository.ReadAmazonSettlements(null, null, false).Values.ToList();
if (settlementList.Any() == false)
{
currentUow = new UnitOfWork();
}
else
{
currentUow = _providedUnitOfWork;
ErrorMessage = "No new settlement reports to process";
return null;
}
// get list of unprocssed settlement reports to export
using (currentUow != null && _ownsUnitOfWork ? currentUow : null)
// test marketplace-name has been sucsessfully entered into settlement table --
// as this is not supplied in the original report from Amazon and has to be inferred from settlement line data or added below
// via currency (null marketplace anme is not picked up in validate stage as null value is valid)
foreach (var settlement in settlementList)
{
settlementList = currentUow.ImportAmazonRepository.ReadAmazonSettlements(null, null, false).Values.ToList();
if (settlementList.Any() == false)
if (settlement.MarketPlaceNameIsSet == false && updateNullMarketplaceByCurrency && settlement.CurrencyCode == CurrencyCode.GBP.ToString())
{
ErrorMessage = "No new settlement reports to process";
// update database with market place name
uow.AmazonSettlementRepository.UpdateAmazonSettlementMarketPlaceName(
settlement.SettlementId
, MarketPlaceEnum.AmazonUK
);
// add to settlement
settlement.MarketPlace = MarketPlaceEnum.AmazonUK;
}
else if (settlement.MarketPlaceNameIsSet == false)
{
string error = "User action required: Enter market place name for amazon settlelment report id:" + settlement.SettlementId + ".";
ErrorMessage = "Cancelled processing of Amazon settlement data into export invoice table: " + error;
_log.LogError(
error
, "Unable to process settlement data from report '" + settlement.SettlementId +
"'. Report header table requires a market place name, which is not supplied in original " +
"report from Amazon. This is useually inferred from settlement lines. " +
"However, in this case, it was not not possible. Manual edit/entry for database table required."
);
_log.LogInformation("Cancelled processing of Amazon settlement data into export invoice table...");
return null;
}
}
// test marketplace-name has been sucsessfully entered into settlement table --
// as this is not supplied in the original report from Amazon and has to be inferred from settlement line data
// this is not picked up in validate stage as null value is valid
foreach (var settlement in settlementList)
// check for time gaps between settlement periods
settlementList = settlementList.OrderBy(x => x.MarketPlace).ThenBy(x => x.StartDate).ToList();
for (var i = 0; i < settlementList.Count; i++)
{
// first marketplace of type in list? retrive the previously completed settlement for that marketplace to compare datetimes
if (i == 0 || settlementList[i].MarketPlace != settlementList[i - 1].MarketPlace)
{
if (settlement.MarketPlaceNameIsSet == false)
// get previously completed settlement for this marketplace
var completedSettlement = uow.AmazonSettlementRepository.ReadAmazonSettlements(
null, new List<string> { settlementList[i].MarketPlace.GetMarketplaceUrl() }, true, true, 1);
if (completedSettlement.Any())
{
string error = "User action required: Enter market place name for amazon settlelment report id:" + settlement.SettlementId + ".";
ErrorMessage = "Cancelled processing of Amazon settlement data into export invoice table: " + error;
_log.LogError(
error
, "Unable to process settlement data from report '" + settlement.SettlementId +
"'. Report header table requires a market place name, which is not supplied in original " +
"report from Amazon. This is useually inferred from settlement lines. " +
"However, in this case, it was not not possible. Manual edit/entry for database table required."
);
_log.LogInformation("Cancelled processing of Amazon settlement data into export invoice table...");
return null;
}
}
// check for time gaps between settlement periods
settlementList = settlementList.OrderBy(x => x.MarketPlace).ThenBy(x => x.StartDate).ToList();
for (var i = 0; i < settlementList.Count; i++)
{
// first marketplace of type in list? retrive the previously completed settlement for that marketplace to compare datetimes
if (i == 0 || settlementList[i].MarketPlace != settlementList[i - 1].MarketPlace)
{
// get previously completed settlement for this marketplace
var completedSettlement = currentUow.ImportAmazonRepository.ReadAmazonSettlements(
null, new List<string> { settlementList[i].MarketPlace.GetMarketplaceUrl() }, true, true, 1);
if (completedSettlement.Any())
{
if (completedSettlement.FirstOrDefault().Value.EndDate != 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")
+ " 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);
return null;
}
}
else
{
// first settlement for this marketplace, no previous settlement to compare against
// continue on
}
}
else
{
if (settlementList[i - 1].EndDate != settlementList[i].StartDate)
if (completedSettlement.FirstOrDefault().Value.EndDate != settlementList[i].StartDate)
{
string error = (settlementList[i].StartDate - settlementList[i - 1].EndDate).Days + " day gap in "
+ settlementList[i].MarketPlace + " settlement data (" + settlementList[i - 1].EndDate.ToString("dd MMM yyyy")
+ settlementList[i].MarketPlace.GetMarketplaceUrl() + " settlement data (" + settlementList[i - 1].EndDate.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);
return null;
}
}
else
{
// first settlement for this marketplace, no previous settlement to compare against
// continue on
}
}
else
{
if (settlementList[i - 1].EndDate != settlementList[i].StartDate)
{
string error = (settlementList[i].StartDate - settlementList[i - 1].EndDate).Days + " day gap in "
+ settlementList[i].MarketPlace + " settlement data (" + settlementList[i - 1].EndDate.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);
return null;
}
}
}
// validate settlelments
if (settlementList == null || settlementList.Any() == false)
{
_log.LogInformation("No new settlement reports to process.");
return null;
}
// validate settlements
var validate = new Logic.Validate.AmazonSettlement();
foreach (var settlement in settlementList)
{
if (!validate.IsValid(settlement))
{
_log.LogError("Error procesing Amazon Settlement data for export.", validate.ValidationResultListToString());
_log.LogError("Error processing Amazon Settlement data for export.", validate.ValidationResultListToString());
}
}
if (validate.IsValidResult == false)

View File

@@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Logic.Export.AccountInvoice
{
internal class InvoiceService
{
}
}

View File

@@ -15,22 +15,17 @@ namespace bnhtrade.Core.Logic.Export.AccountInvoice
/// <summary>
/// Processes the Export Invoice table and exports to Xero
/// </summary>
public class QueueService
public class QueueService : UnitOfWorkBase
{
private Log.LogEvent _log = new Log.LogEvent();
private IEnumerable<int> _exportSaleInvoiceIdList = new List<int>();
private readonly IUnitOfWork _providedUnitOfWork = null;
private readonly bool _ownsUnitOfWork = false;
private UnitOfWork _exportUow = null;
public QueueService()
{
_ownsUnitOfWork = true;
}
internal QueueService(IUnitOfWork unitOfWork)
internal QueueService(IUnitOfWork unitOfWork) : base(unitOfWork)
{
_providedUnitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
_ownsUnitOfWork = false;
}
public string ErrorMessage { get; private set; } = null;
@@ -64,26 +59,11 @@ namespace bnhtrade.Core.Logic.Export.AccountInvoice
{
Init();
IUnitOfWork currentUow = null;
if (_ownsUnitOfWork)
{
currentUow = new UnitOfWork();
}
else
{
currentUow = _providedUnitOfWork;
}
string result = null;
using (currentUow != null && _ownsUnitOfWork ? currentUow : null)
return WithUnitOfWork(uow =>
{
result = "_tmp" + currentUow.SequenceGenerator.GetNext("ExportTempInvoiceNumber").ToString("00000000");
if (_ownsUnitOfWork)
{
currentUow.Commit();
}
}
return result;
return "_tmp" + uow.SequenceGenerator.GetNext("ExportTempInvoiceNumber").ToString("00000000");
});
}
public void AddTempInvoiceNumber(IEnumerable<Model.Account.IInvoice> invoiceList, bool overwriteExisting)
@@ -110,30 +90,26 @@ namespace bnhtrade.Core.Logic.Export.AccountInvoice
{
Init();
IUnitOfWork currentUow = null;
if (_ownsUnitOfWork)
return WithUnitOfWork(uow =>
{
currentUow = new UnitOfWork();
}
else
{
currentUow = _providedUnitOfWork;
}
using (_ownsUnitOfWork ? currentUow : null)
{
var returnList = currentUow.ExportInvoiceRepository.GetSalesInvoiceById(invoiceIdList);
var validate = new Logic.Validate.Invoice();
bool isValid = validate.IsValidExportInvoice(returnList.Values.ToList());
return ReadInvoiceById(uow, invoiceIdList);
});
}
if (isValid == false)
{
ErrorMessage = "Reading invoices from database failed validation. See logs for further details.";
_log.LogError("ErrorMessage", validate.ValidationResultListToString());
throw new Exception(ErrorMessage);
}
private Dictionary<int, Model.Account.SalesInvoice> ReadInvoiceById(IUnitOfWork uow, IEnumerable<int> invoiceIdList)
{
var returnList = uow.ExportInvoiceRepository.GetSalesInvoiceById(invoiceIdList);
var validate = new Logic.Validate.Invoice();
bool isValid = validate.IsValidExportInvoice(returnList.Values.ToList());
return returnList;
if (isValid == false)
{
ErrorMessage = "Reading invoices from database failed validation. See logs for further details.";
_log.LogError("ErrorMessage", validate.ValidationResultListToString());
throw new Exception(ErrorMessage);
}
return returnList;
}
/// <summary>
@@ -158,25 +134,12 @@ namespace bnhtrade.Core.Logic.Export.AccountInvoice
validateInvoice = null;
// save to database
IUnitOfWork currentUow = null;
if (_ownsUnitOfWork)
return WithUnitOfWork(uow =>
{
currentUow = new UnitOfWork();
}
else
{
currentUow = _providedUnitOfWork;
}
using (currentUow != null && _ownsUnitOfWork ? currentUow : null)
{
var result = currentUow.ExportInvoiceRepository.InsertSalesInvoices(invoiceList);
if (_ownsUnitOfWork)
{
currentUow.Commit();
}
var result = uow.ExportInvoiceRepository.InsertSalesInvoices(invoiceList);
CommitIfOwned(uow);
return result;
}
});
}
/// <summary>
@@ -187,25 +150,10 @@ namespace bnhtrade.Core.Logic.Export.AccountInvoice
{
Init();
IUnitOfWork currentUow = null;
if (_ownsUnitOfWork)
return WithUnitOfWork(uow =>
{
currentUow = new UnitOfWork();
}
else
{
currentUow = _providedUnitOfWork;
}
using (currentUow != null && _ownsUnitOfWork ? currentUow : null)
{
var result = currentUow.ExportInvoiceRepository.GetNewInvoiceNumbers(invoiceType).Count();
if (_ownsUnitOfWork)
{
currentUow.Commit();
}
return result;
}
return uow.ExportInvoiceRepository.GetNewInvoiceNumbers(invoiceType).Count();
});
}
/// <summary>
@@ -213,80 +161,45 @@ namespace bnhtrade.Core.Logic.Export.AccountInvoice
/// </summary>
/// <param name="filePath"></param>
/// <param name="firstInvoiceNumber"></param>
public void ExportSalesInvoice(string filePath, int firstInvoiceNumber)
public bool ExportSalesInvoice(string filePath, int firstInvoiceNumber, Func<bool> getUserConfirmation)
{
Init();
IUnitOfWork currentUow = null;
if (_ownsUnitOfWork)
{
currentUow = new UnitOfWork();
}
else
{
currentUow = _providedUnitOfWork;
}
using (currentUow != null && _ownsUnitOfWork ? currentUow : null)
return WithUnitOfWork(uow =>
{
var invoiceType = Model.Account.InvoiceType.Sale;
var idList = currentUow.ExportInvoiceRepository.GetNewInvoiceNumbers(invoiceType);
_exportSaleInvoiceIdList = idList.Keys.ToList();
var invoiceList = ReadInvoiceById(idList.Keys.ToList());
// get list of unprocessed invoices
var newInvoiceIdDict = uow.ExportInvoiceRepository.GetNewInvoiceNumbers(invoiceType);
// update db entries with invoice numbers and set to iscompleted=true
foreach (var newInvoiceId in newInvoiceIdDict)
{
string invoiceNumber = "INV-" + firstInvoiceNumber.ToString("000000");
uow.ExportInvoiceRepository.UpdateInvoiceHeaderDetail(newInvoiceId.Key, invoiceNumber, true);
firstInvoiceNumber++;
}
// read invoices from database
var invoiceList = ReadInvoiceById(uow, newInvoiceIdDict.Keys.ToList());
var exportToFile = new Data.Xero.SalesInvoice();
exportToFile.ExportToCsv(invoiceList.Values.ToList(), firstInvoiceNumber, filePath);
}
}
exportToFile.ExportToCsv(invoiceList.Values.ToList(), filePath);
/// <summary>
/// Call this after ExportSalesInvoice() to mark exported invoices as complete
/// </summary>
/// <returns>number of invoices effected</returns>
public int? ExportSalesInvoiceIsComplete()
{
Init();
// get user confitmation before marking as exported
bool userInput = getUserConfirmation.Invoke();
if (_exportSaleInvoiceIdList.Any() == false)
{
ErrorMessage = "Nothing to set as complete, did you call the ExportSalesInvoice method first?";
return null;
}
var parameters = new Dictionary<int, bool>();
foreach (var id in _exportSaleInvoiceIdList)
{
parameters.Add(id, true);
}
// update database
IUnitOfWork currentUow = null;
if (_ownsUnitOfWork)
{
currentUow = new UnitOfWork();
}
else
{
currentUow = _providedUnitOfWork;
}
using (currentUow != null && _ownsUnitOfWork ? currentUow : null)
{
int count = currentUow.ExportInvoiceRepository.SetInvoiceIsCompleteValue(parameters);
if (_exportSaleInvoiceIdList.Count() == count)
if (userInput == false)
{
currentUow.Commit();
return count;
RollbackIfOwned(uow);
ErrorMessage = "User cancelled export, invoices not marked as exported.";
_log.LogInformation(ErrorMessage);
return false;
}
else
{
currentUow.Rollback();
ErrorMessage = "ExportSalesInvoiceIsComplete() Incorrect number of rows updated, changes rolled back.";
_log.LogError(ErrorMessage);
throw new Exception(ErrorMessage);
}
}
CommitIfOwned(uow);
return true;
});
}
}
}

View File

@@ -5,43 +5,26 @@ using System.Linq;
namespace bnhtrade.Core.Logic.Import
{
public class AmazonSettlement
public class AmazonSettlement : UnitOfWorkBase
{
private readonly IUnitOfWork _providedUnitOfWork = null;
private readonly bool _ownsUnitOfWork = false;
private Data.Amazon.Report.SettlementReport amazonReport;
private Logic.Log.LogEvent log = new Log.LogEvent();
public AmazonSettlement()
{
_ownsUnitOfWork = true;
}
internal AmazonSettlement(IUnitOfWork unitOfWork)
internal AmazonSettlement(IUnitOfWork unitOfWork) : base(unitOfWork)
{
_providedUnitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
_ownsUnitOfWork = false;
}
public void SyncDatabase()
{
string operation = "Import Amazon Settlement Reports";
log.LogInformation("Started '" + operation + "' operation.");
var amazonReport = new Data.Amazon.Report.SettlementReport();
// get avaiable reports from amazon api
IUnitOfWork currentUow = null;
if (_ownsUnitOfWork)
{
currentUow = new UnitOfWork();
}
else
{
currentUow = _providedUnitOfWork;
}
using (currentUow != null && _ownsUnitOfWork ? currentUow : null)
WithUnitOfWork(uow =>
{
// get avaiable reports from amazon api
var spapiReportIdList = amazonReport.ListAvaliableReports();
@@ -54,7 +37,7 @@ namespace bnhtrade.Core.Logic.Import
}
// query db and remove reports that have already been imported
var dbReportList = currentUow.ImportAmazonRepository.ReadAmazonSettlementHeaderInfoBySpapiReportId(spapiReportIdList);
var dbReportList = uow.AmazonSettlementRepository.ReadAmazonSettlementHeaderInfoBySpapiReportId(spapiReportIdList);
foreach (var dbReport in dbReportList)
{
if (dbReport.SpapiReportIdIsSet)
@@ -82,16 +65,12 @@ namespace bnhtrade.Core.Logic.Import
{
UI.Console.WriteLine("Importing settlement report " + (i + 1) + " of " + spapiReportIdList.Count() + " (ReportID:" + spapiReportIdList[i] + ").");
var filePath = amazonReport.GetReportFile(spapiReportIdList[i]);
bool ack = currentUow.ImportAmazonRepository.CreateAmazonSettlements(filePath, spapiReportIdList[i]);
bool ack = uow.AmazonSettlementRepository.CreateAmazonSettlements(filePath, spapiReportIdList[i]);
log.LogInformation("Settlment Report imported (ReportID:" + spapiReportIdList[i] + ").");
}
if (_ownsUnitOfWork)
{
currentUow.Commit();
}
return;
}
CommitIfOwned(uow);
});
}
}
}

View File

@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Transactions;
using System.Windows.Forms;
namespace bnhtrade.Core.Logic.Sku
{
public class GetSkuId
public class SkuService : UnitOfWorkBase
{
/// <summary>
/// Used for retriving an SKU ID by parameters. If no match, can create a new SKU if required.
@@ -15,11 +17,11 @@ namespace bnhtrade.Core.Logic.Sku
/// <param name="noMatchCreateNew">When set to true, if no match is made, function will create a new sku and return the id for that</param>
/// <returns>Return the id for the new or existing sku or, dependant on set parameters, 0 if not found</returns>
/// <exception cref="Exception"></exception>
public int Request(int productId, int conditionId, int accountTaxCodeId, bool noMatchCreateNew)
public int GetSkuId(int productId, int conditionId, int accountTaxCodeId, bool noMatchCreateNew)
{
using (TransactionScope scope = new TransactionScope())
return WithUnitOfWork(uow =>
{
int? skuId = new Data.Database.Sku.GetSkuId().ByParameters(productId, conditionId, accountTaxCodeId);
int? skuId = uow.SkuRepository.ReadSkuId(productId, conditionId, accountTaxCodeId);
if (skuId != null)
{
return (int)skuId;
@@ -30,9 +32,11 @@ namespace bnhtrade.Core.Logic.Sku
}
else
{
return new Data.Database.Sku.InsertSku().InsertNew(productId, conditionId, accountTaxCodeId);
int newSkuId = uow.SkuRepository.InsertNewSku(productId, conditionId, accountTaxCodeId);
CommitIfOwned(uow);
return newSkuId;
}
}
});
}
}
}

View File

@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace bnhtrade.Core.Logic.Stock
{
public class StatusBalance
public class StatusBalance : UnitOfWorkBase
{
public StatusBalance()
{
@@ -35,91 +35,93 @@ namespace bnhtrade.Core.Logic.Stock
/// <returns></returns>
public Model.Stock.StatusBalance GetStatusBalance(string skuNumber, int statusId, bool includeDetails = true)
{
if (string.IsNullOrWhiteSpace(skuNumber))
// need to enroll moree of the code into the unit of work as I redo the database layer
return WithUnitOfWork(uow =>
{
throw new Exception("SKU number is null, empty, or whitespace");
}
// get list of transactions for availale stock
var readStatusTransaction = new Data.Database.Stock.ReadStatusTransaction();
var statusTransaction = readStatusTransaction.BySku(statusId, skuNumber);
// create quantity list
List<int> qtyList = new List<int>();
for (int i = 0; i < statusTransaction.TransactionList.Count; i++)
{
qtyList.Add(statusTransaction.TransactionList[i].Quantity);
}
// tally list
// loop, in reverse, to find credits to tally with debits
for (int iCr = qtyList.Count - 1; iCr > -1; iCr--)
{
if (qtyList[iCr] < 0)
if (string.IsNullOrWhiteSpace(skuNumber))
{
int crStockNumber = statusTransaction.TransactionList[iCr].StockNumber;
DateTime crDate = statusTransaction.TransactionList[iCr].EntryDate;
throw new Exception("SKU number is null, empty, or whitespace");
}
// loop, in reverse, to find debits
for (int iDr = qtyList.Count - 1; iDr > -1; iDr--)
// get list of transactions for availale stock
var readStatusTransaction = new Data.Database.Stock.ReadStatusTransaction(); // ambient uow open above
var statusTransaction = readStatusTransaction.BySku(statusId, skuNumber); // ambient uow open above
// create quantity list
List<int> qtyList = new List<int>();
for (int i = 0; i < statusTransaction.TransactionList.Count; i++)
{
qtyList.Add(statusTransaction.TransactionList[i].Quantity);
}
// tally list
// loop, in reverse, to find credits to tally with debits
for (int iCr = qtyList.Count - 1; iCr > -1; iCr--)
{
if (qtyList[iCr] < 0)
{
// find debits, last in first out (filter by date)
if (statusTransaction.TransactionList[iDr].StockNumber == crStockNumber
&& statusTransaction.TransactionList[iDr].EntryDate <= crDate
&& qtyList[iDr] > 0)
int crStockNumber = statusTransaction.TransactionList[iCr].StockNumber;
DateTime crDate = statusTransaction.TransactionList[iCr].EntryDate;
// loop, in reverse, to find debits
for (int iDr = qtyList.Count - 1; iDr > -1; iDr--)
{
// credit fully assigned
if ((qtyList[iCr] + qtyList[iDr]) >= 0)
// find debits, last in first out (filter by date)
if (statusTransaction.TransactionList[iDr].StockNumber == crStockNumber
&& statusTransaction.TransactionList[iDr].EntryDate <= crDate
&& qtyList[iDr] > 0)
{
qtyList[iDr] = qtyList[iDr] + qtyList[iCr];
qtyList[iCr] = 0;
break;
}
// credit partially assigned
else
{
qtyList[iCr] = qtyList[iDr] + qtyList[iCr];
qtyList[iDr] = 0;
// credit fully assigned
if ((qtyList[iCr] + qtyList[iDr]) >= 0)
{
qtyList[iDr] = qtyList[iDr] + qtyList[iCr];
qtyList[iCr] = 0;
break;
}
// credit partially assigned
else
{
qtyList[iCr] = qtyList[iDr] + qtyList[iCr];
qtyList[iDr] = 0;
}
}
}
}
}
}
// build result list from tally results
var entryList = new List<(DateTime EntryDate, int StockNumber, int Quantity)>();
for (int i = 0; i < qtyList.Count; i++)
{
if (qtyList[i] != 0)
// build result list from tally results
var entryList = new List<(DateTime EntryDate, int StockNumber, int Quantity)>();
for (int i = 0; i < qtyList.Count; i++)
{
(DateTime EntryDate, int StockNumber, int Quantity) entryItem = (
statusTransaction.TransactionList[i].EntryDate,
statusTransaction.TransactionList[i].StockNumber,
qtyList[i]);
entryList.Add(entryItem);
if (qtyList[i] != 0)
{
(DateTime EntryDate, int StockNumber, int Quantity) entryItem = (
statusTransaction.TransactionList[i].EntryDate,
statusTransaction.TransactionList[i].StockNumber,
qtyList[i]);
entryList.Add(entryItem);
}
}
}
if (includeDetails)
{
// get the sku obj
var readSku = new Logic.Sku.GetSkuInfo();
readSku.IncludeConditionInfo = true;
readSku.IncludeProductInfo = true;
readSku.IncludeTaxCodeInfo = true;
var sku = readSku.BySkuNumber(statusTransaction.SkuNumber);
if (includeDetails)
{
// get the sku obj
var readSku = new Logic.Sku.GetSkuInfo(); // ambient uow open above
readSku.IncludeConditionInfo = true;
readSku.IncludeProductInfo = true;
readSku.IncludeTaxCodeInfo = true;
var sku = readSku.BySkuNumber(statusTransaction.SkuNumber);
// get the status obj
var readStatus = new Data.Database.Stock.Status();
readStatus.StatusIds = new List<int> { statusTransaction.StockStatusId };
var status = readStatus.Read()[0];
// get the status obj
var status = uow.StockRepository.ReadStatus(new List<int> { statusTransaction.StockStatusId })[0];
return new Model.Stock.StatusBalance(status, sku, entryList);
}
else
{
return new Model.Stock.StatusBalance(statusTransaction.StockStatusId, statusTransaction.SkuNumber, entryList);
}
return new Model.Stock.StatusBalance(status, sku, entryList);
}
else
{
return new Model.Stock.StatusBalance(statusTransaction.StockStatusId, statusTransaction.SkuNumber, entryList);
}
});
}
/// <summary>

View File

@@ -0,0 +1,76 @@
using bnhtrade.Core.Data.Database.UnitOfWork;
using System;
namespace bnhtrade.Core.Logic
{
public abstract class UnitOfWorkBase
{
private readonly IUnitOfWork _providedUnitOfWork;
private readonly bool _ownsUnitOfWork;
protected UnitOfWorkBase()
{
_ownsUnitOfWork = true;
}
internal UnitOfWorkBase(IUnitOfWork unitOfWork)
{
_providedUnitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
_ownsUnitOfWork = false;
}
/// <summary>
/// Executes an action with a managed UnitOfWork, handling disposal and commit if owned.
/// </summary>
internal void WithUnitOfWork(Action<IUnitOfWork> action)
{
IUnitOfWork currentUow = _ownsUnitOfWork ? new UnitOfWork() : _providedUnitOfWork;
try
{
action(currentUow);
}
finally
{
if (_ownsUnitOfWork && currentUow is IDisposable disposable)
disposable.Dispose();
}
}
/// <summary>
/// Executes a function with a managed UnitOfWork, handling disposal and commit if owned.
/// </summary>
internal T WithUnitOfWork<T>(Func<IUnitOfWork, T> func)
{
IUnitOfWork currentUow = _ownsUnitOfWork ? new UnitOfWork() : _providedUnitOfWork;
try
{
return func(currentUow);
}
finally
{
if (_ownsUnitOfWork && currentUow is IDisposable disposable)
disposable.Dispose();
}
}
/// <summary>
/// Executes an action with a managed UnitOfWork, committing if owned.
/// </summary>
/// <param name="uow"></param>
internal void CommitIfOwned(IUnitOfWork uow)
{
if (_ownsUnitOfWork)
uow.Commit();
}
/// <summary>
/// Executes an action with a managed UnitOfWork, rolling back if owned.
/// </summary>
/// <param name="uow"></param>
internal void RollbackIfOwned(IUnitOfWork uow)
{
if (_ownsUnitOfWork)
uow.Rollback();
}
}
}

View File

@@ -1,53 +0,0 @@
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._BoilerPlate
{
internal class UnitOfWorkPattern
{
private readonly IUnitOfWork _providedUnitOfWork = null;
private readonly bool _ownsUnitOfWork = false;
public UnitOfWorkPattern()
{
_ownsUnitOfWork = true;
}
internal UnitOfWorkPattern(IUnitOfWork unitOfWork)
{
_providedUnitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
_ownsUnitOfWork = false;
}
public void LogicThatUsesService()
{
IUnitOfWork currentUow = null;
if (_ownsUnitOfWork)
{
currentUow = new UnitOfWork();
}
else
{
currentUow = _providedUnitOfWork;
}
using (currentUow != null && _ownsUnitOfWork ? currentUow : null)
{
//
// Perform operations using currentUow, e.g. repository calls
//
if (_ownsUnitOfWork)
{
currentUow.Commit();
}
}
}
}
}

View File

@@ -0,0 +1,38 @@
using bnhtrade.Core.Data.Database.UnitOfWork;
using System;
using System.Collections.Generic;
namespace bnhtrade.Core.Logic._boilerplate
{
public class UnitOfWorkService : UnitOfWorkBase
{
public UnitOfWorkService() : base() { }
internal UnitOfWorkService(IUnitOfWork unitOfWork) : base(unitOfWork) { }
public Model.Account.InvoiceLineItem ReturnExample(string itemCode)
{
return WithUnitOfWork(uow =>
{
// add all code in here that uses the unit of work, this will ensure that the unit of work is disposed of correctly
var item = uow.InvoiceRepository.GetInvoiceLineItem(null, new List<string> { itemCode });
// use the base method to commit, it will check if the unit of work is owned by this service before committing
CommitIfOwned(uow);
// return
return item[0];
});
}
public void VoidExample()
{
WithUnitOfWork(uow =>
{
var items = uow.InvoiceRepository.GetInvoiceLineItem();
// use the base method to commit, it will check if the unit of work is owned by this service before committing
CommitIfOwned(uow);
});
}
}
}

View File

@@ -9,7 +9,7 @@ namespace bnhtrade.Core.Model.Account
{
public class Account
{
public Account(uint id, uint accountCode, string accountName, string description, string type, string basicType, int multiplier)
public Account(int id, int accountCode, string accountName, string description, string type, string basicType, int multiplier)
{
Id = id;
AccountCode = accountCode;
@@ -23,9 +23,9 @@ namespace bnhtrade.Core.Model.Account
/// <summary>
/// Database record id
/// </summary>
public uint Id { get; private set; }
public int Id { get; private set; }
public uint AccountCode { get; private set; }
public int AccountCode { get; private set; }
public string AccountName { get; private set; }

View File

@@ -10,7 +10,7 @@ namespace bnhtrade.Core.Model.Account
{
public class Journal : IValidatableObject
{
internal Journal(uint journalId, Core.Model.Account.JournalType type, List<Post> posts, DateTime entryDate, DateTime postDate, DateTime lastModifed, bool isLocked)
internal Journal(int journalId, Core.Model.Account.JournalType type, List<Post> posts, DateTime entryDate, DateTime postDate, DateTime lastModifed, bool isLocked)
{
JournalId = journalId;
Type = type;
@@ -21,7 +21,7 @@ namespace bnhtrade.Core.Model.Account
IsLocked = isLocked;
}
public uint JournalId { get; private set; }
public int JournalId { get; private set; }
public Core.Model.Account.JournalType Type { get; private set; }
public List<Post> Posts { get; private set; } = new List<Post>();
public DateTime EntryDate { get; private set; }
@@ -31,14 +31,14 @@ namespace bnhtrade.Core.Model.Account
public class Post
{
internal Post(uint postId, Core.Model.Account.Account account, decimal amountGbp)
internal Post(int postId, Core.Model.Account.Account account, decimal amountGbp)
{
PostId = postId;
Account = account;
AmountGbp = amountGbp;
}
public uint PostId { get; private set; }
public int PostId { get; private set; }
public Core.Model.Account.Account Account { get; private set; }
public decimal AmountGbp { get; private set; }
}

View File

@@ -8,7 +8,7 @@ namespace bnhtrade.Core.Model.Account
{
public class JournalType
{
internal JournalType(uint journalTypeId, string title, Model.Account.Account defaultCreditAccount = null, Model.Account.Account defaultDebitAccount = null)
internal JournalType(int journalTypeId, string title, Model.Account.Account defaultCreditAccount = null, Model.Account.Account defaultDebitAccount = null)
{
JournalTypeId = journalTypeId;
Title = title;
@@ -22,7 +22,7 @@ namespace bnhtrade.Core.Model.Account
DefaultDebitAccount = defaultDebitAccount;
}
public uint JournalTypeId { get ; private set; }
public int JournalTypeId { get ; private set; }
public string Title { get; private set; }

View File

@@ -1,11 +1,14 @@
using System;
using bnhtrade.Core.Logic;
using Microsoft.Data.SqlClient;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Data.Common;
using System.Data.SqlTypes;
using System.IO;
using System.Linq;
using System.Transactions;
using System.Data.SqlTypes;
using System.Security.Cryptography;
using System.Transactions;
namespace bnhtrade.Core
{
@@ -231,7 +234,7 @@ namespace bnhtrade.Core
namespace Stock
{
public class StockCreate
public class StockCreate : UnitOfWorkBase
{
private int WIP_StockInsert(string sqlConnectionString, int accountJournalType, int stockJournalType, string currencyCode, decimal amount,
int quantity, int productId, int conditionId, int accountTaxCodeId, DateTime entryDate, int debitStatusId)
@@ -337,7 +340,7 @@ namespace bnhtrade.Core
}
// get/set an skuId
int skuId = new Logic.Sku.GetSkuId().Request(productId, conditionId, accountTaxCodeId, true);
int skuId = new Logic.Sku.SkuService().GetSkuId(productId, conditionId, accountTaxCodeId, true);
// add the entry to the stock table (minus stockJournalId)
int stockId = 0;
@@ -563,10 +566,10 @@ namespace bnhtrade.Core
// to be used by other methods within a transaction scope
private static void WIP_StockDeleteSubAccountJournalEntry(string sqlConnectionString, int stockId)
{
using (TransactionScope scope = new TransactionScope())
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
var trans = conn.BeginTransaction();
// get the account journal id
int accountJournalId = 0;
@@ -576,6 +579,7 @@ namespace bnhtrade.Core
WHERE StockID=@stockId;
", conn))
{
cmd.Transaction = trans;
cmd.Parameters.AddWithValue("@stockId", stockId);
object obj = cmd.ExecuteScalar();
@@ -601,6 +605,7 @@ namespace bnhtrade.Core
WHERE StockID=@stockId;
", conn))
{
cmd.Transaction = trans;
cmd.Parameters.AddWithValue("@stockId", stockId);
int count = cmd.ExecuteNonQuery();
@@ -612,9 +617,9 @@ namespace bnhtrade.Core
}
// delete account journal entry
new Data.Database.Account.DeleteJournal().AccountJournalDelete(accountJournalId);
new Data.Database.Repository.Implementation.JournalRepository(conn, trans).DeleteJournal(accountJournalId);
scope.Complete();
trans.Commit();
}
}
@@ -1457,10 +1462,10 @@ namespace bnhtrade.Core
public static void WIP_PurchaseLineTransactionDelete(string sqlConnectionString, int purchaseLineId, int accountJournalId)
{
using (TransactionScope scope = new TransactionScope())
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
var trans = conn.BeginTransaction();
// check accountJournalId does not exist in stock table
using (SqlCommand cmd = new SqlCommand(@"
@@ -1469,6 +1474,7 @@ namespace bnhtrade.Core
WHERE AccountJournalID=@accountJournalId;
", conn))
{
cmd.Transaction = trans;
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
using (var reader = cmd.ExecuteReader())
@@ -1493,6 +1499,7 @@ namespace bnhtrade.Core
WHERE AccountJournalID=@accountJournalId;
", conn))
{
cmd.Transaction = trans;
cmd.Parameters.AddWithValue("@accountJournalId", accountJournalId);
int count = cmd.ExecuteNonQuery();
@@ -1504,9 +1511,9 @@ namespace bnhtrade.Core
}
// delete account journal entry
new Data.Database.Account.DeleteJournal().AccountJournalDelete(accountJournalId);
new Data.Database.Repository.Implementation.JournalRepository(conn, trans).DeleteJournal(accountJournalId);
scope.Complete();
trans.Commit();
}
}
}

View File

@@ -1,4 +1,5 @@
using bnhtrade.Core.Data.Database.Account;
using bnhtrade.Core.Data.Database.UnitOfWork;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -25,28 +26,28 @@ namespace bnhtrade.Core.Test.Account
public void PurchaseInvoice()
{
var result = new bnhtrade.Core.Logic.Account.PurchaseInvoice().GetPurchaseInvoice( new List<int> { 14718, 100, 101, 102, 300, 400, 1200, 2734, 6339, 9999 }); // 10 in total
var result = new bnhtrade.Core.Logic.Account.PurchaseInvoiceService().GetPurchaseInvoice( new List<int> { 14718, 100, 101, 102, 300, 400, 1200, 2734, 6339, 9999 }); // 10 in total
}
public void PurchaseInvoiceLine()
{
var read = new Data.Database.Account.ReadPurchaseInvoiceLine();
read.ItemDescription = new List<string> { "xbox", "kill" };
var result = read.Read();
var uof = new UnitOfWork();
var result = uof.InvoiceRepository.ReadPurchaseInvoiceLine(null, null, null, new List<string> { "xbox", "kill" });
}
public void Journal()
{
var read = new Data.Database.Account.ReadJournal();
read.AccountJournalId = new List<uint> { 123, 300, 324, 5678, 22 };
var result = read.Read();
//var read = new Data.Database.Account.ReadJournal();
//read.AccountJournalId = new List<uint> { 123, 300, 324, 5678, 22 };
//var result = read.Read();
}
public void InoivceCurrencyConversion()
{
var invoiceService = new bnhtrade.Core.Logic.Export.AccountInvoice.QueueService();
var uof = new UnitOfWork();
var invoiceService = new bnhtrade.Core.Logic.Export.AccountInvoice.QueueService(uof);
var invoiceList = invoiceService.ReadInvoiceById(new List<int> { 349, 371, 375, 379 });
var currencyService = new bnhtrade.Core.Logic.Account.CurrencyService();
var currencyService = new bnhtrade.Core.Logic.Account.CurrencyService(uof);
foreach (var invoice in invoiceList.Values.ToList())
{

View File

@@ -11,7 +11,7 @@ namespace bnhtrade.Core.Test.Export
{
public Export()
{
DeleteExportInvoice();
UPdateInvoiceHeaderDetail();
}
private void SubmitAmazonInventoryLoader()
@@ -43,24 +43,22 @@ namespace bnhtrade.Core.Test.Export
var list = unitOfWork.ExportInvoiceRepository.GetSalesInvoiceById(new List<int> { 550, 555 });
}
private void ExportSalesInvoiceQueue()
{
var invoice = new Model.Account.SalesInvoice(true);
invoice.InvoiceLineList = new List<Model.Account.Invoice.InvoiceLine>();
string path = @"%USERPROFILE%\Downloads\TEST.CSV";
var queueService = new bnhtrade.Core.Logic.Export.AccountInvoice.QueueService();
queueService.ImportAll();
queueService.ExportSalesInvoice(path, 1234);
var return1 = queueService.ExportSalesInvoiceIsComplete();
}
private void DeleteExportInvoice()
{
//var uow = new bnhtrade.Core.Data.Database.UnitOfWork.UnitOfWork();
throw new Exception("This method is for testing purposes only, it will delete export invoices from the database. Use with caution.");
using (var uow = new bnhtrade.Core.Data.Database.UnitOfWork.UnitOfWork())
{
int dfkjl = uow.ExportInvoiceRepository.DeleteInvoice(new List<int> { 576, 577, 584 });
int lskdjflsd = uow.ImportAmazonRepository.SetAmazonSettlementIsProcessed(new List<string> { "24684639382f", "14720584692f", "14386695522f" }, false);
int dfkjl = uow.ExportInvoiceRepository.DeleteInvoice(new List<int> { 591, 590, 589, 588, 587, 586, 585, 583, 582, 581, 580, 579, 578 });
int lskdjflsd = uow.AmazonSettlementRepository.UpdateAmazonSettlementIsProcessed(new List<string> { "24945698052", "24684639382", "24859276062", "24769420562", "24684661532", "14720584692", "24593881302", "24508182552", "14386695522", "24416840332", "24334973902", "24162226452" }, false);
uow.Commit();
}
}
private void UPdateInvoiceHeaderDetail()
{
using (var uow = new bnhtrade.Core.Data.Database.UnitOfWork.UnitOfWork())
{
int dfkjl = uow.ExportInvoiceRepository.UpdateInvoiceHeaderDetail(123333, "douche", true);
uow.Commit();
}
}

View File

@@ -23,7 +23,7 @@ namespace bnhtrade.Core.Test.Logic
{
using (var uow = new Data.Database.UnitOfWork.UnitOfWork())
{
var list = uow.ImportAmazonRepository.ReadAmazonSettlements(marketPlaceNameList: new List<string> { "Amazon.fr" }, returnTop: 3);
var list = uow.AmazonSettlementRepository.ReadAmazonSettlements(marketPlaceNameList: new List<string> { "Amazon.fr" }, returnTop: 3);
}
}
public void UpdateExportInvoiceQueue()

View File

@@ -60,11 +60,11 @@ namespace bnhtrade.Core.Test.Stock
public void ReadStockStatus()
{
var db = new Status();
db.StatusIds = new List<int> { 3, 4, 5, 6, 7, 11, 12, 13, 15 };
db.StatusTypeIds = new List<int> { 12, 5 };
var result = db.Read();
int i = 0;
//var db = new Status();
//db.StatusIds = new List<int> { 3, 4, 5, 6, 7, 11, 12, 13, 15 };
//db.StatusTypeIds = new List<int> { 12, 5 };
//var result = db.Read();
//int i = 0;
}
}
}

View File

@@ -53,7 +53,7 @@ namespace bnhtrade.gui
private void InitialiseTabReceiving()
{
Cursor.Current = Cursors.WaitCursor;
purchaseLineStatusBindingSource.DataSource = new Core.Logic.Account.PurchaseInvoiceMisc().ReadLineStatusToList();
purchaseLineStatusBindingSource.DataSource = new Core.Logic.Account.PurchaseInvoiceService().ReadLineStatusToList();
comboBox1.SelectedIndex = 3;
ListBoxQuery();
initTabReceiving = true;
@@ -96,7 +96,7 @@ namespace bnhtrade.gui
comboBox = comboBox1.Text;
}
bsReceivingLines.DataSource = new Core.Logic.Account.PurchaseInvoiceMisc().GetLineSummary(
bsReceivingLines.DataSource = new Core.Logic.Account.PurchaseInvoiceService().GetLineSummary(
dateTimeOrderSearch.Value
, comboBox
, searchList);
@@ -120,7 +120,7 @@ namespace bnhtrade.gui
var row = dataGridView1.CurrentCell.RowIndex;
var lineSummary = (bnhtrade.Core.Model.Account.PurchaseInvoiceLineSummary)bsReceivingLines[row];
int purchaseId = lineSummary.PurchaseId;
var purchaseInvoiceList = new Core.Logic.Account.PurchaseInvoice().GetPurchaseInvoice(new List<int> { purchaseId });
var purchaseInvoiceList = new Core.Logic.Account.PurchaseInvoiceService().GetPurchaseInvoice(new List<int> { purchaseId });
var purchaseInvoice = purchaseInvoiceList[purchaseId];
var form = new PurchaseInvoice(purchaseInvoice);
form.Show();
@@ -177,12 +177,6 @@ namespace bnhtrade.gui
}
}
// create export invoices and export to CSV
var queueService = new bnhtrade.Core.Logic.Export.AccountInvoice.QueueService();
queueService.ImportAll();
queueService.ExportSalesInvoice(savePath, nextInvoiceNumber);
// open import page
Process.Start(new ProcessStartInfo
{
@@ -190,33 +184,42 @@ namespace bnhtrade.gui
UseShellExecute = true
});
// did the import go okay
var result = MessageBox.Show(
"Import invoices to Xero ensuring UnitAmount field option is set to 'Tax Exclusive' on the import page."
+ Environment.NewLine + Environment.NewLine
+ "Once the import has completed suscessfully click 'Okay' to mark the invoice(s) as complete/imported.",
"Import Confirmation",
MessageBoxButtons.OKCancel,
MessageBoxIcon.Question
);
if (result == DialogResult.OK)
// create export invoices and export to CSV
var queueService = new bnhtrade.Core.Logic.Export.AccountInvoice.QueueService();
queueService.ImportAll();
queueService.ExportSalesInvoice(savePath, nextInvoiceNumber, () =>
{
var completeCount = queueService.ExportSalesInvoiceIsComplete();
if (completeCount != invoices)
// did the import go okay
var result = MessageBox.Show(
"Import invoices to Xero ensuring UnitAmount field option is set to 'Tax Exclusive' on the import page."
+ Environment.NewLine + Environment.NewLine
+ "Once the import has completed suscessfully click 'Okay' to mark the invoice(s) as complete/imported.",
"Import Confirmation",
MessageBoxButtons.OKCancel,
MessageBoxIcon.Question
);
if (result == DialogResult.OK)
{
MessageBox.Show("Error marking invoices as complete. Please check the logs for more details.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
log.LogError("ExportSalesInvoiceIsComplete returned " + completeCount + " but expected " + invoices + ". Please check the logs for more details.", queueService.ErrorMessage);
return true;
}
else
{
MessageBox.Show(completeCount + " invoices marked as complete.", "Export Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
return false;
}
});
if (queueService.ErrorMessageIsSet)
{
MessageBox.Show("Error exporting invoices: " + queueService.ErrorMessage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
log.LogError("Error exporting invoices: " + queueService.ErrorMessage);
return;
}
else
{
MessageBox.Show("Operation cancelled. No invoices marked as complete.");
MessageBox.Show("Exported " + invoices + " invoices to " + savePath, "Export Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
UpdateInvoiceExportBox();
return;
}