From 88159d4cc3db490915e12dbfab5ef68a94366560 Mon Sep 17 00:00:00 2001 From: Bobbie Hodgetts Date: Fri, 31 Jan 2020 11:32:54 +0000 Subject: [PATCH] Import Xero sales invoice flat-file Feature complete and tested --- .../BealeEngineering.Accounts/Form1.cs | 1 - .../BealeEngineering.Core.csproj | 34 +-- ...te.cs => CreatePurchaseOrderAllocation.cs} | 4 +- ...rchaseOrderGet.cs => ReadPurchaseOrder.cs} | 8 +- ...nGet.cs => ReadPurchaseOrderAllocation.cs} | 4 +- ...eaderGet.cs => ReadPurchaseOrderHeader.cs} | 4 +- .../Data/Database/Connection.cs | 2 + .../Data/Database/Contact/ContactHeaderGet.cs | 160 -------------- .../Data/Database/Contact/CreateContact.cs | 29 +++ .../Data/Database/Contact/ReadContact.cs | 191 +++++++++++++++++ .../Data/Database/Contact/UpdateContact.cs | 157 ++++++++++++++ .../Data/Database/Sale/CreateInvoice.cs | 26 +++ .../Sale/{InvoiceGet.cs => ReadInvoice.cs} | 12 +- ...voiceHeaderGet.cs => ReadInvoiceHeader.cs} | 27 +-- .../Data/Database/Sale/UpdateInvoice.cs | 201 ++++++++++++++++++ ...voiceGet.cs => ReadXeroInvoiceFlatFile.cs} | 8 +- .../Logic/Client/PurchaseOrderAutoAllocate.cs | 10 +- .../Logic/Import/XeroInvoiceFlatFile.cs | 136 ++++++++++++ .../Logic/Import/wipXeroInvoiceFlatFile.cs | 54 ----- .../Model/Client/PurchaseOrder.cs | 11 +- .../Model/Client/PurchaseOrderHeader.cs | 20 +- .../Model/Client/PurchaseOrderLine.cs | 16 -- .../Model/Contact/Address.cs | 29 +++ .../Model/Contact/Contact.cs | 76 +++++++ .../Model/Contact/ContactHeader.cs | 15 -- .../Model/Sale/Invoice.cs | 84 +++++++- .../Model/Sale/InvoiceHeader.cs | 32 ++- .../Model/Sale/InvoiceLine.cs | 23 -- .../Model/ValidateModel.cs | 33 +++ .../BealeEngineering.Core/Test/AUtoexec.cs | 27 ++- .../Test/Client/PurchaseOrder.cs | 2 +- .../Test/Contact/Contact.cs | 50 +++++ .../Test/Import/ImportFlatfile.cs | 15 +- .../Test/Sales/Invoice.cs | 23 +- 34 files changed, 1166 insertions(+), 358 deletions(-) rename BealeEngineering/BealeEngineering.Core/Data/Database/Client/{PurchaseOrderAllocationCreate.cs => CreatePurchaseOrderAllocation.cs} (93%) rename BealeEngineering/BealeEngineering.Core/Data/Database/Client/{PurchaseOrderGet.cs => ReadPurchaseOrder.cs} (92%) rename BealeEngineering/BealeEngineering.Core/Data/Database/Client/{PurchaseOrderAllocationGet.cs => ReadPurchaseOrderAllocation.cs} (94%) rename BealeEngineering/BealeEngineering.Core/Data/Database/Client/{PurchaseOrderHeaderGet.cs => ReadPurchaseOrderHeader.cs} (96%) delete mode 100644 BealeEngineering/BealeEngineering.Core/Data/Database/Contact/ContactHeaderGet.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Data/Database/Contact/CreateContact.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Data/Database/Contact/ReadContact.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Data/Database/Contact/UpdateContact.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Data/Database/Sale/CreateInvoice.cs rename BealeEngineering/BealeEngineering.Core/Data/Database/Sale/{InvoiceGet.cs => ReadInvoice.cs} (90%) rename BealeEngineering/BealeEngineering.Core/Data/Database/Sale/{InvoiceHeaderGet.cs => ReadInvoiceHeader.cs} (86%) create mode 100644 BealeEngineering/BealeEngineering.Core/Data/Database/Sale/UpdateInvoice.cs rename BealeEngineering/BealeEngineering.Core/Data/Xero/{SaleInvoiceGet.cs => ReadXeroInvoiceFlatFile.cs} (96%) create mode 100644 BealeEngineering/BealeEngineering.Core/Logic/Import/XeroInvoiceFlatFile.cs delete mode 100644 BealeEngineering/BealeEngineering.Core/Logic/Import/wipXeroInvoiceFlatFile.cs delete mode 100644 BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrderLine.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Model/Contact/Address.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Model/Contact/Contact.cs delete mode 100644 BealeEngineering/BealeEngineering.Core/Model/Contact/ContactHeader.cs delete mode 100644 BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceLine.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Model/ValidateModel.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Test/Contact/Contact.cs diff --git a/BealeEngineering/BealeEngineering.Accounts/Form1.cs b/BealeEngineering/BealeEngineering.Accounts/Form1.cs index 8a0c46a..b166419 100644 --- a/BealeEngineering/BealeEngineering.Accounts/Form1.cs +++ b/BealeEngineering/BealeEngineering.Accounts/Form1.cs @@ -24,7 +24,6 @@ namespace BealeEngineering.Accounts string conString = ConfigurationManager.ConnectionStrings["BealeEngSQLDb"].ToString(); var inst = new Core.Test.Autoexec(conString); - inst.Start(); } } } diff --git a/BealeEngineering/BealeEngineering.Core/BealeEngineering.Core.csproj b/BealeEngineering/BealeEngineering.Core/BealeEngineering.Core.csproj index 6bdac92..7472117 100644 --- a/BealeEngineering/BealeEngineering.Core/BealeEngineering.Core.csproj +++ b/BealeEngineering/BealeEngineering.Core/BealeEngineering.Core.csproj @@ -42,6 +42,7 @@ + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll @@ -50,6 +51,7 @@ ..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll + @@ -58,38 +60,44 @@ - - - - - - + + + + + + + + + + + - - - + + + - - + - + + - + + diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderAllocationCreate.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/CreatePurchaseOrderAllocation.cs similarity index 93% rename from BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderAllocationCreate.cs rename to BealeEngineering/BealeEngineering.Core/Data/Database/Client/CreatePurchaseOrderAllocation.cs index dfb6200..a18cf9a 100644 --- a/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderAllocationCreate.cs +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/CreatePurchaseOrderAllocation.cs @@ -8,9 +8,9 @@ using System.Transactions; namespace BealeEngineering.Core.Data.Database.Client { - public class PurchaseOrderAllocationCreate : Connection + public class CreatePurchaseOrderAllocation : Connection { - public PurchaseOrderAllocationCreate(string sqlConnectionString) : base(sqlConnectionString) + public CreatePurchaseOrderAllocation(string sqlConnectionString) : base(sqlConnectionString) { } diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderGet.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/ReadPurchaseOrder.cs similarity index 92% rename from BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderGet.cs rename to BealeEngineering/BealeEngineering.Core/Data/Database/Client/ReadPurchaseOrder.cs index eab592c..d6c17c3 100644 --- a/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderGet.cs +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/ReadPurchaseOrder.cs @@ -9,9 +9,9 @@ using System.Threading.Tasks; namespace BealeEngineering.Core.Data.Database.Client { - public class PurchaseOrderGet : PurchaseOrderHeaderGet + public class ReadPurchaseOrder : ReadPurchaseOrderHeader { - public PurchaseOrderGet(string sqlConnectionString) : base(sqlConnectionString) + public ReadPurchaseOrder(string sqlConnectionString) : base(sqlConnectionString) { } @@ -73,7 +73,7 @@ namespace BealeEngineering.Core.Data.Database.Client var orderDictionary = new Dictionary(); - var orderList = conn.Query + var orderList = conn.Query ( sqlString, (order, orderDetail) => @@ -83,7 +83,7 @@ namespace BealeEngineering.Core.Data.Database.Client if (!orderDictionary.TryGetValue(order.ClientPurchaseOrderID, out orderEntry)) { orderEntry = order; - orderEntry.OrderLineList = new List(); + orderEntry.OrderLineList = new List(); orderDictionary.Add(orderEntry.ClientPurchaseOrderID, orderEntry); } diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderAllocationGet.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/ReadPurchaseOrderAllocation.cs similarity index 94% rename from BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderAllocationGet.cs rename to BealeEngineering/BealeEngineering.Core/Data/Database/Client/ReadPurchaseOrderAllocation.cs index 4d10a63..b730d88 100644 --- a/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderAllocationGet.cs +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/ReadPurchaseOrderAllocation.cs @@ -7,9 +7,9 @@ using System.Threading.Tasks; namespace BealeEngineering.Core.Data.Database.Client { - public class PurchaseOrderAllocationGet : Connection + public class ReadPurchaseOrderAllocation : Connection { - public PurchaseOrderAllocationGet(string sqlConnectionString) : base(sqlConnectionString) + public ReadPurchaseOrderAllocation(string sqlConnectionString) : base(sqlConnectionString) { } diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderHeaderGet.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/ReadPurchaseOrderHeader.cs similarity index 96% rename from BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderHeaderGet.cs rename to BealeEngineering/BealeEngineering.Core/Data/Database/Client/ReadPurchaseOrderHeader.cs index 4b80262..a2f696d 100644 --- a/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderHeaderGet.cs +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/ReadPurchaseOrderHeader.cs @@ -8,9 +8,9 @@ using Dapper; namespace BealeEngineering.Core.Data.Database.Client { - public class PurchaseOrderHeaderGet : Connection + public class ReadPurchaseOrderHeader : Connection { - public PurchaseOrderHeaderGet(string sqlConnectionString) : base(sqlConnectionString) + public ReadPurchaseOrderHeader(string sqlConnectionString) : base(sqlConnectionString) { } diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Connection.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Connection.cs index aeeaf0f..6d9646c 100644 --- a/BealeEngineering/BealeEngineering.Core/Data/Database/Connection.cs +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Connection.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Dapper; +using System.Data.SqlClient; namespace BealeEngineering.Core.Data.Database { diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/ContactHeaderGet.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/ContactHeaderGet.cs deleted file mode 100644 index 4bc183c..0000000 --- a/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/ContactHeaderGet.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.SqlClient; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace BealeEngineering.Core.Data.Database.Contact -{ - public class ContactHeaderGet : Connection - { - public ContactHeaderGet(string sqlConnectionString) : base(sqlConnectionString) - { - - } - - private Dictionary cacheContact = new Dictionary(); - public int NumberRequested = 0; - public int NumberRetrived = 0; - public int NumberRetrivedUnique = 0; - public int NumberFailed = 0; - public Model.Contact.ContactHeader ById(int contactId, bool cacheClear = false) - { - var contactIdList = new List(); - contactIdList.Add(contactId); - var resultList = ByIdList(contactIdList, cacheClear); - if (cacheContact.ContainsKey(contactId)) - { - return cacheContact[contactId]; - } - else - { - return null; - } - } - public Dictionary ByIdList(List contactIdList, bool cacheClear = false) - { - ClearStats(); - - // check list for values - if (!contactIdList.Any()) - { - return null; - } - - if (cacheClear) - { - cacheContact = new Dictionary(); - } - - // build list of contactIds to lookup from db - var idLookupList = new List(); - foreach (int contactId in contactIdList) - { - if (!cacheContact.ContainsKey(contactId)) - { - idLookupList.Add(contactId); - } - } - - // query db and add to cache - if (idLookupList.Any()) - { - //build sql string - string sqlString = null; - foreach (int id in idLookupList) - { - int count = 0; - if (count == 0) - { - sqlString = " WHERE ContactId=@contactId" + count; - } - else - { - sqlString = sqlString + " OR ContactId=@contactId" + count; - } - count = count + 1; - } - - sqlString = @" - SELECT - ContactID - ,ContactName - ,EmailAddress - FROM Contact - " + sqlString; - - // run query - using (SqlConnection conn = new SqlConnection(sqlConnectionString)) - { - conn.Open(); - - using (SqlCommand cmd = new SqlCommand(sqlString, conn)) - { - foreach (int id in idLookupList) - { - int count = 0; - cmd.Parameters.AddWithValue("@contactId" + count, id); - count = count + 1; - } - - using (SqlDataReader reader = cmd.ExecuteReader()) - { - if (!reader.HasRows) - { - // do something - } - else - { - while (reader.Read()) - { - // load data into cache - var contact = new Model.Contact.ContactHeader(); - contact.ContactId = reader.GetInt32(0); - contact.ContactName = reader.GetString(1); - contact.EmailAddress = reader.GetString(2); - - if (cacheContact.ContainsKey(contact.ContactId)) - { - cacheContact.Remove(contact.ContactId); - } - - cacheContact.Add(contact.ContactId, contact); - } - } - } - } - } - } - // build and return list - var returnList = new Dictionary(); - foreach (var contactId in contactIdList) - { - NumberRequested = NumberRequested + 1; - if (cacheContact.ContainsKey(contactId)) - { - if (!returnList.ContainsKey(contactId)) - { - returnList.Add(contactId, cacheContact[contactId]); - } - } - else - { - NumberFailed = NumberFailed + 1; - } - } - NumberRetrived = NumberRequested - NumberFailed; - NumberRetrivedUnique = returnList.Count(); - - return returnList; - } - private void ClearStats() - { - NumberRequested = 0; - NumberRetrived = 0; - NumberRetrivedUnique = 0; - NumberFailed = 0; - } - } -} diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/CreateContact.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/CreateContact.cs new file mode 100644 index 0000000..1097dae --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/CreateContact.cs @@ -0,0 +1,29 @@ +using Dapper; +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Transactions; + +namespace BealeEngineering.Core.Data.Database.Contact +{ + public class CreateContact : Connection + { + public CreateContact(string sqlConnectionString) : base(sqlConnectionString) + { + + } + public void ByContact(Model.Contact.Contact contact) + { + var list = new List { contact }; + ByContactList(list); + } + public void ByContactList(List contactList) + { + var updateContact = new UpdateContact(sqlConnectionString); + updateContact.ByContactList(contactList, true); + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/ReadContact.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/ReadContact.cs new file mode 100644 index 0000000..ffc8a82 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/ReadContact.cs @@ -0,0 +1,191 @@ +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using Dapper; + +namespace BealeEngineering.Core.Data.Database.Contact +{ + public class ReadContact : Connection + { + public ReadContact(string sqlConnectionString) : base(sqlConnectionString) + { + CacheInnit(); + } + private Dictionary cacheId; + private Dictionary cacheName; + public Model.Contact.Contact ByContactId(int contactId, bool cacheClear = false) + { + var contactIdList = new List(); + contactIdList.Add(contactId); + var resultList = ByContactId(contactIdList, cacheClear); + if (resultList == null || !resultList.Any()) + { return null; } + else + { return resultList[0]; } + } + public List ByContactId(List contactIdList, bool cacheClear = false) + { + if (cacheClear) + { CacheInnit(); } + + if (!contactIdList.Any()) + { return null; } + + // find items not in cache + var dbQuery = new List(); + foreach (var id in contactIdList) + { + if (!cacheId.ContainsKey(id)) + { dbQuery.Add(id); } + } + + // populate cache with values from db + if (dbQuery.Any()) + { + string whereString = @" + AND ContactID IN @contactID"; + + var parameters = new DynamicParameters(); + parameters.Add("@contactID", dbQuery); + + Execute(whereString, parameters); + } + + // query chache for return + var returnList = new List(); + foreach (var id in contactIdList) + { + if (cacheId.ContainsKey(id)) + { returnList.Add(cacheId[id]); } + } + + if (returnList.Any()) + { return returnList; } + else + { return null; } + } + + /// + /// Get contact by unique contact name. + /// + /// Unique contact name + /// Force database read + /// Contact Header information + public Model.Contact.Contact ByContactName(string contactName, bool cacheClear = false) + { + var contactNameList = new List(); + contactNameList.Add(contactName); + var resultList = ByContactName(contactNameList, cacheClear); + if (resultList == null || !resultList.Any()) + { return null; } + else + { return resultList[0]; } + } + public List ByContactName(List contactNameList, bool cacheClear = false) + { + if (cacheClear) + { CacheInnit(); } + + if (!contactNameList.Any()) + { return null; } + + // find items not in cache + List dbQuery = new List(); + foreach (var name in contactNameList) + { + if (!cacheName.ContainsKey(name)) + { dbQuery.Add(name); } + } + + // populate cache with values from db + if (dbQuery.Any()) + { + string whereString = @" + AND ContactName IN @contactName"; + + var parameters = new DynamicParameters(); + parameters.Add("@contactName", dbQuery); + + Execute(whereString, parameters); + } + + // query chache for return + var returnList = new List(); + foreach (var name in contactNameList) + { + if (cacheName.ContainsKey(name)) + { returnList.Add(cacheId[cacheName[name]]); } + } + + if (returnList.Any()) + { return returnList; } + else + { return null; } + } + private void CacheAdd(Model.Contact.Contact contact) + { + if (cacheId.ContainsKey(contact.ContactId)) + { CacheRemove(contact); } + cacheId.Add(contact.ContactId, contact); + cacheName.Add(contact.ContactName, contact.ContactId); + } + private void CacheInnit() + { + cacheId = new Dictionary(); + cacheName = new Dictionary(); + } + private void CacheRemove(Model.Contact.Contact contact) + { + cacheId.Remove(contact.ContactId); + cacheName.Remove(contact.ContactName); + + } + private void Execute(string sqlWhere, DynamicParameters parameters) + { + var contactList = new List(); + + string sqlString = @" + SELECT + [ContactID] + ,[ContactName] + ,[EmailAddress] + ,[PrimaryPersonFirstName] + ,[PrimaryPersonSurname] + ,[PrimaryPersonEmail] + ,[POAddressLine1] AS AddressLine1 + ,[POAddressLine2] AS AddressLine2 + ,[POAddressLine3] AS AddressLine3 + ,[POAddressLine4] AS AddressLine4 + ,[POAddressCity] AS City + ,[POAddressRegion] AS Region + ,[POAddressPostalCode] AS PostalCode + ,[POAddressCountry] AS Country + FROM Contact + WHERE 1=1" + sqlWhere; + + // make the call + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + contactList = conn.Query + ( + sqlString, + (contact, address) => + { + contact.PostalAddress = address; + return contact; + }, + parameters, + splitOn: "AddressLine1") + .Distinct() + .ToList(); + } + + foreach (var contact in contactList) + { + CacheAdd(contact); + } + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/UpdateContact.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/UpdateContact.cs new file mode 100644 index 0000000..f3f77c5 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/UpdateContact.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Transactions; +using Dapper; + +namespace BealeEngineering.Core.Data.Database.Contact +{ + public class UpdateContact : Connection + { + public UpdateContact(string sqlConnectionString) : base(sqlConnectionString) + { + + } + public void ByContact(Model.Contact.Contact contact, bool insertNew = false) + { + var list = new List { contact }; + ByContactList(list, insertNew); + } + public void ByContactList(List contactList, bool insertNew = false) + { + // check the list + CheckList(ref contactList); + + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + foreach (var contact in contactList) + { + // build the sql string + string sqlString = @" + UPDATE Contact + SET + [ContactName] = @contactName + ,[EmailAddress] = @emailAddress + ,[PrimaryPersonFirstName] = @primaryPersonFirstName + ,[PrimaryPersonSurname] = @primaryPersonSurname + ,[PrimaryPersonEmail] = @primaryPersonEmail + ,[POAddressLine1] = @poAddressLine1 + ,[POAddressLine2] = @poAddressLine2 + ,[POAddressLine3] = @poAddressLine3 + ,[POAddressLine4] = @poAddressLine4 + ,[POAddressCity] = @poAddressCity + ,[POAddressRegion] = @poAddressRegion + ,[POAddressPostalCode] = @poAddressPostalCode + ,[POAddressCountry] = @poAddressCountry + WHERE ContactName = @contactName"; + + if (insertNew) + { + sqlString = sqlString + @" + IF @@ROWCOUNT = 0 + INSERT INTO Contact( + [ContactName] + ,[EmailAddress] + ,[PrimaryPersonFirstName] + ,[PrimaryPersonSurname] + ,[PrimaryPersonEmail] + ,[POAddressLine1] + ,[POAddressLine2] + ,[POAddressLine3] + ,[POAddressLine4] + ,[POAddressCity] + ,[POAddressRegion] + ,[POAddressPostalCode] + ,[POAddressCountry] + ) + VALUES( + @contactName + ,@emailAddress + ,@primaryPersonFirstName + ,@primaryPersonSurname + ,@primaryPersonEmail + ,@poAddressLine1 + ,@poAddressLine2 + ,@poAddressLine3 + ,@poAddressLine4 + ,@poAddressCity + ,@poAddressRegion + ,@poAddressPostalCode + ,@poAddressCountry + )"; + } + + using (SqlCommand cmd = new SqlCommand(sqlString, conn)) + { + cmd.Parameters.AddWithValue("@contactName", contact.ContactName); + if (!string.IsNullOrWhiteSpace(contact.EmailAddress)) + { cmd.Parameters.AddWithValue("@emailAddress", contact.EmailAddress); } + else { cmd.Parameters.AddWithValue("@emailAddress", DBNull.Value); } + cmd.Parameters.AddWithValue("@primaryPersonFirstName", DBNull.Value); + cmd.Parameters.AddWithValue("@primaryPersonSurname", DBNull.Value); + cmd.Parameters.AddWithValue("@primaryPersonEmail", DBNull.Value); + if (contact.PostalAddressIsSet) + { + if (!string.IsNullOrWhiteSpace(contact.PostalAddress.AddressLine1)) + { cmd.Parameters.AddWithValue("@poAddressLine1", contact.PostalAddress.AddressLine1); } + else { cmd.Parameters.AddWithValue("@poAddressLine1", DBNull.Value); } + if (!string.IsNullOrWhiteSpace(contact.PostalAddress.AddressLine2)) + { cmd.Parameters.AddWithValue("@poAddressLine2", contact.PostalAddress.AddressLine2); } + else { cmd.Parameters.AddWithValue("@poAddressLine2", DBNull.Value); } + if (!string.IsNullOrWhiteSpace(contact.PostalAddress.AddressLine3)) + { cmd.Parameters.AddWithValue("@poAddressLine3", contact.PostalAddress.AddressLine3); } + else { cmd.Parameters.AddWithValue("@poAddressLine3", DBNull.Value); } + if (!string.IsNullOrWhiteSpace(contact.PostalAddress.AddressLine4)) + { cmd.Parameters.AddWithValue("@poAddressLine4", contact.PostalAddress.AddressLine4); } + else { cmd.Parameters.AddWithValue("@poAddressLine4", DBNull.Value); } + if (!string.IsNullOrWhiteSpace(contact.PostalAddress.City)) + { cmd.Parameters.AddWithValue("@poAddressCity", contact.PostalAddress.City); } + else { cmd.Parameters.AddWithValue("@poAddressCity", DBNull.Value); } + if (!string.IsNullOrWhiteSpace(contact.PostalAddress.Region)) + { cmd.Parameters.AddWithValue("@poAddressRegion", contact.PostalAddress.Region); } + else { cmd.Parameters.AddWithValue("@poAddressRegion", DBNull.Value); } + if (!string.IsNullOrWhiteSpace(contact.PostalAddress.PostalCode)) + { cmd.Parameters.AddWithValue("@poAddressPostalCode", contact.PostalAddress.PostalCode); } + else { cmd.Parameters.AddWithValue("@poAddressPostalCode", DBNull.Value); } + if (!string.IsNullOrWhiteSpace(contact.PostalAddress.Country)) + { cmd.Parameters.AddWithValue("@poAddressCountry", contact.PostalAddress.Country); } + else { cmd.Parameters.AddWithValue("@poAddressCountry", DBNull.Value); } + } + else + { + cmd.Parameters.AddWithValue("@poAddressLine1", DBNull.Value); + cmd.Parameters.AddWithValue("@poAddressLine2", DBNull.Value); + cmd.Parameters.AddWithValue("@poAddressLine3", DBNull.Value); + cmd.Parameters.AddWithValue("@poAddressLine4", DBNull.Value); + cmd.Parameters.AddWithValue("@poAddressCity", DBNull.Value); + cmd.Parameters.AddWithValue("@poAddressRegion", DBNull.Value); + cmd.Parameters.AddWithValue("@poAddressPostalCode", DBNull.Value); + cmd.Parameters.AddWithValue("@poAddressCountry", DBNull.Value); + } + + int effected = (int)cmd.ExecuteNonQuery(); + } + } + scope.Complete(); + } + } + private void CheckList(ref List contactList) + { + var tempDic = new Dictionary(); + foreach(var item in contactList) + { + if (tempDic.ContainsKey(item.ContactName)) + { throw new Exception("Duplicate contact name in list."); } + else { tempDic.Add(item.ContactName, 0); } + if (!item.IsValid()) + { throw new Exception("Validation check failed: " + item.ValidationResults[0]); } + } + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/CreateInvoice.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/CreateInvoice.cs new file mode 100644 index 0000000..851007a --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/CreateInvoice.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Data.Database.Sale +{ + public class CreateInvoice : Connection + { + public CreateInvoice(string sqlConnectionString) : base(sqlConnectionString) + { + + } + public void ByInvoice(Model.Sale.Invoice invoice) + { + var invoiceList = new List { invoice }; + ByInvoiceList(invoiceList); + } + public void ByInvoiceList(List invoiceList) + { + var updateInvoice = new UpdateInvoice(sqlConnectionString); + updateInvoice.ByInvoiceList(invoiceList, true); + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/InvoiceGet.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/ReadInvoice.cs similarity index 90% rename from BealeEngineering/BealeEngineering.Core/Data/Database/Sale/InvoiceGet.cs rename to BealeEngineering/BealeEngineering.Core/Data/Database/Sale/ReadInvoice.cs index 2ff0e1e..5afe4f2 100644 --- a/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/InvoiceGet.cs +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/ReadInvoice.cs @@ -8,9 +8,9 @@ using System.Threading.Tasks; namespace BealeEngineering.Core.Data.Database.Sale { - public class InvoiceGet : InvoiceHeaderGet + public class ReadInvoice : ReadInvoiceHeader { - public InvoiceGet(string sqlConnectionString) : base(sqlConnectionString) + public ReadInvoice(string sqlConnectionString) : base(sqlConnectionString) { } @@ -45,14 +45,15 @@ namespace BealeEngineering.Core.Data.Database.Sale var parameters = new DynamicParameters(); string sqlString = @" SELECT SaleInvoice.SaleInvoiceID - ,SaleInvoice.ContactID ,SaleInvoice.SaleInvoiceNumber ,SaleInvoice.InvoiceDate + ,Contact.ContactName ,SaleInvoice.DateDue ,SaleInvoice.Reference ,SaleInvoice.CurrencyCode ,SaleInvoice.InvoiceTotal ,SaleInvoice.TaxTotal + ,SaleInvoice.IsCreditNote ,SaleInvoiceLine.SaleInvoiceLineID ,SaleInvoiceLine.SaleInvoiceID ,SaleInvoiceLine.LineNumber @@ -66,6 +67,7 @@ namespace BealeEngineering.Core.Data.Database.Sale ,SaleInvoiceLine.TaxAmount ,SaleInvoiceLine.LineAmount FROM SaleInvoice + INNER JOIN Contact ON SaleInvoice.ContactID = Contact.ContactID LEFT OUTER JOIN SaleInvoiceLine ON SaleInvoice.SaleInvoiceID = SaleInvoiceLine.SaleInvoiceID"; AddSqlWhereString(ref sqlString, ref parameters); @@ -82,7 +84,7 @@ namespace BealeEngineering.Core.Data.Database.Sale var invoiceDictionary = new Dictionary(); - var invoiceList = conn.Query + var invoiceList = conn.Query ( sqlString, (invoice, invoiceDetail) => @@ -92,7 +94,7 @@ namespace BealeEngineering.Core.Data.Database.Sale if (!invoiceDictionary.TryGetValue(invoice.SaleInvoiceID, out invoiceEntry)) { invoiceEntry = invoice; - invoiceEntry.InvoiceLineList = new List(); + invoiceEntry.InvoiceLineList = new List(); invoiceDictionary.Add(invoiceEntry.SaleInvoiceID, invoiceEntry); } diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/InvoiceHeaderGet.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/ReadInvoiceHeader.cs similarity index 86% rename from BealeEngineering/BealeEngineering.Core/Data/Database/Sale/InvoiceHeaderGet.cs rename to BealeEngineering/BealeEngineering.Core/Data/Database/Sale/ReadInvoiceHeader.cs index c710717..acc59c6 100644 --- a/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/InvoiceHeaderGet.cs +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/ReadInvoiceHeader.cs @@ -8,9 +8,9 @@ using System.Threading.Tasks; namespace BealeEngineering.Core.Data.Database.Sale { - public class InvoiceHeaderGet : Connection + public class ReadInvoiceHeader : Connection { - public InvoiceHeaderGet(string sqlConnectionString) : base(sqlConnectionString) + public ReadInvoiceHeader(string sqlConnectionString) : base(sqlConnectionString) { } @@ -130,17 +130,18 @@ namespace BealeEngineering.Core.Data.Database.Sale // build the sql string and dapper parameters var parameters = new DynamicParameters(); string sqlString = @" - SELECT SaleInvoiceID - ,ContactID - ,SaleInvoiceNumber - ,InvoiceDate - ,DateDue - ,Reference - ,CurrencyCode - ,InvoiceTotal - ,TaxTotal - ,IsCreditNote - FROM SaleInvoice"; + SELECT SaleInvoice.SaleInvoiceID + ,SaleInvoice.SaleInvoiceNumber + ,SaleInvoice.InvoiceDate + ,SaleInvoice.DateDue + ,SaleInvoice.Reference + ,SaleInvoice.CurrencyCode + ,SaleInvoice.InvoiceTotal + ,SaleInvoice.TaxTotal + ,SaleInvoice.IsCreditNote + ,Contact.ContactName + FROM SaleInvoice + INNER JOIN Contact ON SaleInvoice.ContactID = Contact.ContactID"; AddSqlWhereString(ref sqlString, ref parameters); diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/UpdateInvoice.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/UpdateInvoice.cs new file mode 100644 index 0000000..7c5c9a3 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/UpdateInvoice.cs @@ -0,0 +1,201 @@ +using Dapper; +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Transactions; + +namespace BealeEngineering.Core.Data.Database.Sale +{ + public class UpdateInvoice : Connection + { + public UpdateInvoice(string sqlConnectionString) : base(sqlConnectionString) + { + + } + public void ByInvoice(Model.Sale.Invoice invoice, bool insertNew = false) + { + var invoiceList = new List { invoice }; + ByInvoiceList(invoiceList, insertNew); + } + public void ByInvoiceList(List invoiceList, bool insertNew = false) + { + // check the list + CheckList(ref invoiceList); + + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // get list of id from db + var dic = new Dictionary(); + string sqlString = @" + SELECT SaleInvoiceNumber, SaleInvoiceID + FROM saleInvoice + WHERE SaleInvoiceNumber IN @saleInvoiceNumber;"; + + var parameters = new DynamicParameters(); + parameters.Add("@saleInvoiceNumber", invoiceList.Select(o => o.SaleInvoiceNumber).ToList()); + using (var reader = conn.ExecuteReader(sqlString, parameters)) + { + while (reader.Read()) + { + if (!dic.ContainsKey(reader.GetString(0))) + { + dic.Add(reader.GetString(0), reader.GetInt32(1)); + } + } + } + + foreach (var invoice in invoiceList) + { + int saleInvoiceId = 0; + if (dic.ContainsKey(invoice.SaleInvoiceNumber)) + { + saleInvoiceId = dic[invoice.SaleInvoiceNumber]; + sqlString = @" + UPDATE SaleInvoice + SET + [ContactID] = (SELECT ContactID FROM Contact WHERE ContactName = @contactName) + ,[SaleInvoiceNumber] = @saleInvoiceNumber + ,[InvoiceDate] = @invoiceDate + ,[DateDue] = @dateDue + ,[Reference] = @reference + ,[CurrencyCode] = @currencyCode + ,[InvoiceTotal] = @invoiceTotal + ,[TaxTotal] = @taxTotal + ,[IsCreditNote] = @isCreditNote + WHERE SaleInvoiceID = @saleInvoiceId; + + DELETE FROM SaleInvoiceLine WHERE SaleInvoiceID = @saleInvoiceId;"; + } + else if (insertNew) + { + sqlString = @" + INSERT INTO SaleInvoice( + [ContactID] + ,[SaleInvoiceNumber] + ,[InvoiceDate] + ,[DateDue] + ,[Reference] + ,[CurrencyCode] + ,[InvoiceTotal] + ,[TaxTotal] + ,[IsCreditNote] + ) + OUTPUT INSERTED.SaleInvoiceID + VALUES( + (SELECT ContactID FROM Contact WHERE ContactName = @contactName) + @saleInvoiceNumber + @invoiceDate + @dateDue + @reference + @currencyCode + @invoiceTotal + @taxTotal + @isCreditNote + )"; + } + else + { + continue; + } + + using (SqlCommand cmd = new SqlCommand(sqlString, conn)) + { + cmd.Parameters.AddWithValue("@contactName", invoice.ContactName); + cmd.Parameters.AddWithValue("@saleInvoiceNumber", invoice.SaleInvoiceNumber); + cmd.Parameters.AddWithValue("@invoiceDate", invoice.InvoiceDate); + if (invoice.DueDate == null) { cmd.Parameters.AddWithValue("@dateDue", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@dateDue", invoice.DueDate); } + cmd.Parameters.AddWithValue("@reference", invoice.Reference); + cmd.Parameters.AddWithValue("@currencyCode", invoice.CurrencyCode); + cmd.Parameters.AddWithValue("@invoiceTotal", invoice.InvoiceTotal); + cmd.Parameters.AddWithValue("@taxTotal", invoice.TaxTotal); + cmd.Parameters.AddWithValue("@isCreditNote", invoice.IsCreditNote); + + if (saleInvoiceId == 0) + { + saleInvoiceId = (int)cmd.ExecuteScalar(); + } + else + { + cmd.Parameters.AddWithValue("@saleInvoiceId", saleInvoiceId); + int effected = cmd.ExecuteNonQuery(); + } + } + + // deal with lines + foreach (var line in invoice.InvoiceLineList) + { + sqlString = @" + INSERT INTO SaleInvoiceLine( + [SaleInvoiceID] + ,[LineNumber] + ,[InventoryItemCode] + ,[Description] + ,[Quantity] + ,[UnitAmount] + ,[Discount] + ,[AccountCode] + ,[TaxType] + ,[TaxAmount] + ,[LineAmount] + ) + VALUES( + @saleInvoiceID + ,@lineNumber + ,@inventoryItemCode + ,@description + ,@quantity + ,@unitAmount + ,@discount + ,@accountCode + ,@taxType + ,@taxAmount + ,@lineAmount + )"; + + using (SqlCommand cmd = new SqlCommand(sqlString, conn)) + { + cmd.Parameters.AddWithValue("@saleInvoiceID", saleInvoiceId); + cmd.Parameters.AddWithValue("@lineNumber", line.LineNumber); + if (string.IsNullOrWhiteSpace(line.InventoryItemCode)) { cmd.Parameters.AddWithValue("@inventoryItemCode", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@inventoryItemCode", line.InventoryItemCode); } + if (string.IsNullOrWhiteSpace(line.Description)) { cmd.Parameters.AddWithValue("@description", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@description", line.Description); } + cmd.Parameters.AddWithValue("@quantity", line.Quantity); + cmd.Parameters.AddWithValue("@unitAmount", line.UnitAmount); + if (line.Discount == null) { cmd.Parameters.AddWithValue("@discount", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@discount", line.Discount); } + if (string.IsNullOrWhiteSpace(line.AccountCode)) { cmd.Parameters.AddWithValue("@accountCode", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@accountCode", line.AccountCode); } + if (string.IsNullOrWhiteSpace(line.TaxType)) { cmd.Parameters.AddWithValue("@taxType", DBNull.Value); } + else { cmd.Parameters.AddWithValue("@taxType", line.TaxType); } + cmd.Parameters.AddWithValue("@taxAmount", line.TaxAmount); + cmd.Parameters.AddWithValue("@lineAmount", line.LineAmount); + + cmd.ExecuteNonQuery(); + } + } + } + scope.Complete(); + } + } + private void CheckList(ref List invoiceList) + { + var tempDic = new Dictionary(); + foreach (var item in invoiceList) + { + if (tempDic.ContainsKey(item.SaleInvoiceNumber)) + { throw new Exception("Duplicate contact name in list."); } + else { tempDic.Add(item.SaleInvoiceNumber, 0); } + if (!item.IsValid()) + { throw new Exception("Validation check failed: " + item.ValidationResults[0]); } + } + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Data/Xero/SaleInvoiceGet.cs b/BealeEngineering/BealeEngineering.Core/Data/Xero/ReadXeroInvoiceFlatFile.cs similarity index 96% rename from BealeEngineering/BealeEngineering.Core/Data/Xero/SaleInvoiceGet.cs rename to BealeEngineering/BealeEngineering.Core/Data/Xero/ReadXeroInvoiceFlatFile.cs index dfbb25f..a2c5926 100644 --- a/BealeEngineering/BealeEngineering.Core/Data/Xero/SaleInvoiceGet.cs +++ b/BealeEngineering/BealeEngineering.Core/Data/Xero/ReadXeroInvoiceFlatFile.cs @@ -10,9 +10,9 @@ using System.Threading.Tasks; namespace BealeEngineering.Core.Data.Xero.FlatFile { - public class ImportInvoice + public class ReadXeroInvoiceFlatFile { - public ImportInvoice() + public ReadXeroInvoiceFlatFile() { FileInputPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) @@ -31,7 +31,7 @@ namespace BealeEngineering.Core.Data.Xero.FlatFile /// /// /// Dictionary, Invoice numbers against data. - public Dictionary ByFilePath(string filePath) + public List ByFilePath(string filePath) { /* So here's the rub. Any field in a CSV doc that has a double quote wihtin, must be enclosed by double quotes and * the double quote within must be 'escaped' by a double quote. @@ -64,7 +64,7 @@ namespace BealeEngineering.Core.Data.Xero.FlatFile dto = csv.GetRecords().ToList(); } - return ConvertFlatDTO(ref dto); + return ConvertFlatDTO(ref dto).Values.ToList(); } private Dictionary ConvertFlatDTO(ref List flatData) diff --git a/BealeEngineering/BealeEngineering.Core/Logic/Client/PurchaseOrderAutoAllocate.cs b/BealeEngineering/BealeEngineering.Core/Logic/Client/PurchaseOrderAutoAllocate.cs index 9e8baf7..498a39e 100644 --- a/BealeEngineering/BealeEngineering.Core/Logic/Client/PurchaseOrderAutoAllocate.cs +++ b/BealeEngineering/BealeEngineering.Core/Logic/Client/PurchaseOrderAutoAllocate.cs @@ -27,7 +27,7 @@ namespace BealeEngineering.Core.Logic.Client Init(); // get list of unallocated invoices - var poAlloInstance = new Data.Database.Client.PurchaseOrderAllocationGet(SqlConnectionString); + var poAlloInstance = new Data.Database.Client.ReadPurchaseOrderAllocation(SqlConnectionString); var invoiceIdList = poAlloInstance.GetUnallocatedInvoiceId(); // nothing to allocate @@ -42,7 +42,7 @@ namespace BealeEngineering.Core.Logic.Client } // get invoice header info - var invoiceInst = new Data.Database.Sale.InvoiceHeaderGet(SqlConnectionString); + var invoiceInst = new Data.Database.Sale.ReadInvoiceHeader(SqlConnectionString); var invoiceList = invoiceInst.GetBySaleInvoiceId(invoiceIdList); // create lookup list for matching @@ -72,7 +72,7 @@ namespace BealeEngineering.Core.Logic.Client //get client POs from db that match reference list var referenceList = new List(); foreach(var item in lookupList) { referenceList.Add(item.Item2); } - var poInstance = new Data.Database.Client.PurchaseOrderGet(SqlConnectionString); + var poInstance = new Data.Database.Client.ReadPurchaseOrder(SqlConnectionString); poInstance.Reference = referenceList.Distinct().ToList(); poInstance.ReturnIsClosed = true; // <--------------------------------------------------change to false after var clientPoList = poInstance.GetByFilters(); @@ -90,7 +90,7 @@ namespace BealeEngineering.Core.Logic.Client // match contact ID foreach (var po in clientPoList) { - if (po.ContactID == lookupList[i].Item1.ContactID) + if (po.Contact.ContactName == lookupList[i].Item1.ContactName) { // match PO reference string reference = lookupList[i].Item2; @@ -143,7 +143,7 @@ namespace BealeEngineering.Core.Logic.Client // update db table if (invoiceIdToPoLineId.Count > 0) { - var instance2 = new Data.Database.Client.PurchaseOrderAllocationCreate(SqlConnectionString); + var instance2 = new Data.Database.Client.CreatePurchaseOrderAllocation(SqlConnectionString); InvoiceMatched = instance2.ByDictionary(invoiceIdToPoLineId); } IsComplete = true; diff --git a/BealeEngineering/BealeEngineering.Core/Logic/Import/XeroInvoiceFlatFile.cs b/BealeEngineering/BealeEngineering.Core/Logic/Import/XeroInvoiceFlatFile.cs new file mode 100644 index 0000000..3f41b7b --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Logic/Import/XeroInvoiceFlatFile.cs @@ -0,0 +1,136 @@ +using CsvHelper; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualBasic.FileIO; + +namespace BealeEngineering.Core.Logic.Import +{ + public class XeroInvoiceFlatFile + { + private List XeroInvoiceData { get; set; } + private List DbInvoiceData { get; set; } + public XeroInvoiceFlatFile(string sqlConnectionString) + { + SqlConnectionString = sqlConnectionString; + } + private string SqlConnectionString { get; set; } + public void ByFilePath(string filePath, bool updateContacts = true) + { + // get xero data + var data = new Data.Xero.FlatFile.ReadXeroInvoiceFlatFile(); + XeroInvoiceData = data.ByFilePath(filePath); + + // update db contacts + UpdateContacts(); + + // populate/map xero data to invoice model list + MapInvoiceDetails(); + + //check + if (XeroInvoiceData.Count != DbInvoiceData.Count) + { + throw new Exception("Something went wrong while mapping the data."); + } + + // send list to database (it will get validated in data layer) + if (DbInvoiceData.Any()) + { + var updateInvoice = new Data.Database.Sale.UpdateInvoice(SqlConnectionString); + updateInvoice.ByInvoiceList(DbInvoiceData); + } + } + /// + /// Get a dictionary of contacts, referenced by unique 'Contact Name'. Any contacts not found in db are + /// automatically added. + /// + /// + private void UpdateContacts() + { + var dicContacts = new Dictionary(); + for (var i = 0; i < XeroInvoiceData.Count; i++) + { + if (!dicContacts.ContainsKey(XeroInvoiceData[0].ContactName)) + { + dicContacts.Add(XeroInvoiceData[0].ContactName, MapContactDetails(XeroInvoiceData[0])); + } + } + if (dicContacts.Any()) + { + var updateContact = new Data.Database.Contact.UpdateContact(SqlConnectionString); + updateContact.ByContactList(dicContacts.Values.ToList()); + } + } + private Model.Contact.Contact MapContactDetails(Model.Import.XeroInvoiceFlatFile xeroData) + { + var contact = new Model.Contact.Contact(); + contact.ContactName = xeroData.ContactName; + if (string.IsNullOrWhiteSpace(xeroData.EmailAddress)) { contact.EmailAddress = null; } + else { contact.EmailAddress = xeroData.EmailAddress; } + + var address = new Model.Contact.Address(); + address.AddressLine1 = xeroData.POAddressLine1; + address.AddressLine2 = xeroData.POAddressLine2; + address.AddressLine3 = xeroData.POAddressLine3; + address.AddressLine4 = xeroData.POAddressLine4; + address.City = xeroData.POCity; + address.Country = xeroData.POCountry; + address.PostalCode = xeroData.POPostalCode; + address.Region = xeroData.PORegion; + + if (address.IsValid()) { contact.PostalAddress = address; } + + return contact; + } + private void MapInvoiceDetails() + { + DbInvoiceData = new List(); + for (var i = 0; i < XeroInvoiceData.Count; i++) + { + if (XeroInvoiceData[i] == null) { throw new NullReferenceException(); } + var invoice = new Model.Sale.Invoice(); + + invoice.ContactName = XeroInvoiceData[i].ContactName; + invoice.CurrencyCode = XeroInvoiceData[i].Currency; + invoice.DueDate = XeroInvoiceData[i].DueDate; + invoice.InvoiceDate = XeroInvoiceData[i].InvoiceDate; + invoice.InvoiceTotal = XeroInvoiceData[i].Total; + if (XeroInvoiceData[i].Type == "Sales invoice") { invoice.IsCreditNote = false; } + else if (XeroInvoiceData[i].Type == "Sales credit note") { invoice.IsCreditNote = true; } + else { throw new FormatException("Unknow value '" + XeroInvoiceData[i].Type + "' found in 'Type' field"); } + invoice.Reference = XeroInvoiceData[i].Reference; + invoice.SaleInvoiceNumber = XeroInvoiceData[i].InvoiceNumber; + invoice.TaxTotal = XeroInvoiceData[i].TaxTotal; + + invoice.InvoiceLineList = new List(); + for (int j = 0; j < XeroInvoiceData[i].LineItems.Count; j++) + { + if (XeroInvoiceData[i].LineItems[j] == null) { throw new NullReferenceException(); } + var invoiceLine = new Model.Sale.Invoice.InvoiceLine(); + + invoiceLine.LineNumber = j + 1; + invoiceLine.AccountCode = XeroInvoiceData[i].LineItems[j].AccountCode; + invoiceLine.Description = XeroInvoiceData[i].LineItems[j].Description; + invoiceLine.Discount = XeroInvoiceData[i].LineItems[j].Discount; + invoiceLine.InventoryItemCode = XeroInvoiceData[i].LineItems[j].InventoryItemCode; + invoiceLine.Quantity = XeroInvoiceData[i].LineItems[j].Quantity; + invoiceLine.TaxAmount = XeroInvoiceData[i].LineItems[j].TaxAmount; + invoiceLine.TaxType = XeroInvoiceData[i].LineItems[j].TaxType; + invoiceLine.UnitAmount = XeroInvoiceData[i].LineItems[j].UnitAmount; + + //check, as line amount is same as calculated in model + if (invoiceLine.LineAmount != XeroInvoiceData[i].LineItems[j].LineAmount) + { + throw new Exception("Imported line total does not equal caluclated."); + } + invoice.InvoiceLineList.Add(invoiceLine); + } + DbInvoiceData.Add(invoice); + } + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Logic/Import/wipXeroInvoiceFlatFile.cs b/BealeEngineering/BealeEngineering.Core/Logic/Import/wipXeroInvoiceFlatFile.cs deleted file mode 100644 index ded6d9d..0000000 --- a/BealeEngineering/BealeEngineering.Core/Logic/Import/wipXeroInvoiceFlatFile.cs +++ /dev/null @@ -1,54 +0,0 @@ -using CsvHelper; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.VisualBasic.FileIO; - -namespace BealeEngineering.Core.Logic.Import -{ - public class wipXeroInvoiceFlatFile - { - public wipXeroInvoiceFlatFile(string sqlConnectionString) - { - SqlConnectionString = sqlConnectionString; - } - private string SqlConnectionString { get; set; } - public void ByFilePath(string filePath) - { - // get model list - - - - - - - - - - - - - //// get db invoices - //var saleInvInst = new Data.Database.Sale.InvoiceGet(SqlConnectionString); - //saleInvInst.InvoiceNumber = invDictionary.Keys.ToList(); - //var dataInvList = saleInvInst.GetByFilters(); - - // compare - - - // update modified records - - // insert new records <--------- only insert approved invoices - - // delete records (is this possible??) <------- i think so, include deleted and voided in flatfile?? - - - - - } - } -} diff --git a/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrder.cs b/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrder.cs index 2a5ddba..67bb1ae 100644 --- a/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrder.cs +++ b/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrder.cs @@ -15,6 +15,15 @@ namespace BealeEngineering.Core.Model.Client else { return OrderLineList.Count; } } } - public List OrderLineList { get; set; } + public List OrderLineList { get; set; } + public class PurchaseOrderLine + { + public int ClientPurchaseOrderLineID { get; set; } + public int ClientPurchaseOrderID { get; set; } + public int LineNumber { get; set; } + public int ProjectJobID { get; set; } + public string Description { get; set; } + public decimal LineNetAmount { get; set; } + } } } diff --git a/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrderHeader.cs b/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrderHeader.cs index e61bcf1..2556435 100644 --- a/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrderHeader.cs +++ b/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrderHeader.cs @@ -11,28 +11,10 @@ namespace BealeEngineering.Core.Model.Client { public int ClientPurchaseOrderID { get; set; } public DateTime PurchaseOrderDate { get; set; } - public int ContactID { get; set; } + public Model.Contact.Contact Contact { get; set; } public string ClientReference { get; set; } public string RequestorEmail { get; set; } public decimal OrderTotal { get; set; } public bool IsClosed { get; set; } - //sealed PurchaseOrder CreatePurchaseOrder() - //{ - // PurchaseOrder destObject = new PurchaseOrder(); - // this.CopyProperties(destObject); // inside a class you want to copy from - - // return destObject; - - // Reflection.CopyProperties(this, destObject); // Same as above but directly calling the function - - // TestClass srcClass = new TestClass(); - // TestStruct destStruct = new TestStruct(); - // srcClass.CopyProperties(destStruct); // using the extension directly on a object - - // Reflection.CopyProperties(srcClass, destObject); // Same as above but directly calling the function - - // //so on and so forth.... your imagination is the limits :D - // return srcClass; - //} } } diff --git a/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrderLine.cs b/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrderLine.cs deleted file mode 100644 index 25141ed..0000000 --- a/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrderLine.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace BealeEngineering.Core.Model.Client -{ - public class PurchaseOrderLine - { - public int ClientPurchaseOrderLineID { get; set; } - public int ClientPurchaseOrderID { get; set; } - public int LineNumber { get; set; } - public int ProjectJobID { get; set; } - public string Description { get; set; } - public decimal LineNetAmount { get; set; } - } -} diff --git a/BealeEngineering/BealeEngineering.Core/Model/Contact/Address.cs b/BealeEngineering/BealeEngineering.Core/Model/Contact/Address.cs new file mode 100644 index 0000000..0930590 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Model/Contact/Address.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Model.Contact +{ + public class Address : ValidateModel + { + [Required(AllowEmptyStrings = false), StringLength(100)] + public string AddressLine1 { get; set; } + [StringLength(100)] + public string AddressLine2 { get; set; } + [StringLength(100)] + public string AddressLine3 { get; set; } + [StringLength(100)] + public string AddressLine4 { get; set; } + [Required(AllowEmptyStrings = false), StringLength(100)] + public string City { get; set; } + [StringLength(100)] + public string Region { get; set; } + [Required(AllowEmptyStrings = false), StringLength(50)] + public string PostalCode { get; set; } + [StringLength(100)] + public string Country { get; set; } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Model/Contact/Contact.cs b/BealeEngineering/BealeEngineering.Core/Model/Contact/Contact.cs new file mode 100644 index 0000000..8ffdd40 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Model/Contact/Contact.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Model.Contact +{ + public class Contact : ValidateModel + { + public int ContactId { get; set; } + [Required(AllowEmptyStrings = false), StringLength(100)] + public string ContactName { get; set; } + [StringLength(150), EmailAddress] + public string EmailAddress { get; set; } + public string PrimaryPersonFirstName { get; set; } + public string PrimaryPersonSurname { get; set; } + public string PrimaryPersonEmail { get; set; } + public Address PostalAddress { get; set; } + public bool PostalAddressIsSet + { + get + { + if(PostalAddress == null) { return false; } + else { return true; } + } + } + public override IEnumerable Validate(ValidationContext validationContext) + { + if (ValidationResults == null) { ValidationResults = new List(); } + if (PostalAddressIsSet) + { + //var lkdfj = Validator.TryValidateObject(this.PostalAddress, + //new ValidationContext(this.PostalAddress, null, null) { MemberName = "PostalAddress" }, + //ValidationResults); + + + + + + + //// this doesn't + //Contact contact = validationContext as contact; + //if (contact != null) + //{ + // // ValidationResult(" Error Message ", " MemberNames " ) + // yield return new ValidationResult("No Department and Employees information", new string[] { "DepartmentList & EmployeeList" }); + //} + + + + + //// this works!!!!!!!!!! + var context = new ValidationContext(this.PostalAddress); + var results = new List(); + if (!Validator.TryValidateObject(this.PostalAddress, context, results)) + { + ValidationResults.AddRange(results); + } + + + //if (!PostalAddress.IsValid()) + //{ + + // // for some reason, when an invalid property is found, it is + // // added to the list twice. + // // It works, so no point in trying to fix + // ValidationResults.AddRange(PostalAddress.ValidationResults); + //} + } + + return ValidationResults; + } + } +} \ No newline at end of file diff --git a/BealeEngineering/BealeEngineering.Core/Model/Contact/ContactHeader.cs b/BealeEngineering/BealeEngineering.Core/Model/Contact/ContactHeader.cs deleted file mode 100644 index 3937b5c..0000000 --- a/BealeEngineering/BealeEngineering.Core/Model/Contact/ContactHeader.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace BealeEngineering.Core.Model.Contact -{ - public class ContactHeader - { - public int ContactId { get; set; } - public string ContactName { get; set; } - public string EmailAddress { get; set; } - } -} diff --git a/BealeEngineering/BealeEngineering.Core/Model/Sale/Invoice.cs b/BealeEngineering/BealeEngineering.Core/Model/Sale/Invoice.cs index 022e23d..2f5e10d 100644 --- a/BealeEngineering/BealeEngineering.Core/Model/Sale/Invoice.cs +++ b/BealeEngineering/BealeEngineering.Core/Model/Sale/Invoice.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -8,6 +9,87 @@ namespace BealeEngineering.Core.Model.Sale { public class Invoice : InvoiceHeader { - public List InvoiceLineList { get; set; } + public List InvoiceLineList { get; set; } = new List(); + public bool InvoiceLineListIsSet + { + get + { + if (InvoiceLineList == null || !InvoiceLineList.Any()) { return false; } + else { return true; } + } + } + public class InvoiceLine + { + [Required(), Range(0, 255)] + public int LineNumber { get; set; } + [Required(), StringLength(50)] + public string InventoryItemCode { get; set; } + [StringLength(500)] + public string Description { get; set; } + [Required(), Range(0, 255)] + public decimal Quantity { get; set; } + [Required()] + public decimal UnitAmount { get; set; } + [Range(1, 100)] + public int? Discount { get; set; } + [Required(), StringLength(10)] + public string AccountCode { get; set; } + [Required(), StringLength(50)] + public string TaxType { get; set; } + [Required()] + public decimal TaxAmount { get; set; } + /// + /// Line amount is Tax Exclusive + /// + public decimal LineAmount + { + get + { + int discount; + if (Discount == null || Discount == 0) { discount = 100; } + else { discount = (int)Discount; } + return decimal.Round(((Quantity * UnitAmount) * (discount / 100m)),2, MidpointRounding.AwayFromZero); + } + } + } + public override IEnumerable Validate(ValidationContext validationContext) + { + base.Validate(validationContext); + + // additional validation + if (!InvoiceLineListIsSet) + { + var result = new ValidationResult("Invoice must have at least one line."); + ValidationResults.Add(result); + } + else + { + decimal lineTotal = 0; + decimal lineTaxTotal = 0; + foreach (var line in InvoiceLineList) + { + // checks on each line + if (line.Quantity <= 0) + { + var result = new ValidationResult("Quantity must be greater than zero."); + ValidationResults.Add(result); + } + + lineTotal = lineTotal + line.LineAmount ; + lineTaxTotal = lineTaxTotal + line.TaxAmount; + } + if (lineTotal + lineTaxTotal != InvoiceTotal) + { + var result = new ValidationResult("Line total is not equal to Invoice Total."); + ValidationResults.Add(result); + } + if (lineTaxTotal != TaxTotal) + { + var result = new ValidationResult("Line tax total is not equal to Invoice Tax Total."); + ValidationResults.Add(result); + } + } + return ValidationResults; + } } } diff --git a/BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceHeader.cs b/BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceHeader.cs index 6eaa918..04c1901 100644 --- a/BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceHeader.cs +++ b/BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceHeader.cs @@ -1,22 +1,48 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; namespace BealeEngineering.Core.Model.Sale { - public class InvoiceHeader + public class InvoiceHeader : ValidateModel { public int SaleInvoiceID { get; set; } - public int ContactID { get; set; } + [Required(AllowEmptyStrings = false)] + public string ContactName { get; set; } + [Required(AllowEmptyStrings = false), StringLength(50)] public string SaleInvoiceNumber { get; set; } + [Required()] public DateTime InvoiceDate { get; set; } - public DateTime DueDate { get; set; } + public DateTime? DueDate { get; set; } + [StringLength(50)] public string Reference { get; set; } + [Required(AllowEmptyStrings = false)] + [StringLength(3, MinimumLength = 3)] public string CurrencyCode { get; set; } + [Required()] public decimal InvoiceTotal { get; set;} + [Required()] public decimal TaxTotal { get; set; } + [Required()] public bool IsCreditNote { get; set; } + public override IEnumerable Validate(ValidationContext validationContext) + { + base.Validate(validationContext); + + if (IsCreditNote && InvoiceTotal > 0) + { + var result = new ValidationResult("Credit note total cannot be greater than zero."); + ValidationResults.Add(result); + } + if (!IsCreditNote && InvoiceTotal < 0) + { + var result = new ValidationResult("Invoice total cannot be less than zero."); + ValidationResults.Add(result); + } + return ValidationResults; + } } } diff --git a/BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceLine.cs b/BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceLine.cs deleted file mode 100644 index e9d61fd..0000000 --- a/BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceLine.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace BealeEngineering.Core.Model.Sale -{ - public class InvoiceLine - { - public int SaleInvoiceLineID { get; set; } - public int SaleInvoiceID { get; set; } - public string InventoryItemCode { get; set; } - public string Description { get; set; } - public int Quantity { get; set; } - public decimal UnitAmount { get; set; } - public int Discount { get; set; } - public string AccountCode { get; set; } - public string TaxType { get; set; } - public decimal TaxAmount { get; set; } - public decimal LineAmount { get; set; } - } -} diff --git a/BealeEngineering/BealeEngineering.Core/Model/ValidateModel.cs b/BealeEngineering/BealeEngineering.Core/Model/ValidateModel.cs new file mode 100644 index 0000000..c3a099b --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Model/ValidateModel.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Model +{ + public abstract class ValidateModel : IValidatableObject + { + public List ValidationResults { get; protected set; } + public bool IsValid() + { + ValidationResults = new List(); + var validationContext = new ValidationContext(this); + if (Validator.TryValidateObject(validationContext.ObjectInstance, validationContext, ValidationResults, true)) + { return true; } + else + { return false; } + } + /// + /// Standard checks on class properties. Use 'override' if you wish to add additional checks in a derived classes + /// + /// + /// List + public virtual IEnumerable Validate(ValidationContext validationContext) + { + if (ValidationResults == null) { ValidationResults = new List(); } + return ValidationResults; + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Test/AUtoexec.cs b/BealeEngineering/BealeEngineering.Core/Test/AUtoexec.cs index de61163..9101fd3 100644 --- a/BealeEngineering/BealeEngineering.Core/Test/AUtoexec.cs +++ b/BealeEngineering/BealeEngineering.Core/Test/AUtoexec.cs @@ -11,21 +11,28 @@ namespace BealeEngineering.Core.Test public Autoexec(string sqlConnectionString) { SqlConnectionString = sqlConnectionString; + + // enter method to start here + Import(); } private string SqlConnectionString { get; set; } - - public void Start() + public void Invoice() { // thing you want to run from the form button - //var inst = new Core.Test.Sales.Invoice(SqlConnectionString); - //inst.GetInvoice(); - - //var inst2 = new Test.Client.PurchaseOrder(SqlConnectionString); - //inst2.AllocateInvoicesToPurchaseOrders(); - - var inst3 = new Test.Import.ImportFlatfile(); - inst3.Go(); + var inst = new Core.Test.Sales.Invoice(SqlConnectionString); + } + public void Contact() + { + var inst = new Test.Contact.Contact(SqlConnectionString); + } + public void Import() + { + var inst = new Test.Import.ImportFlatfile(SqlConnectionString); + } + public void ValidateModel() + { + var inst = new Test.Sales.Invoice(SqlConnectionString); } } } diff --git a/BealeEngineering/BealeEngineering.Core/Test/Client/PurchaseOrder.cs b/BealeEngineering/BealeEngineering.Core/Test/Client/PurchaseOrder.cs index 9cc347a..1be401c 100644 --- a/BealeEngineering/BealeEngineering.Core/Test/Client/PurchaseOrder.cs +++ b/BealeEngineering/BealeEngineering.Core/Test/Client/PurchaseOrder.cs @@ -21,7 +21,7 @@ namespace BealeEngineering.Core.Test.Client } public void GetPurchaseOrderById() { - var inst = new Core.Data.Database.Client.PurchaseOrderGet(SqlConnectionString); + var inst = new Core.Data.Database.Client.ReadPurchaseOrder(SqlConnectionString); var newList = inst.GetByClientPurchaseOrderId(PurchaseOrderIdList); } public void AllocateInvoicesToPurchaseOrders() diff --git a/BealeEngineering/BealeEngineering.Core/Test/Contact/Contact.cs b/BealeEngineering/BealeEngineering.Core/Test/Contact/Contact.cs new file mode 100644 index 0000000..24f7aef --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Test/Contact/Contact.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Test.Contact +{ + public class Contact + { + public Contact(string sqlConnectionString) + { + SqlConnectionString = sqlConnectionString; + + ContactIdList = new List + { + 23, 18, 5 + }; + + EmailAddressList = new List + { + "phil.kennerley@gardiners.uk.com", + "patricia.snook@severntrent.co.uk", + "david.lane@severntrent.co.uk" + }; + + // put method to run here + ValidateContact(); + + } + private string SqlConnectionString { get; set; } + public List ContactIdList { get; set; } + public List EmailAddressList { get; set; } + + public void ReadContactHeader() + { + var inst = new Data.Database.Contact.ReadContact(SqlConnectionString); + //var result = inst.ByContactId(ContactIdList); + //var result = inst.ByEmailAddress(EmailAddressList); + } + public void ValidateContact() + { + var inst = new Data.Database.Contact.ReadContact(SqlConnectionString); + var result = inst.ByContactName("Ben Broughton"); + result.PostalAddress.AddressLine1 = " "; + bool isValid = result.IsValid(); + var errorList = result.ValidationResults; + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Test/Import/ImportFlatfile.cs b/BealeEngineering/BealeEngineering.Core/Test/Import/ImportFlatfile.cs index b682b49..dc86503 100644 --- a/BealeEngineering/BealeEngineering.Core/Test/Import/ImportFlatfile.cs +++ b/BealeEngineering/BealeEngineering.Core/Test/Import/ImportFlatfile.cs @@ -8,14 +8,23 @@ namespace BealeEngineering.Core.Test.Import { public class ImportFlatfile { - public void Go() + public ImportFlatfile(string sqlConnectionString) + { + Go(sqlConnectionString); + } + public void Go(string sqlConnectionString) { string fileInputPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + @"\Dropbox\Beale Engineering Services Ltd\BE Accounts\Xero-Export-Invoices.csv"; - var inst = new Data.Xero.FlatFile.ImportInvoice(); - var lkdsjflsd = inst.ByFilePath(fileInputPath); + var inst = new Logic.Import.XeroInvoiceFlatFile(sqlConnectionString); + inst.ByFilePath(fileInputPath); + + return; + + var inst2 = new Data.Xero.FlatFile.ReadXeroInvoiceFlatFile(); + var lkdsjflsd = inst2.ByFilePath(fileInputPath); } } } diff --git a/BealeEngineering/BealeEngineering.Core/Test/Sales/Invoice.cs b/BealeEngineering/BealeEngineering.Core/Test/Sales/Invoice.cs index d4c4b1d..5b9ad0e 100644 --- a/BealeEngineering/BealeEngineering.Core/Test/Sales/Invoice.cs +++ b/BealeEngineering/BealeEngineering.Core/Test/Sales/Invoice.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations; namespace BealeEngineering.Core.Test.Sales { @@ -12,14 +13,34 @@ namespace BealeEngineering.Core.Test.Sales { SqlConnectionString = sqlConnectionString; SaleInvoiceIdList = new List { 131, 481, 105, 324 }; + + + // add method you want to start here + ValidateInvoice(); + + + + } + public Model.Sale.InvoiceHeader InvoiceHeader {get; set;} private string SqlConnectionString { get; set; } public List SaleInvoiceIdList { get; set; } public void GetInvoice() { - var InvInst = new Data.Database.Sale.InvoiceGet(SqlConnectionString); + var InvInst = new Data.Database.Sale.ReadInvoice(SqlConnectionString); var lkdjflsk = InvInst.GetBySaleInvoiceId(SaleInvoiceIdList); } + public void ValidateInvoice() + { + var readContact = new Data.Database.Contact.ReadContact(SqlConnectionString); + var contact = readContact.ByContactId(1); + + var readInvoice = new Data.Database.Sale.ReadInvoice(SqlConnectionString); + var invoices = readInvoice.GetBySaleInvoiceId(new List { 1 }); + invoices[0].CurrencyCode = "EURR"; + bool isValid = invoices[0].IsValid(); + var errorList = invoices[0].ValidationResults; + } } }