This commit is contained in:
Bobbie Hodgetts
2024-05-12 16:22:53 +01:00
parent 0fb45b8090
commit 1c7ed5da93
18 changed files with 660 additions and 559 deletions

View File

@@ -35,26 +35,26 @@ namespace bnhtrade.ComTypeLib
public int AccountJournalInsert(ConnectionCredential sqlConnCred, int journalTypeId, DateTime entryDate, public int AccountJournalInsert(ConnectionCredential sqlConnCred, int journalTypeId, DateTime entryDate,
string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false) string currencyCode, [MarshalAs(UnmanagedType.Currency)] decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false)
{ {
return Core.Account.AccountQuery.AccountJournalInsert(sqlConnCred.ConnectionString, journalTypeId, entryDate, return new Core.Logic.Account.Journal().AccountJournalInsert(journalTypeId, entryDate,
currencyCode, amount, debitAccountId, creditAccountId, lockEntry); currencyCode, amount, debitAccountId, creditAccountId, lockEntry);
} }
public bool AccountJournalDelete(ConnectionCredential sqlConnCred, int accountJournalId) public bool AccountJournalDelete(ConnectionCredential sqlConnCred, int accountJournalId)
{ {
return Core.Account.AccountQuery.AccountJournalDelete(sqlConnCred.ConnectionString, accountJournalId); return new Core.Logic.Account.Journal().AccountJournalDelete(accountJournalId);
} }
[return: MarshalAs(UnmanagedType.Currency)] [return: MarshalAs(UnmanagedType.Currency)]
public decimal CurrencyConvertToGbp(ConnectionCredential sqlConnCred, string currencyCode, public decimal CurrencyConvertToGbp(ConnectionCredential sqlConnCred, string currencyCode,
[MarshalAs(UnmanagedType.Currency)] decimal amount, DateTime conversionDate) [MarshalAs(UnmanagedType.Currency)] decimal amount, DateTime conversionDate)
{ {
return Core.Account.AccountQuery.CurrencyConvertToGbp(sqlConnCred.ConnectionString, currencyCode, amount, conversionDate); return new Core.Logic.Account.Currency().CurrencyConvertToGbp(currencyCode, amount, conversionDate);
} }
public int CurrencyExchangeRateInsert(ConnectionCredential sqlConnCred, int exchangeRateSource, string currencyCode, public int CurrencyExchangeRateInsert(ConnectionCredential sqlConnCred, int exchangeRateSource, string currencyCode,
[MarshalAs(UnmanagedType.Currency)] decimal currencyUnitsPerGbp, DateTime periodStart, DateTime periodEnd, bool checkOverride = false) [MarshalAs(UnmanagedType.Currency)] decimal currencyUnitsPerGbp, DateTime periodStart, DateTime periodEnd, bool checkOverride = false)
{ {
return Core.Account.AccountQuery.CurrencyExchangeRateInsert(sqlConnCred.ConnectionString, exchangeRateSource, currencyCode, return new Core.Logic.Account.Currency().CurrencyExchangeRateInsert(exchangeRateSource, currencyCode,
currencyUnitsPerGbp, periodStart, periodEnd, checkOverride); currencyUnitsPerGbp, periodStart, periodEnd, checkOverride);
} }
} }

View File

@@ -0,0 +1,208 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace bnhtrade.Core.Data.Database.Account
{
internal class CreateJournal : Connection
{
/// <summary>
/// Old code needs sorting
/// </summary>
public int AccountJournalInsert(int journalTypeId, DateTime entryDate, string currencyCode,
decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false)
{
int defaultDebit = 0;
int defaultCredit = 0;
// ensure date is UTC
entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc);
// debit and credit locks are checked in journal post method
using (TransactionScope scope = new TransactionScope())
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
// insert the journal entry
int journalId;
using (SqlCommand cmd = new SqlCommand(@"
INSERT INTO tblAccountJournal
(AccountJournalTypeID, EntryDate, IsLocked)
OUTPUT INSERTED.AccountJournalID
VALUES
(@journalTypeId, @entryDate, @lockEntry)
", conn))
{
// add parameters
cmd.Parameters.AddWithValue("@journalTypeId", journalTypeId);
cmd.Parameters.AddWithValue("@entryDate", entryDate.ToUniversalTime());
cmd.Parameters.AddWithValue("@lockEntry", lockEntry);
//execute
journalId = (int)cmd.ExecuteScalar();
}
// insert journal entries
//bool postResult = AccountJournalPostInsert(sqlConnectionString, journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId);
bool postResult = AccountJournalPostInsert(journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId);
scope.Complete();
return journalId;
}
}
/// <summary>
/// Old code needs sorting
/// </summary>
internal bool AccountJournalPostInsert(int journalId, DateTime entryDate,
string currencyCode, decimal amount, int debitAccountId = 0, int creditAccountId = 0)
{
int defaultDebit;
int defaultCredit;
entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc);
using (TransactionScope scope = new TransactionScope())
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
// ensure their are no other entries
using (SqlCommand cmd = new SqlCommand(@"
SELECT
Count(tblAccountJournalPost.AccountJournalPostID) AS CountOfAccountJournalPostID
FROM
tblAccountJournalPost
WHERE
(((tblAccountJournalPost.AccountJournalID)=@AccountJournalID));
", conn))
{
cmd.Parameters.AddWithValue("@AccountJournalID", journalId);
int count = (int)cmd.ExecuteScalar();
if (count > 0)
{
throw new Exception("Unable the insert journal posts, post already present AccountJournalID=" + journalId);
}
}
//checks
using (SqlCommand cmd = new SqlCommand(@"
SELECT
tblAccountJournalType.ChartOfAccountID_Debit, tblAccountJournalType.ChartOfAccountID_Credit
FROM
tblAccountJournal
INNER JOIN tblAccountJournalType
ON tblAccountJournal.AccountJournalTypeID = tblAccountJournalType.AccountJournalTypeID
WHERE
(((tblAccountJournal.AccountJournalID)=@journalId));
", conn))
{
cmd.Parameters.AddWithValue("@journalId", journalId);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
// debit check
if (reader.IsDBNull(0))
{
if (debitAccountId == 0)
{
throw new Exception("Debit Account ID required, default not set for journal type");
}
}
else
{
defaultDebit = reader.GetInt32(0);
if (debitAccountId == 0)
{
debitAccountId = defaultDebit;
}
else if (debitAccountId != defaultDebit)
{
throw new Exception("Debit Account ID supplied does not match default set for journal type");
}
}
// credit check
if (reader.IsDBNull(1))
{
if (creditAccountId == 0)
{
throw new Exception("Credit Account ID required, default not set for journal type");
}
}
else
{
defaultCredit = reader.GetInt32(1);
if (creditAccountId == 0)
{
creditAccountId = defaultCredit;
}
else if (creditAccountId != defaultCredit)
{
throw new Exception("Credit Account ID supplied does not match default set for journal type");
}
}
}
else
{
throw new Exception("AccountJournalID '" + journalId + "' does not exist.");
}
}
}
// currency conversion
if (currencyCode != "GBP")
{
amount = new Data.Database.Account.Currency().CurrencyConvertToGbp(currencyCode, amount, entryDate);
}
// ensure decimal is rounded
amount = Math.Round(amount, 2);
// insert debit post
using (SqlCommand cmd = new SqlCommand(@"
INSERT INTO tblAccountJournalPost
(AccountJournalID, AccountChartOfID, AmountGbp)
VALUES
(@AccountJournalId, @AccountChartOfId, @AmountGbp)
", conn))
{
// add parameters
cmd.Parameters.AddWithValue("@AccountJournalId", journalId);
cmd.Parameters.AddWithValue("@AccountChartOfId", debitAccountId);
cmd.Parameters.AddWithValue("@AmountGbp", amount);
cmd.ExecuteNonQuery();
}
// insert credit post
using (SqlCommand cmd = new SqlCommand(@"
INSERT INTO tblAccountJournalPost
(AccountJournalID, AccountChartOfID, AmountGbp)
VALUES
(@AccountJournalId, @AccountChartOfId, @AmountGbp)
", conn))
{
// add parameters
cmd.Parameters.AddWithValue("@AccountJournalId", journalId);
cmd.Parameters.AddWithValue("@AccountChartOfId", creditAccountId);
cmd.Parameters.AddWithValue("@AmountGbp", (amount * -1));
cmd.ExecuteNonQuery();
}
scope.Complete();
return true;
}
}
}
}

View File

@@ -0,0 +1,199 @@
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 Currency : Connection
{
public decimal CurrencyConvertToGbp(string currencyCode, decimal amount, DateTime conversionDate)
{
if (currencyCode == "GBP" || amount == 0M)
{
return amount;
}
if (currencyCode.Length != 3)
{
throw new Exception("Invalid currency code '" + currencyCode + "'");
}
using (SqlConnection sqlConn = new SqlConnection(SqlConnectionString))
{
sqlConn.Open();
using (SqlCommand cmd = new SqlCommand(@"
SELECT CurrencyUnitsPerGBP
FROM tblAccountExchangeRate
WHERE CurrencyCode=@currencyCode AND StartDate<=@conversionDate AND EndDate>@conversionDate
", sqlConn))
{
cmd.Parameters.AddWithValue("@currencyCode", currencyCode);
cmd.Parameters.AddWithValue("@conversionDate", conversionDate);
object result = cmd.ExecuteScalar();
if (result != null)
{
return amount / Convert.ToDecimal(result);
}
}
// return reason for no record found
using (SqlCommand cmd = new SqlCommand(@"
SELECT CurrencyUnitsPerGBP
FROM tblAccountExchangeRate
WHERE CurrencyCode=@currencyCode
", sqlConn))
{
cmd.Parameters.AddWithValue("@currencyCode", currencyCode);
object result = cmd.ExecuteScalar();
if (result == null)
{
throw new Exception("Currency code '" + currencyCode + "' does not exist in Exchange Rate table");
}
else
{
throw new Exception("Date range for " + currencyCode + " " + conversionDate.ToShortDateString() + " " +
conversionDate.ToLongTimeString() + "' does not exist in Exchange Rate table");
}
}
}
}
public int CurrencyExchangeRateInsert(int exchangeRateSource, string currencyCode,
decimal currencyUnitsPerGbp, DateTime periodStart, DateTime periodEnd, bool checkOverride = false)
{
currencyUnitsPerGbp = decimal.Round(currencyUnitsPerGbp, 4);
periodStart = DateTime.SpecifyKind(periodStart, DateTimeKind.Utc);
periodEnd = DateTime.SpecifyKind(periodEnd, DateTimeKind.Utc);
// CHECKS
// HMRC source only
if (exchangeRateSource != 1)
{
throw new Exception("Function does not currently accept exchange rates from sources other than HMRC");
}
// currency code upper case only
currencyCode = currencyCode.ToUpper();
if (currencyCode.Length != 3)
{
throw new Exception("Invalid currency code '" + currencyCode + "'");
}
if (periodEnd <= periodStart)
{
throw new Exception("Invalid date period.");
}
if (checkOverride == false && (periodEnd - periodStart).Days > 31)
{
throw new Exception("Date period is greater than 31 days.");
}
// retirve previous data
DateTime? periodEndLast = null;
using (SqlConnection sqlConn = new SqlConnection(SqlConnectionString))
{
sqlConn.Open();
using (SqlCommand cmd = new SqlCommand(@"
SELECT Max(tblAccountExchangeRate.EndDate) AS MaxOfEndDate
FROM tblAccountExchangeRate
WHERE (((tblAccountExchangeRate.CurrencyCode) = @currencyCode))
", sqlConn))
{
cmd.Parameters.AddWithValue("@currencyCode", currencyCode);
object obj = cmd.ExecuteScalar();
// currency code not existing
if (obj == DBNull.Value && checkOverride == false)
{
throw new Exception("Currency code '" + currencyCode + "' does not exist in table");
}
// currency code exists
else
{
periodEndLast = DateTime.SpecifyKind(Convert.ToDateTime(obj), DateTimeKind.Utc);
if (periodStart != periodEndLast)
{
throw new Exception("Invalid period start date -- must equal previous period end-date.");
}
}
}
// retrive previous exchange rate and check
decimal currencyUnitsPerGbpLast = 0;
if (periodEndLast != null)
{
using (SqlCommand cmd = new SqlCommand(@"
SELECT tblAccountExchangeRate.AccountExchangeRateID, tblAccountExchangeRate.CurrencyUnitsPerGBP
FROM tblAccountExchangeRate
WHERE (tblAccountExchangeRate.EndDate = @periodEndLast)
AND (CurrencyCode = @currencyCode);
", sqlConn))
{
cmd.Parameters.AddWithValue("@periodEndLast", periodEndLast);
cmd.Parameters.AddWithValue("@currencyCode", currencyCode);
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
currencyUnitsPerGbpLast = reader.GetDecimal(1);
}
else
{
throw new Exception("Error that shouldn't happen! Check code @ 5129f3e6-2f7e-4883-bc73-b317d8fa4050");
}
// error if >1 line
if (reader.Read())
{
string errText = "Multiple lines in currency exchange table for '" + currencyCode + "' where [EndDate]=" + periodEndLast.ToString();
new Logic.Log.LogEvent().LogError(errText);
throw new Exception(errText);
}
}
}
}
// check difference between current and previous exchange rates isn't too great
if (checkOverride == false &&
(currencyUnitsPerGbpLast > (currencyUnitsPerGbp * 1.05m) || currencyUnitsPerGbpLast < (currencyUnitsPerGbp * 0.95m))
)
{
throw new Exception("Difference between supplied and previous exchange rates is greater than 5%");
}
// MAKE THE INSERT
int recordId = 0;
using (SqlCommand cmd = new SqlCommand(@"
INSERT INTO tblAccountExchangeRate (ExchangeRateSource, CurrencyCode, CurrencyUnitsPerGBP, StartDate, EndDate)
OUTPUT INSERTED.AccountExchangeRateID
VALUES (@exchangeRateSource, @currencyCode, @currencyUnitsPerGbp, @periodStart, @periodEnd);
", sqlConn))
{
cmd.Parameters.AddWithValue("@exchangeRateSource", exchangeRateSource);
cmd.Parameters.AddWithValue("@currencyCode", currencyCode);
cmd.Parameters.AddWithValue("@currencyUnitsPerGbp", currencyUnitsPerGbp);
cmd.Parameters.AddWithValue("@periodStart", periodStart);
cmd.Parameters.AddWithValue("@periodEnd", periodEnd);
recordId = (int)cmd.ExecuteScalar();
if (recordId < 1)
{
throw new Exception("Error inserting record, did not retrive new record ID.");
}
}
return recordId;
}
}
}
}

View File

@@ -0,0 +1,64 @@
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

@@ -7,13 +7,13 @@ using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database.Account namespace bnhtrade.Core.Data.Database.Account
{ {
internal class Contact : Connection internal class ReadContact : Connection
{ {
private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder; private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder;
public List<int> ContactIdList { get; set; } public List<int> ContactIdList { get; set; }
public Contact() public ReadContact()
{ {
Init(); Init();
} }

View File

@@ -10,16 +10,16 @@ using static System.ComponentModel.Design.ObjectSelectorEditor;
namespace bnhtrade.Core.Data.Database.Account namespace bnhtrade.Core.Data.Database.Account
{ {
internal class Journal : Connection internal class ReadJournal : Connection
{ {
private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder; private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder;
/// <summary> /// <summary>
/// Results filter /// Filter the read results
/// </summary> /// </summary>
public List<uint> AccountJournalId { get; set; } public List<uint> AccountJournalId { get; set; }
public Journal() public ReadJournal()
{ {
Init(); Init();
} }
@@ -162,7 +162,7 @@ namespace bnhtrade.Core.Data.Database.Account
} }
// get journalTypes from db // get journalTypes from db
var dbJournalType = new Data.Database.Account.JournalType(); var dbJournalType = new Data.Database.Account.ReadJournalType();
dbJournalType.IdList = journalTypeIdList; dbJournalType.IdList = journalTypeIdList;
var journalTypeDict = dbJournalType.Read(); var journalTypeDict = dbJournalType.Read();
@@ -204,5 +204,39 @@ namespace bnhtrade.Core.Data.Database.Account
// all done, return the list herevar // all done, return the list herevar
return returnList; 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

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database.Account namespace bnhtrade.Core.Data.Database.Account
{ {
internal class JournalType : Connection internal class ReadJournalType : Connection
{ {
private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder; private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder;
@@ -21,7 +21,7 @@ namespace bnhtrade.Core.Data.Database.Account
/// </summary> /// </summary>
public List<string> TitleList { get; set; } public List<string> TitleList { get; set; }
public JournalType() public ReadJournalType()
{ {
Init(); Init();
} }

View File

@@ -8,13 +8,13 @@ using static System.ComponentModel.Design.ObjectSelectorEditor;
namespace bnhtrade.Core.Data.Database.Account namespace bnhtrade.Core.Data.Database.Account
{ {
public class PurchaseInvoice : Connection public class ReadPurchaseInvoice : Connection
{ {
private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder; private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder;
public List<int> PurchaseInvoiceIdList { get; set; } public List<int> PurchaseInvoiceIdList { get; set; }
public PurchaseInvoice() public ReadPurchaseInvoice()
{ {
Init(); Init();
} }
@@ -136,7 +136,7 @@ namespace bnhtrade.Core.Data.Database.Account
// add contact info // add contact info
if (invoiceContactDict.Any()) if (invoiceContactDict.Any())
{ {
var readContact = new Data.Database.Account.Contact(); var readContact = new Data.Database.Account.ReadContact();
readContact.ContactIdList = invoiceContactDict.Values.ToList(); readContact.ContactIdList = invoiceContactDict.Values.ToList();
var contactDict = readContact.Read(); var contactDict = readContact.Read();
@@ -154,7 +154,7 @@ namespace bnhtrade.Core.Data.Database.Account
} }
// add invoice lines // add invoice lines
var readLines = new Data.Database.Account.PurchaseInvoiceLine(); var readLines = new Data.Database.Account.ReadPurchaseInvoiceLine();
readLines.InvoiceIdList = purchaseIdList; readLines.InvoiceIdList = purchaseIdList;
var lines = readLines.Read(); var lines = readLines.Read();
foreach(var invoice in returnList.Values) foreach(var invoice in returnList.Values)

View File

@@ -9,7 +9,7 @@ using static System.ComponentModel.Design.ObjectSelectorEditor;
namespace bnhtrade.Core.Data.Database.Account namespace bnhtrade.Core.Data.Database.Account
{ {
internal class PurchaseInvoiceLine : Connection internal class ReadPurchaseInvoiceLine : Connection
{ {
private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder; private bnhtrade.Core.Data.Database.SqlWhereBuilder sqlBuilder;
@@ -33,7 +33,7 @@ namespace bnhtrade.Core.Data.Database.Account
/// </summary> /// </summary>
public List<string> ItemDescription { get; set; } public List<string> ItemDescription { get; set; }
public PurchaseInvoiceLine() public ReadPurchaseInvoiceLine()
{ {
Init(); Init();
} }

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Database.Account namespace bnhtrade.Core.Data.Database.Account
{ {
internal class PurchaseInvoiceLineStatus : Connection internal class ReadPurchaseInvoiceLineStatus : Connection
{ {
public Dictionary<int, Model.Account.PurchaseInvoiceLineStatus> Read() public Dictionary<int, Model.Account.PurchaseInvoiceLineStatus> Read()
{ {

View File

@@ -9,7 +9,7 @@ using static System.ComponentModel.Design.ObjectSelectorEditor;
namespace bnhtrade.Core.Data.Database.Account namespace bnhtrade.Core.Data.Database.Account
{ {
internal class PurchaseInvoiceLineSummary : Connection internal class ReadPurchaseInvoiceLineSummary : Connection
{ {
public List<Model.Account.PurchaseInvoiceLineSummary> Read(DateTime periodTo, string lineStatus, List<string> descriptionSearch) public List<Model.Account.PurchaseInvoiceLineSummary> Read(DateTime periodTo, string lineStatus, List<string> descriptionSearch)
{ {

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace bnhtrade.Core.Data.Database.Account
{
internal class UpdateJournal : Connection
{
public bool AccountJournalPostUpdate(int journalId, string currencyCode, decimal amount, int debitAccountId = 0, int creditAccountId = 0)
{
using (TransactionScope scope = new TransactionScope())
using (SqlConnection conn = new SqlConnection(SqlConnectionString))
{
conn.Open();
// retrive journal entry date
DateTime entryDate;
using (SqlCommand cmd = new SqlCommand(@"
SELECT
tblAccountJournal.EntryDate
FROM
tblAccountJournal
WHERE
(((tblAccountJournal.AccountJournalID)=@accountJournalId));
", conn))
{
cmd.Parameters.AddWithValue("@accountJournalId", journalId);
entryDate = DateTime.SpecifyKind((DateTime)cmd.ExecuteScalar(), DateTimeKind.Utc);
}
// delete the original posts
using (SqlCommand cmd = new SqlCommand(@"
DELETE FROM
tblAccountJournalPost
WHERE
(((tblAccountJournalPost.AccountJournalID)=@accountJournalId));
", conn))
{
cmd.Parameters.AddWithValue("@accountJournalId", journalId);
cmd.ExecuteNonQuery();
}
//insert new posts
//bool postResult = AccountJournalPostInsert(sqlConnectionString, journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId);
bool postResult = new Data.Database.Account.CreateJournal().AccountJournalPostInsert(journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId);
// update modified date on journal
using (SqlCommand cmd = new SqlCommand(@"
UPDATE
tblAccountJournal
SET
tblAccountJournal.LastModified=@utcNow
WHERE
(((tblAccountJournal.AccountJournalID)=@accountJournalId));
", conn))
{
cmd.Parameters.AddWithValue("@accountJournalId", journalId);
cmd.Parameters.AddWithValue("@utcNow", DateTime.UtcNow);
cmd.ExecuteNonQuery();
}
scope.Complete();
}
return true;
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Logic.Account
{
public class Currency
{
public decimal CurrencyConvertToGbp(string currencyCode, decimal amount, DateTime conversionDate)
{
return new Data.Database.Account.Currency().CurrencyConvertToGbp(currencyCode, amount, conversionDate);
}
public int CurrencyExchangeRateInsert(int exchangeRateSource, string currencyCode,
decimal currencyUnitsPerGbp, DateTime periodStart, DateTime periodEnd, bool checkOverride = false)
{
return new Data.Database.Account.Currency().CurrencyExchangeRateInsert(exchangeRateSource, currencyCode,
currencyUnitsPerGbp, periodStart, periodEnd, checkOverride);
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace bnhtrade.Core.Logic.Account
{
public class Journal
{
public int AccountJournalInsert(int journalTypeId, DateTime entryDate, string currencyCode,
decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false)
{
return new Data.Database.Account.CreateJournal().AccountJournalInsert(journalTypeId, entryDate, currencyCode,
amount, debitAccountId, creditAccountId, lockEntry);
}
public bool AccountJournalDelete(int accountJournalId)
{
return new Data.Database.Account.DeleteJournal().AccountJournalDelete(accountJournalId);
}
}
}

View File

@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace bnhtrade.Core.Logic.Account namespace bnhtrade.Core.Logic.Account
{ {
public class PurchaseInvoice : Core.Data.Database.Account.PurchaseInvoice public class PurchaseInvoice : Core.Data.Database.Account.ReadPurchaseInvoice
{ {
} }
} }

View File

@@ -10,12 +10,12 @@ namespace bnhtrade.Core.Logic.Account
{ {
public List<Model.Account.PurchaseInvoiceLineStatus> ReadLineStatusToList() public List<Model.Account.PurchaseInvoiceLineStatus> ReadLineStatusToList()
{ {
return new Data.Database.Account.PurchaseInvoiceLineStatus().Read().Values.ToList(); return new Data.Database.Account.ReadPurchaseInvoiceLineStatus().Read().Values.ToList();
} }
public List<Model.Account.PurchaseInvoiceLineSummary> GetLineSummary(DateTime maxDate, string lineStatus, List<string> wordSearchList) public List<Model.Account.PurchaseInvoiceLineSummary> GetLineSummary(DateTime maxDate, string lineStatus, List<string> wordSearchList)
{ {
return new Data.Database.Account.PurchaseInvoiceLineSummary().Read(maxDate,lineStatus, wordSearchList); return new Data.Database.Account.ReadPurchaseInvoiceLineSummary().Read(maxDate,lineStatus, wordSearchList);
} }
} }
} }

View File

@@ -229,532 +229,6 @@ namespace bnhtrade.Core
} }
} }
namespace Account
{
public class AccountQuery
{
// externally called & internal
public static decimal CurrencyConvertToGbp(string sqlConnectionString, string currencyCode, decimal amount, DateTime conversionDate)
{
if (currencyCode == "GBP" || amount == 0M)
{
return amount;
}
if (currencyCode.Length != 3)
{
throw new Exception("Invalid currency code '" + currencyCode + "'");
}
using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString))
{
sqlConn.Open();
using (SqlCommand cmd = new SqlCommand(@"
SELECT CurrencyUnitsPerGBP
FROM tblAccountExchangeRate
WHERE CurrencyCode=@currencyCode AND StartDate<=@conversionDate AND EndDate>@conversionDate
", sqlConn))
{
cmd.Parameters.AddWithValue("@currencyCode", currencyCode);
cmd.Parameters.AddWithValue("@conversionDate", conversionDate);
object result = cmd.ExecuteScalar();
if (result != null)
{
return amount / Convert.ToDecimal(result);
}
}
// return reason for no record found
using (SqlCommand cmd = new SqlCommand(@"
SELECT CurrencyUnitsPerGBP
FROM tblAccountExchangeRate
WHERE CurrencyCode=@currencyCode
", sqlConn))
{
cmd.Parameters.AddWithValue("@currencyCode", currencyCode);
object result = cmd.ExecuteScalar();
if (result == null)
{
throw new Exception("Currency code '" + currencyCode + "' does not exist in Exchange Rate table");
}
else
{
throw new Exception("Date range for " + currencyCode + " " + conversionDate.ToShortDateString() + " " +
conversionDate.ToLongTimeString() + "' does not exist in Exchange Rate table");
}
}
}
}
// externally called
public static int CurrencyExchangeRateInsert(string sqlConnectionString, int exchangeRateSource, string currencyCode,
decimal currencyUnitsPerGbp, DateTime periodStart, DateTime periodEnd, bool checkOverride = false)
{
currencyUnitsPerGbp = decimal.Round(currencyUnitsPerGbp, 4);
periodStart = DateTime.SpecifyKind(periodStart, DateTimeKind.Utc);
periodEnd = DateTime.SpecifyKind(periodEnd, DateTimeKind.Utc);
// CHECKS
// HMRC source only
if (exchangeRateSource != 1)
{
throw new Exception("Function does not currently accept exchange rates from sources other than HMRC");
}
// currency code upper case only
currencyCode = currencyCode.ToUpper();
if (currencyCode.Length != 3)
{
throw new Exception("Invalid currency code '" + currencyCode +"'");
}
if (periodEnd <= periodStart)
{
throw new Exception("Invalid date period.");
}
if (checkOverride == false && (periodEnd - periodStart).Days > 31)
{
throw new Exception("Date period is greater than 31 days.");
}
// retirve previous data
DateTime? periodEndLast = null;
using (SqlConnection sqlConn = new SqlConnection(sqlConnectionString))
{
sqlConn.Open();
using (SqlCommand cmd = new SqlCommand(@"
SELECT Max(tblAccountExchangeRate.EndDate) AS MaxOfEndDate
FROM tblAccountExchangeRate
WHERE (((tblAccountExchangeRate.CurrencyCode) = @currencyCode))
", sqlConn))
{
cmd.Parameters.AddWithValue("@currencyCode", currencyCode);
object obj = cmd.ExecuteScalar();
// currency code not existing
if (obj == DBNull.Value && checkOverride == false)
{
throw new Exception("Currency code '" + currencyCode + "' does not exist in table");
}
// currency code exists
else
{
periodEndLast = DateTime.SpecifyKind(Convert.ToDateTime(obj), DateTimeKind.Utc);
if (periodStart != periodEndLast)
{
throw new Exception("Invalid period start date -- must equal previous period end-date.");
}
}
}
// retrive previous exchange rate and check
decimal currencyUnitsPerGbpLast = 0;
if (periodEndLast != null)
{
using (SqlCommand cmd = new SqlCommand(@"
SELECT tblAccountExchangeRate.AccountExchangeRateID, tblAccountExchangeRate.CurrencyUnitsPerGBP
FROM tblAccountExchangeRate
WHERE (tblAccountExchangeRate.EndDate = @periodEndLast)
AND (CurrencyCode = @currencyCode);
", sqlConn))
{
cmd.Parameters.AddWithValue("@periodEndLast", periodEndLast);
cmd.Parameters.AddWithValue("@currencyCode", currencyCode);
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
currencyUnitsPerGbpLast = reader.GetDecimal(1);
}
else
{
throw new Exception("Error that shouldn't happen! Check code @ 5129f3e6-2f7e-4883-bc73-b317d8fa4050");
}
// error if >1 line
if (reader.Read())
{
string errText = "Multiple lines in currency exchange table for '" + currencyCode + "' where [EndDate]=" + periodEndLast.ToString();
new Logic.Log.LogEvent().LogError(errText);
throw new Exception(errText);
}
}
}
}
// check difference between current and previous exchange rates isn't too great
if (checkOverride == false &&
(currencyUnitsPerGbpLast > (currencyUnitsPerGbp * 1.05m) || currencyUnitsPerGbpLast < (currencyUnitsPerGbp * 0.95m))
)
{
throw new Exception("Difference between supplied and previous exchange rates is greater than 5%");
}
// MAKE THE INSERT
int recordId = 0;
using (SqlCommand cmd = new SqlCommand(@"
INSERT INTO tblAccountExchangeRate (ExchangeRateSource, CurrencyCode, CurrencyUnitsPerGBP, StartDate, EndDate)
OUTPUT INSERTED.AccountExchangeRateID
VALUES (@exchangeRateSource, @currencyCode, @currencyUnitsPerGbp, @periodStart, @periodEnd);
", sqlConn))
{
cmd.Parameters.AddWithValue("@exchangeRateSource", exchangeRateSource);
cmd.Parameters.AddWithValue("@currencyCode", currencyCode);
cmd.Parameters.AddWithValue("@currencyUnitsPerGbp", currencyUnitsPerGbp);
cmd.Parameters.AddWithValue("@periodStart", periodStart);
cmd.Parameters.AddWithValue("@periodEnd", periodEnd);
recordId = (int)cmd.ExecuteScalar();
if (recordId < 1)
{
throw new Exception("Error inserting record, did not retrive new record ID.");
}
}
return recordId;
}
}
// internally called
public static bool AccountJournalEntryIsLocked(string sqlConnectionString, 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;
}
}
}
}
// externally called
public static int AccountJournalInsert(string sqlConnectionString, int journalTypeId, DateTime entryDate, string currencyCode,
decimal amount, int debitAccountId = 0, int creditAccountId = 0, bool lockEntry = false)
{
int defaultDebit = 0;
int defaultCredit = 0;
// ensure date is UTC
entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc);
// debit and credit locks are checked in journal post method
using (TransactionScope scope = new TransactionScope())
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
// insert the journal entry
int journalId;
using (SqlCommand cmd = new SqlCommand(@"
INSERT INTO tblAccountJournal
(AccountJournalTypeID, EntryDate, IsLocked)
OUTPUT INSERTED.AccountJournalID
VALUES
(@journalTypeId, @entryDate, @lockEntry)
", conn))
{
// add parameters
cmd.Parameters.AddWithValue("@journalTypeId", journalTypeId);
cmd.Parameters.AddWithValue("@entryDate", entryDate.ToUniversalTime());
cmd.Parameters.AddWithValue("@lockEntry", lockEntry);
//execute
journalId = (int)cmd.ExecuteScalar();
}
// insert journal entries
bool postResult = AccountJournalPostInsert(sqlConnectionString, journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId);
scope.Complete();
return journalId;
}
}
// externally called
// return false on locked journal entry
public static bool AccountJournalDelete(string sqlConnectionString, int accountJournalId)
{
// check if journal entry is locked
using (TransactionScope scope = new TransactionScope())
{
bool IsLocked = Account.AccountQuery.AccountJournalEntryIsLocked(sqlConnectionString, 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;
}
}
}
// internally called
private static bool AccountJournalPostInsert(string sqlConnectionString, int journalId, DateTime entryDate,
string currencyCode, decimal amount, int debitAccountId = 0, int creditAccountId = 0)
{
int defaultDebit;
int defaultCredit;
entryDate = DateTime.SpecifyKind(entryDate, DateTimeKind.Utc);
using (TransactionScope scope = new TransactionScope())
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
// ensure their are no other entries
using (SqlCommand cmd = new SqlCommand(@"
SELECT
Count(tblAccountJournalPost.AccountJournalPostID) AS CountOfAccountJournalPostID
FROM
tblAccountJournalPost
WHERE
(((tblAccountJournalPost.AccountJournalID)=@AccountJournalID));
", conn))
{
cmd.Parameters.AddWithValue("@AccountJournalID", journalId);
int count = (int)cmd.ExecuteScalar();
if (count > 0)
{
throw new Exception("Unable the insert journal posts, post already present AccountJournalID=" + journalId);
}
}
//checks
using (SqlCommand cmd = new SqlCommand(@"
SELECT
tblAccountJournalType.ChartOfAccountID_Debit, tblAccountJournalType.ChartOfAccountID_Credit
FROM
tblAccountJournal
INNER JOIN tblAccountJournalType
ON tblAccountJournal.AccountJournalTypeID = tblAccountJournalType.AccountJournalTypeID
WHERE
(((tblAccountJournal.AccountJournalID)=@journalId));
", conn))
{
cmd.Parameters.AddWithValue("@journalId", journalId);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
// debit check
if (reader.IsDBNull(0))
{
if (debitAccountId == 0)
{
throw new Exception("Debit Account ID required, default not set for journal type");
}
}
else
{
defaultDebit = reader.GetInt32(0);
if (debitAccountId == 0)
{
debitAccountId = defaultDebit;
}
else if (debitAccountId != defaultDebit)
{
throw new Exception("Debit Account ID supplied does not match default set for journal type");
}
}
// credit check
if (reader.IsDBNull(1))
{
if (creditAccountId == 0)
{
throw new Exception("Credit Account ID required, default not set for journal type");
}
}
else
{
defaultCredit = reader.GetInt32(1);
if (creditAccountId == 0)
{
creditAccountId = defaultCredit;
}
else if (creditAccountId != defaultCredit)
{
throw new Exception("Credit Account ID supplied does not match default set for journal type");
}
}
}
else
{
throw new Exception("AccountJournalID '" + journalId + "' does not exist.");
}
}
}
// currency conversion
if (currencyCode != "GBP")
{
amount = Core.Account.AccountQuery.CurrencyConvertToGbp(sqlConnectionString, currencyCode, amount, entryDate);
}
// ensure decimal is rounded
amount = Math.Round(amount, 2);
// insert debit post
using (SqlCommand cmd = new SqlCommand(@"
INSERT INTO tblAccountJournalPost
(AccountJournalID, AccountChartOfID, AmountGbp)
VALUES
(@AccountJournalId, @AccountChartOfId, @AmountGbp)
", conn))
{
// add parameters
cmd.Parameters.AddWithValue("@AccountJournalId", journalId);
cmd.Parameters.AddWithValue("@AccountChartOfId", debitAccountId);
cmd.Parameters.AddWithValue("@AmountGbp", amount);
cmd.ExecuteNonQuery();
}
// insert credit post
using (SqlCommand cmd = new SqlCommand(@"
INSERT INTO tblAccountJournalPost
(AccountJournalID, AccountChartOfID, AmountGbp)
VALUES
(@AccountJournalId, @AccountChartOfId, @AmountGbp)
", conn))
{
// add parameters
cmd.Parameters.AddWithValue("@AccountJournalId", journalId);
cmd.Parameters.AddWithValue("@AccountChartOfId", creditAccountId);
cmd.Parameters.AddWithValue("@AmountGbp", (amount * -1));
cmd.ExecuteNonQuery();
}
scope.Complete();
return true;
}
}
// externally called
public static bool AccountJournalPostUpdate(string sqlConnectionString, int journalId, string currencyCode, decimal amount,
int debitAccountId = 0, int creditAccountId = 0)
{
using (TransactionScope scope = new TransactionScope())
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
// retrive journal entry date
DateTime entryDate;
using (SqlCommand cmd = new SqlCommand(@"
SELECT
tblAccountJournal.EntryDate
FROM
tblAccountJournal
WHERE
(((tblAccountJournal.AccountJournalID)=@accountJournalId));
", conn))
{
cmd.Parameters.AddWithValue("@accountJournalId", journalId);
entryDate = DateTime.SpecifyKind((DateTime)cmd.ExecuteScalar(), DateTimeKind.Utc);
}
// delete the original posts
using (SqlCommand cmd = new SqlCommand(@"
DELETE FROM
tblAccountJournalPost
WHERE
(((tblAccountJournalPost.AccountJournalID)=@accountJournalId));
", conn))
{
cmd.Parameters.AddWithValue("@accountJournalId", journalId);
cmd.ExecuteNonQuery();
}
//insert new posts
bool postResult = AccountJournalPostInsert(sqlConnectionString, journalId, entryDate, currencyCode, amount, debitAccountId, creditAccountId);
// update modified date on journal
using (SqlCommand cmd = new SqlCommand(@"
UPDATE
tblAccountJournal
SET
tblAccountJournal.LastModified=@utcNow
WHERE
(((tblAccountJournal.AccountJournalID)=@accountJournalId));
", conn))
{
cmd.Parameters.AddWithValue("@accountJournalId", journalId);
cmd.Parameters.AddWithValue("@utcNow", DateTime.UtcNow);
cmd.ExecuteNonQuery();
}
scope.Complete();
}
return true;
}
}
}
namespace Sku namespace Sku
{ {
public class Sku public class Sku
@@ -885,7 +359,7 @@ namespace bnhtrade.Core
conn.Open(); conn.Open();
// add account journal entry // add account journal entry
int accountJournalId = Account.AccountQuery.AccountJournalInsert(sqlConnectionString, accountJournalType, entryDate, currencyCode, amount); int accountJournalId = new Logic.Account.Journal().AccountJournalInsert(accountJournalType, entryDate, currencyCode, amount);
// make the stock insert // make the stock insert
int stockId = WIP_StockInsertSub(sqlConnectionString, productId, conditionId, accountTaxCodeId, int stockId = WIP_StockInsertSub(sqlConnectionString, productId, conditionId, accountTaxCodeId,
@@ -1255,7 +729,7 @@ namespace bnhtrade.Core
} }
// delete account journal entry // delete account journal entry
Account.AccountQuery.AccountJournalDelete(sqlConnectionString, accountJournalId); new Data.Database.Account.DeleteJournal().AccountJournalDelete(accountJournalId);
scope.Complete(); scope.Complete();
} }
@@ -1986,8 +1460,8 @@ namespace bnhtrade.Core
conn.Open(); conn.Open();
// create account journal entry // create account journal entry
int journalId = Account.AccountQuery.AccountJournalInsert( int journalId = new Data.Database.Account.CreateJournal().AccountJournalInsert(
sqlConnectionString, accountJournalTypeIdNet, entryDate, currencyCode, amountNet, debitAccountId); accountJournalTypeIdNet, entryDate, currencyCode, amountNet, debitAccountId);
// add transaction to purchase line transaction table // add transaction to purchase line transaction table
using (SqlCommand cmd = new SqlCommand(@" using (SqlCommand cmd = new SqlCommand(@"
@@ -2049,8 +1523,7 @@ namespace bnhtrade.Core
} }
// make the update // make the update
bool result = Core.Account.AccountQuery.AccountJournalPostUpdate(sqlConnectionString, bool result = new Data.Database.Account.UpdateJournal().AccountJournalPostUpdate(accountJouranlId, currencyCode, amountNet, debitAccountId, creditAccountId);
accountJouranlId, currencyCode, amountNet, debitAccountId, creditAccountId);
scope.Complete(); scope.Complete();
} }
@@ -2147,7 +1620,7 @@ namespace bnhtrade.Core
} }
// delete account journal entry // delete account journal entry
Account.AccountQuery.AccountJournalDelete(sqlConnectionString, accountJournalId); new Data.Database.Account.DeleteJournal().AccountJournalDelete(accountJournalId);
scope.Complete(); scope.Complete();
} }

View File

@@ -16,21 +16,21 @@ namespace bnhtrade.Core.Test.Account
public void PurchaseInvoice() public void PurchaseInvoice()
{ {
var read = new Data.Database.Account.PurchaseInvoice(); var read = new Data.Database.Account.ReadPurchaseInvoice();
read.PurchaseInvoiceIdList = new List<int> { 14718, 100, 101, 102, 300, 400, 1200, 2734, 6339, 9999 }; // 10 in total read.PurchaseInvoiceIdList = new List<int> { 14718, 100, 101, 102, 300, 400, 1200, 2734, 6339, 9999 }; // 10 in total
var result = read.Read(); var result = read.Read();
} }
public void PurchaseInvoiceLine() public void PurchaseInvoiceLine()
{ {
var read = new Data.Database.Account.PurchaseInvoiceLine(); var read = new Data.Database.Account.ReadPurchaseInvoiceLine();
read.ItemDescription = new List<string> { "xbox", "kill" }; read.ItemDescription = new List<string> { "xbox", "kill" };
var result = read.Read(); var result = read.Read();
} }
public void Journal() public void Journal()
{ {
var read = new Data.Database.Account.Journal(); var read = new Data.Database.Account.ReadJournal();
read.AccountJournalId = new List<uint> { 123, 300, 324, 5678, 22 }; read.AccountJournalId = new List<uint> { 123, 300, 324, 5678, 22 };
var result = read.Read(); var result = read.Read();
} }