From 773ce4cee5eb43aa9fabc1507c7c2cc22139c67b Mon Sep 17 00:00:00 2001 From: Bobbie Hodgetts Date: Thu, 23 Jan 2020 12:09:20 +0000 Subject: [PATCH] Added feature to auto allocate sales invoices to client purchase orders. --- .../BealeEngineering.Accounts/App.config | 9 + .../BealeEngineering.Accounts.csproj | 90 ++++++++ .../Form1.Designer.cs | 61 ++++++ .../BealeEngineering.Accounts/Form1.cs | 30 +++ .../BealeEngineering.Accounts/Form1.resx | 120 +++++++++++ .../BealeEngineering.Accounts/Program.cs | 22 ++ .../Properties/AssemblyInfo.cs | 36 ++++ .../Properties/Resources.Designer.cs | 71 +++++++ .../Properties/Resources.resx | 117 +++++++++++ .../Properties/Settings.Designer.cs | 30 +++ .../Properties/Settings.settings | 7 + .../BealeEngineering.Core.csproj | 80 ++++++++ .../Client/PurchaseOrderAllocationCreate.cs | 57 ++++++ .../Client/PurchaseOrderAllocationGet.cs | 71 +++++++ .../Data/Database/Client/PurchaseOrderGet.cs | 102 +++++++++ .../Database/Client/PurchaseOrderHeaderGet.cs | 149 ++++++++++++++ .../Data/Database/Connection.cs | 20 ++ .../Data/Database/Contact/ContactHeaderGet.cs | 160 +++++++++++++++ .../Data/Database/Sale/InvoiceGet.cs | 111 ++++++++++ .../Data/Database/Sale/InvoiceHeaderGet.cs | 160 +++++++++++++++ .../Logic/Client/PurchaseOrderAutoAllocate.cs | 182 +++++++++++++++++ .../Logic/Utilities/Reflection.cs | 91 +++++++++ .../Logic/Utilities/StringCheck.cs | 193 ++++++++++++++++++ .../Model/Client/PurchaseOrder.cs | 20 ++ .../Model/Client/PurchaseOrderHeader.cs | 38 ++++ .../Model/Client/PurchaseOrderLine.cs | 16 ++ .../Model/Contact/ContactHeader.cs | 15 ++ .../Model/Sale/Invoice.cs | 13 ++ .../Model/Sale/InvoiceHeader.cs | 22 ++ .../Model/Sale/InvoiceLine.cs | 23 +++ .../Properties/AssemblyInfo.cs | 36 ++++ .../BealeEngineering.Core/Test/AUtoexec.cs | 31 +++ .../Test/Client/PurchaseOrder.cs | 33 +++ .../Test/Sales/Invoice.cs | 25 +++ .../BealeEngineering.Core/packages.config | 4 + BealeEngineering/BealeEngineering.sln | 33 +++ 36 files changed, 2278 insertions(+) create mode 100644 BealeEngineering/BealeEngineering.Accounts/App.config create mode 100644 BealeEngineering/BealeEngineering.Accounts/BealeEngineering.Accounts.csproj create mode 100644 BealeEngineering/BealeEngineering.Accounts/Form1.Designer.cs create mode 100644 BealeEngineering/BealeEngineering.Accounts/Form1.cs create mode 100644 BealeEngineering/BealeEngineering.Accounts/Form1.resx create mode 100644 BealeEngineering/BealeEngineering.Accounts/Program.cs create mode 100644 BealeEngineering/BealeEngineering.Accounts/Properties/AssemblyInfo.cs create mode 100644 BealeEngineering/BealeEngineering.Accounts/Properties/Resources.Designer.cs create mode 100644 BealeEngineering/BealeEngineering.Accounts/Properties/Resources.resx create mode 100644 BealeEngineering/BealeEngineering.Accounts/Properties/Settings.Designer.cs create mode 100644 BealeEngineering/BealeEngineering.Accounts/Properties/Settings.settings create mode 100644 BealeEngineering/BealeEngineering.Core/BealeEngineering.Core.csproj create mode 100644 BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderAllocationCreate.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderAllocationGet.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderGet.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderHeaderGet.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Data/Database/Connection.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Data/Database/Contact/ContactHeaderGet.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Data/Database/Sale/InvoiceGet.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Data/Database/Sale/InvoiceHeaderGet.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Logic/Client/PurchaseOrderAutoAllocate.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Logic/Utilities/Reflection.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Logic/Utilities/StringCheck.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrder.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrderHeader.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrderLine.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Model/Contact/ContactHeader.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Model/Sale/Invoice.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceHeader.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceLine.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Properties/AssemblyInfo.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Test/AUtoexec.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Test/Client/PurchaseOrder.cs create mode 100644 BealeEngineering/BealeEngineering.Core/Test/Sales/Invoice.cs create mode 100644 BealeEngineering/BealeEngineering.Core/packages.config create mode 100644 BealeEngineering/BealeEngineering.sln diff --git a/BealeEngineering/BealeEngineering.Accounts/App.config b/BealeEngineering/BealeEngineering.Accounts/App.config new file mode 100644 index 0000000..a0f10b3 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Accounts/App.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/BealeEngineering/BealeEngineering.Accounts/BealeEngineering.Accounts.csproj b/BealeEngineering/BealeEngineering.Accounts/BealeEngineering.Accounts.csproj new file mode 100644 index 0000000..33499df --- /dev/null +++ b/BealeEngineering/BealeEngineering.Accounts/BealeEngineering.Accounts.csproj @@ -0,0 +1,90 @@ + + + + + Debug + AnyCPU + {F025483F-53D1-47FC-9691-EB771FD845EF} + WinExe + BealeEngineering.Accounts + BealeEngineering.Accounts + v4.7.2 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + Form + + + Form1.cs + + + + + Form1.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + {fd88a52a-fde5-4d0a-abdf-ee87d19f21bd} + BealeEngineering.Core + + + + \ No newline at end of file diff --git a/BealeEngineering/BealeEngineering.Accounts/Form1.Designer.cs b/BealeEngineering/BealeEngineering.Accounts/Form1.Designer.cs new file mode 100644 index 0000000..d98a3a8 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Accounts/Form1.Designer.cs @@ -0,0 +1,61 @@ +namespace BealeEngineering.Accounts +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnTest = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // btnTest + // + this.btnTest.Location = new System.Drawing.Point(61, 39); + this.btnTest.Name = "btnTest"; + this.btnTest.Size = new System.Drawing.Size(139, 42); + this.btnTest.TabIndex = 0; + this.btnTest.Text = "Test it!"; + this.btnTest.UseVisualStyleBackColor = true; + this.btnTest.Click += new System.EventHandler(this.button1_Click); + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.btnTest); + this.Name = "Form1"; + this.Text = "Form1"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button btnTest; + } +} + diff --git a/BealeEngineering/BealeEngineering.Accounts/Form1.cs b/BealeEngineering/BealeEngineering.Accounts/Form1.cs new file mode 100644 index 0000000..8a0c46a --- /dev/null +++ b/BealeEngineering/BealeEngineering.Accounts/Form1.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Configuration; +using BealeEngineering.Core; + +namespace BealeEngineering.Accounts +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + } + + private void button1_Click(object sender, EventArgs e) + { + string conString = ConfigurationManager.ConnectionStrings["BealeEngSQLDb"].ToString(); + + var inst = new Core.Test.Autoexec(conString); + inst.Start(); + } + } +} diff --git a/BealeEngineering/BealeEngineering.Accounts/Form1.resx b/BealeEngineering/BealeEngineering.Accounts/Form1.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Accounts/Form1.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/BealeEngineering/BealeEngineering.Accounts/Program.cs b/BealeEngineering/BealeEngineering.Accounts/Program.cs new file mode 100644 index 0000000..f56d26e --- /dev/null +++ b/BealeEngineering/BealeEngineering.Accounts/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace BealeEngineering.Accounts +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} diff --git a/BealeEngineering/BealeEngineering.Accounts/Properties/AssemblyInfo.cs b/BealeEngineering/BealeEngineering.Accounts/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..44daf93 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Accounts/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BealeEngineering.Accounts")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BealeEngineering.Accounts")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f025483f-53d1-47fc-9691-eb771fd845ef")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/BealeEngineering/BealeEngineering.Accounts/Properties/Resources.Designer.cs b/BealeEngineering/BealeEngineering.Accounts/Properties/Resources.Designer.cs new file mode 100644 index 0000000..ae83c8d --- /dev/null +++ b/BealeEngineering/BealeEngineering.Accounts/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace BealeEngineering.Accounts.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BealeEngineering.Accounts.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/BealeEngineering/BealeEngineering.Accounts/Properties/Resources.resx b/BealeEngineering/BealeEngineering.Accounts/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/BealeEngineering/BealeEngineering.Accounts/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/BealeEngineering/BealeEngineering.Accounts/Properties/Settings.Designer.cs b/BealeEngineering/BealeEngineering.Accounts/Properties/Settings.Designer.cs new file mode 100644 index 0000000..032928b --- /dev/null +++ b/BealeEngineering/BealeEngineering.Accounts/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace BealeEngineering.Accounts.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/BealeEngineering/BealeEngineering.Accounts/Properties/Settings.settings b/BealeEngineering/BealeEngineering.Accounts/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Accounts/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/BealeEngineering/BealeEngineering.Core/BealeEngineering.Core.csproj b/BealeEngineering/BealeEngineering.Core/BealeEngineering.Core.csproj new file mode 100644 index 0000000..b42d248 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/BealeEngineering.Core.csproj @@ -0,0 +1,80 @@ + + + + + Debug + AnyCPU + {FD88A52A-FDE5-4D0A-ABDF-EE87D19F21BD} + Library + Properties + BealeEngineering.Core + BealeEngineering.Core + v4.7.2 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Dapper.2.0.30\lib\net461\Dapper.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderAllocationCreate.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderAllocationCreate.cs new file mode 100644 index 0000000..dfb6200 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderAllocationCreate.cs @@ -0,0 +1,57 @@ +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.Client +{ + public class PurchaseOrderAllocationCreate : Connection + { + public PurchaseOrderAllocationCreate(string sqlConnectionString) : base(sqlConnectionString) + { + + } + public int ByDictionary(Dictionary saleInvoiceIdToPoLineId) + { + int rowsCreated = 0; + + if (saleInvoiceIdToPoLineId == null || !saleInvoiceIdToPoLineId.Any()) + { + throw new Exception("No data passed to function."); + } + + using (TransactionScope scope = new TransactionScope()) + { + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + foreach (var item in saleInvoiceIdToPoLineId) + { + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO ClientPurchaseOrderLineSalesInvoice ( + ClientPurchaseOrderLineID + ,SaleInvoiceID + ) + VALUES ( + @clientPurchaseOrderLineID + ,@saleInvoiceID + ) + ", conn)) + { + cmd.Parameters.AddWithValue("@clientPurchaseOrderLineID", item.Value); + cmd.Parameters.AddWithValue("@saleInvoiceID", item.Key); + + rowsCreated = rowsCreated + cmd.ExecuteNonQuery(); + } + } + } + scope.Complete(); + } + return rowsCreated; + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderAllocationGet.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderAllocationGet.cs new file mode 100644 index 0000000..4d10a63 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderAllocationGet.cs @@ -0,0 +1,71 @@ +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.Client +{ + public class PurchaseOrderAllocationGet : Connection + { + public PurchaseOrderAllocationGet(string sqlConnectionString) : base(sqlConnectionString) + { + + } + public int GetUnallocatedInvoiceCount() + { + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + SELECT Count(SaleInvoice.SaleInvoiceID) AS CountOfSaleInvoiceID + FROM SaleInvoice + LEFT OUTER JOIN ClientPurchaseOrderLineSalesInvoice ON SaleInvoice.SaleInvoiceID = ClientPurchaseOrderLineSalesInvoice.SaleInvoiceID + WHERE (ClientPurchaseOrderLineSalesInvoice.SaleInvoiceID IS NULL) + AND (SaleInvoice.Reference IS NOT NULL) + ", conn)) + { + object obj = cmd.ExecuteScalar(); + + return (int)obj; + } + } + } + public List GetUnallocatedInvoiceId() + { + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + SELECT SaleInvoice.SaleInvoiceID + FROM SaleInvoice + LEFT OUTER JOIN ClientPurchaseOrderLineSalesInvoice ON SaleInvoice.SaleInvoiceID = ClientPurchaseOrderLineSalesInvoice.SaleInvoiceID + WHERE (ClientPurchaseOrderLineSalesInvoice.SaleInvoiceID IS NULL) + AND (SaleInvoice.Reference IS NOT NULL) + ", conn)) + { + using (SqlDataReader reader = cmd.ExecuteReader()) + { + if (!reader.HasRows) + { + // do nothing + return null; + } + else + { + var returnList = new List(); + while (reader.Read()) + { + returnList.Add(reader.GetInt32(0)); + } + return returnList; + } + } + } + } + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderGet.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderGet.cs new file mode 100644 index 0000000..eab592c --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderGet.cs @@ -0,0 +1,102 @@ +using Dapper; +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Data.Database.Client +{ + public class PurchaseOrderGet : PurchaseOrderHeaderGet + { + public PurchaseOrderGet(string sqlConnectionString) : base(sqlConnectionString) + { + + } + public List PurchaseOrderHeader { get; set; } + public bool PurchaseOrderHeaderIsSet + { + get + { + if (PurchaseOrderHeader == null || !PurchaseOrderHeader.Any()) { return false; } + else { return true; } + } + } + public new List GetByClientPurchaseOrderId(List orderIdList) + { + ClientPurchaseOrderIdList = orderIdList; + try + { + return GetByFilters(); + } + catch (Exception ex) + { + throw ex; + } + finally + { + ClientPurchaseOrderIdList = null; + } + } + public new List GetByFilters() + { + // build the sql string and dapper parameters + var parameters = new DynamicParameters(); + string sqlString = @" + SELECT ClientPurchaseOrder.ClientPurchaseOrderID + ,ClientPurchaseOrder.PurchaseOrderDate + ,ClientPurchaseOrder.ContactID + ,ClientPurchaseOrder.ClientReference + ,ClientPurchaseOrder.RequestorEmail + ,ClientPurchaseOrder.OrderTotal + ,ClientPurchaseOrder.IsClosed + ,ClientPurchaseOrderLine.ClientPurchaseOrderLineID + ,ClientPurchaseOrderLine.LineNumber + ,ClientPurchaseOrderLine.ProjectJobID + ,ClientPurchaseOrderLine.Description + ,ClientPurchaseOrderLine.LineNetAmount + FROM ClientPurchaseOrder + LEFT OUTER JOIN ClientPurchaseOrderLine ON ClientPurchaseOrder.ClientPurchaseOrderID = ClientPurchaseOrderLine.ClientPurchaseOrderID"; + + AddSqlWhereString(ref sqlString, ref parameters); + + sqlString = sqlString + @" + ORDER BY ClientPurchaseOrder.ClientPurchaseOrderID + ,ClientPurchaseOrderLine.LineNumber"; + + // make the call + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + var orderDictionary = new Dictionary(); + + var orderList = conn.Query + ( + sqlString, + (order, orderDetail) => + { + Model.Client.PurchaseOrder orderEntry; + + if (!orderDictionary.TryGetValue(order.ClientPurchaseOrderID, out orderEntry)) + { + orderEntry = order; + orderEntry.OrderLineList = new List(); + orderDictionary.Add(orderEntry.ClientPurchaseOrderID, orderEntry); + } + + orderEntry.OrderLineList.Add(orderDetail); + return orderEntry; + }, + parameters, + splitOn: "ClientPurchaseOrderLineID") + .Distinct() + .ToList(); + + return orderList; + } + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderHeaderGet.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderHeaderGet.cs new file mode 100644 index 0000000..4b80262 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Client/PurchaseOrderHeaderGet.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Data; +using System.Data.SqlClient; +using System.Text; +using Dapper; + +namespace BealeEngineering.Core.Data.Database.Client +{ + public class PurchaseOrderHeaderGet : Connection + { + public PurchaseOrderHeaderGet(string sqlConnectionString) : base(sqlConnectionString) + { + + } + /// + /// Setting this will override he other filters, within the sql statement. + /// + protected List ClientPurchaseOrderIdList { get; set; } + private bool ClientPurchaseOrderIdListIsSet + { + get + { + if (ClientPurchaseOrderIdList == null || !ClientPurchaseOrderIdList.Any()) { return false; } + else { return true; } + } + } + public DateTime DateFrom { get; set; } + public bool DateFromIsSet + { + get + { + if (DateFrom == null || DateFrom == default(DateTime)) { return false; } + else { return true; } + } + } + public DateTime DateTo { get; set; } + public bool DateToIsSet + { + get + { + if (DateTo == null || DateTo == default(DateTime)) { return false; } + else { return true; } + } + } + public List Reference { get; set; } + public bool ReferenceIsSet + { + get + { + if (Reference == null || !Reference.Any()) { return false; } + else { return true; } + } + } + public bool ReturnIsClosed { get; set; } = true; + public List GetByClientPurchaseOrderId(List orderIdList) + { + ClientPurchaseOrderIdList = orderIdList; + try + { + return GetByFilters(); + } + catch (Exception ex) + { + throw ex; + } + finally + { + ClientPurchaseOrderIdList = null; + } + } + protected void AddSqlWhereString(ref string sqlString, ref DynamicParameters parameters) + { + if (string.IsNullOrWhiteSpace(sqlString)) + { throw new Exception("SQL string is empty."); } + + sqlString = sqlString + @" + WHERE 1=1"; + + if (ClientPurchaseOrderIdListIsSet) + { + sqlString = sqlString + @" + AND ClientPurchaseOrder.ClientPurchaseOrderID IN @purchaseOrderId"; + + parameters.Add("@purchaseOrderId", ClientPurchaseOrderIdList); + } + else + { + if (DateFromIsSet) + { + sqlString = sqlString + @" + AND PurchaseOrderDate >= @dateFrom"; + + parameters.Add("@dateFrom", DateFrom); + } + if (DateToIsSet) + { + sqlString = sqlString + @" + AND PurchaseOrderDate <= @dateTo"; + + parameters.Add("@dateTo", DateTo); + } + if (ReferenceIsSet) + { + sqlString = sqlString + @" + AND ClientReference IN @reference"; + + parameters.Add("@reference", Reference); + } + if (ReturnIsClosed == false) + { + sqlString = sqlString + @" + AND IsClosed = @isClosed"; + + parameters.Add("@isClosed", false); + } + } + } + public List GetByFilters() + { + // build the sql string and dapper parameters + var parameters = new DynamicParameters(); + string sqlString = @" + SELECT ClientPurchaseOrderID + ,PurchaseOrderDate + ,ContactID + ,ClientReference + ,RequestorEmail + ,OrderTotal + ,IsClosed + FROM ClientPurchaseOrder"; + + AddSqlWhereString(ref sqlString, ref parameters); + + sqlString = sqlString + @" + ORDER BY ClientPurchaseOrderID"; + + // make the call + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + var purchaseOrders = conn.Query(sqlString, parameters).ToList(); + return purchaseOrders; + } + } + } +} \ No newline at end of file diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Connection.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Connection.cs new file mode 100644 index 0000000..aeeaf0f --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Connection.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Data.Database +{ + public class Connection + { + protected readonly string sqlConnectionString; + public Connection(string sqlConnectionString) + { + // setup sql parameters + if (sqlConnectionString.Length == 0) + { throw new Exception("Zero length sql connectionstring passed"); } + this.sqlConnectionString = sqlConnectionString; + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/ContactHeaderGet.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/ContactHeaderGet.cs new file mode 100644 index 0000000..4bc183c --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Contact/ContactHeaderGet.cs @@ -0,0 +1,160 @@ +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/Sale/InvoiceGet.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/InvoiceGet.cs new file mode 100644 index 0000000..2ff0e1e --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/InvoiceGet.cs @@ -0,0 +1,111 @@ +using Dapper; +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.Sale +{ + public class InvoiceGet : InvoiceHeaderGet + { + public InvoiceGet(string sqlConnectionString) : base(sqlConnectionString) + { + + } + public List SaleInvoiceHeader { get; set; } + public bool SaleInvoiceHeaderIsSet + { + get + { + if (SaleInvoiceHeader == null || !SaleInvoiceHeader.Any()) { return false; } + else { return true; } + } + } + public new List GetBySaleInvoiceId(List invoiceIdList) + { + SalesInvoiceIdList = invoiceIdList; + try + { + return GetByFilters(); + } + catch (Exception ex) + { + throw ex; + } + finally + { + SalesInvoiceIdList = null; + } + } + public new List GetByFilters() + { + // build the sql string and dapper parameters + var parameters = new DynamicParameters(); + string sqlString = @" + SELECT SaleInvoice.SaleInvoiceID + ,SaleInvoice.ContactID + ,SaleInvoice.SaleInvoiceNumber + ,SaleInvoice.InvoiceDate + ,SaleInvoice.DateDue + ,SaleInvoice.Reference + ,SaleInvoice.CurrencyCode + ,SaleInvoice.InvoiceTotal + ,SaleInvoice.TaxTotal + ,SaleInvoiceLine.SaleInvoiceLineID + ,SaleInvoiceLine.SaleInvoiceID + ,SaleInvoiceLine.LineNumber + ,SaleInvoiceLine.InventoryItemCode + ,SaleInvoiceLine.Description + ,SaleInvoiceLine.Quantity + ,SaleInvoiceLine.UnitAmount + ,SaleInvoiceLine.Discount + ,SaleInvoiceLine.AccountCode + ,SaleInvoiceLine.TaxType + ,SaleInvoiceLine.TaxAmount + ,SaleInvoiceLine.LineAmount + FROM SaleInvoice + LEFT OUTER JOIN SaleInvoiceLine ON SaleInvoice.SaleInvoiceID = SaleInvoiceLine.SaleInvoiceID"; + + AddSqlWhereString(ref sqlString, ref parameters); + + sqlString = sqlString + @" + ORDER BY SaleInvoice.SaleInvoiceID + ,SaleInvoiceLine.LineNumber + ,SaleInvoiceLine.SaleInvoiceLineID"; + + // make the call + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + var invoiceDictionary = new Dictionary(); + + var invoiceList = conn.Query + ( + sqlString, + (invoice, invoiceDetail) => + { + Model.Sale.Invoice invoiceEntry; + + if (!invoiceDictionary.TryGetValue(invoice.SaleInvoiceID, out invoiceEntry)) + { + invoiceEntry = invoice; + invoiceEntry.InvoiceLineList = new List(); + invoiceDictionary.Add(invoiceEntry.SaleInvoiceID, invoiceEntry); + } + + invoiceEntry.InvoiceLineList.Add(invoiceDetail); + return invoiceEntry; + }, + parameters, + splitOn: "SaleInvoiceLineID") + .Distinct() + .ToList(); + + return invoiceList; + } + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/InvoiceHeaderGet.cs b/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/InvoiceHeaderGet.cs new file mode 100644 index 0000000..c710717 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Data/Database/Sale/InvoiceHeaderGet.cs @@ -0,0 +1,160 @@ +using Dapper; +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.Sale +{ + public class InvoiceHeaderGet : Connection + { + public InvoiceHeaderGet(string sqlConnectionString) : base(sqlConnectionString) + { + + } + /// + /// Setting this will override he other filters, within the sql statement. + /// + protected List SalesInvoiceIdList { get; set; } + private bool SalesInvoiceIdListListIsSet + { + get + { + if (SalesInvoiceIdList == null || !SalesInvoiceIdList.Any()) { return false; } + else { return true; } + } + } + public DateTime DateFrom { get; set; } + public bool DateFromIsSet + { + get + { + if (DateFrom == null || DateFrom == default(DateTime)) { return false; } + else { return true; } + } + } + public DateTime DateTo { get; set; } + public bool DateToIsSet + { + get + { + if (DateTo == null || DateTo == default(DateTime)) { return false; } + else { return true; } + } + } + public List InvoiceNumber { get; set; } + public bool InvoiceNumberIsSet + { + get + { + if (InvoiceNumber == null || !InvoiceNumber.Any()) { return false; } + else { return true; } + } + } + public List Reference { get; set; } + public bool ReferenceIsSet + { + get + { + if (Reference == null || !Reference.Any()) { return false; } + else { return true; } + } + } + public List GetBySaleInvoiceId(List orderIdList) + { + SalesInvoiceIdList = orderIdList; + try + { + return GetByFilters(); + } + catch (Exception ex) + { + throw ex; + } + finally + { + SalesInvoiceIdList = null; + } + } + protected void AddSqlWhereString(ref string sqlString, ref DynamicParameters parameters) + { + if (string.IsNullOrWhiteSpace(sqlString)) + { throw new Exception("SQL string is empty."); } + + sqlString = sqlString + @" + WHERE 1=1"; + + if (SalesInvoiceIdListListIsSet) + { + sqlString = sqlString + @" + AND SaleInvoice.SaleInvoiceID IN @saleInvoiceId"; + + parameters.Add("@saleInvoiceId", SalesInvoiceIdList); + } + else + { + if (DateFromIsSet) + { + sqlString = sqlString + @" + AND InvoiceDate >= @dateFrom"; + + parameters.Add("@dateFrom", DateFrom); + } + if (DateToIsSet) + { + sqlString = sqlString + @" + AND InvoiceDate <= @dateTo"; + + parameters.Add("@dateTo", DateTo); + } + if (InvoiceNumberIsSet) + { + sqlString = sqlString + @" + AND SaleInvoiceNumber IN @salesInvoiceNumber"; + + parameters.Add("@salesInvoiceNumber", InvoiceNumber); + } + if (ReferenceIsSet) + { + sqlString = sqlString + @" + AND Reference IN @reference"; + + parameters.Add("@reference", Reference); + } + } + } + public List GetByFilters() + { + // 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"; + + AddSqlWhereString(ref sqlString, ref parameters); + + sqlString = sqlString + @" + ORDER BY SaleInvoiceID"; + + // make the call + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + var invoiceHeaders = conn.Query(sqlString, parameters).ToList(); + return invoiceHeaders; + } + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Logic/Client/PurchaseOrderAutoAllocate.cs b/BealeEngineering/BealeEngineering.Core/Logic/Client/PurchaseOrderAutoAllocate.cs new file mode 100644 index 0000000..9e8baf7 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Logic/Client/PurchaseOrderAutoAllocate.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Logic.Client +{ + public class PurchaseOrderAutoAllocate + { + public PurchaseOrderAutoAllocate(string sqlConnectionString) + { + SqlConnectionString = sqlConnectionString; + Init(); + } + public bool IsComplete { get; private set; } + public int InvoiceMatched { get; private set; } + public int InvoiceProcessed { get; private set; } + public int InvoiceUnmatched + { + get { return InvoiceProcessed - InvoiceMatched; } + } + private string SqlConnectionString { get; set; } + public void Execute() + { + Init(); + + // get list of unallocated invoices + var poAlloInstance = new Data.Database.Client.PurchaseOrderAllocationGet(SqlConnectionString); + var invoiceIdList = poAlloInstance.GetUnallocatedInvoiceId(); + + // nothing to allocate + if (invoiceIdList == null || !invoiceIdList.Any()) + { + IsComplete = true; + return; + } + else + { + InvoiceProcessed = invoiceIdList.Count(); + } + + // get invoice header info + var invoiceInst = new Data.Database.Sale.InvoiceHeaderGet(SqlConnectionString); + var invoiceList = invoiceInst.GetBySaleInvoiceId(invoiceIdList); + + // create lookup list for matching + var lookupList = new List>(); + + for (int i = 0; i < invoiceList.Count; i++) + { + lookupList.Add(new Tuple + (invoiceList[i], invoiceList[i].Reference, null)); + + // check if a line number can be potentially parsed off reference + // if it can, add a second lookup entry (leave the first as it might be right) + string parsedReference = string.Copy(invoiceList[i].Reference); + int? parsedLineNumber = null; + ParseOutLineNumbes(ref parsedReference, ref parsedLineNumber); + if (parsedLineNumber != null) + { + lookupList.Add(new Tuple + (invoiceList[i], parsedReference, parsedLineNumber)); + } + } + + // for PO with multiple lines, sort lookup list with potential parsed line numbers first + // try to match on ref and line# first, then try ref and line total + lookupList = lookupList.OrderByDescending(t => t.Item3).ToList(); + + //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); + poInstance.Reference = referenceList.Distinct().ToList(); + poInstance.ReturnIsClosed = true; // <--------------------------------------------------change to false after + var clientPoList = poInstance.GetByFilters(); + + // create dictionary for matched items + var invoiceIdToPoLineId = new Dictionary(); + + // loop through list and do the matching + for (int i = 0; i < lookupList.Count; i++) + { + // skip any invoice ids already done + int invoiceId = lookupList[i].Item1.SaleInvoiceID; + if (!invoiceIdToPoLineId.ContainsKey(invoiceId)) + { + // match contact ID + foreach (var po in clientPoList) + { + if (po.ContactID == lookupList[i].Item1.ContactID) + { + // match PO reference + string reference = lookupList[i].Item2; + if (po.ClientReference == reference) + { + // match PO line(s) + int? parsedLineNumber = lookupList[i].Item3; + // only one line in PO, jus match invoice to it + if (po.OrderLineCount == 1) + { + invoiceIdToPoLineId.Add(invoiceId, po.OrderLineList.First().ClientPurchaseOrderLineID); + } + // for multiple line, try to match invoice to line number + else if (po.OrderLineCount > 1 && parsedLineNumber != null) + { + foreach (var line in po.OrderLineList) + { + if (line.LineNumber == parsedLineNumber) + { + invoiceIdToPoLineId.Add(invoiceId, line.ClientPurchaseOrderLineID); + } + } + } + // for multiple line, try to match invoice to line total + else if(po.OrderLineCount > 1 && parsedLineNumber == null) + { + int matchCount = 0; + int poLineId = 0; + decimal invoiceNetTotal = lookupList[i].Item1.InvoiceTotal - lookupList[i].Item1.TaxTotal; + foreach (var line in po.OrderLineList) + { + if (line.LineNetAmount == invoiceNetTotal) + { + matchCount = matchCount + 1; + poLineId = line.ClientPurchaseOrderLineID; + } + } + // only do match if one line is the same + if (matchCount == 1) + { + invoiceIdToPoLineId.Add(invoiceId, poLineId); + } + } + } + } + } + } + } + + // update db table + if (invoiceIdToPoLineId.Count > 0) + { + var instance2 = new Data.Database.Client.PurchaseOrderAllocationCreate(SqlConnectionString); + InvoiceMatched = instance2.ByDictionary(invoiceIdToPoLineId); + } + IsComplete = true; + } + public void Init() + { + IsComplete = false; + InvoiceMatched = 0; + InvoiceProcessed = 0; + } + /// + /// Parses out any possible line numbers from end of PO reference and adds to them the end of the reference list. + /// + /// + /// + private void ParseOutLineNumbes(ref string reference, ref int? lineNumber) + { + int dashIndex = reference.LastIndexOf('-'); + if (dashIndex > 0) + { + var newReference = reference.Substring(0, dashIndex); + if (newReference != reference) + { + string lineNoString = reference.Substring(dashIndex + 1); + int lineNoInt = 0; + if (Int32.TryParse(lineNoString, out lineNoInt)) + { + // it can, and the end string can be converted into an int, so we add it. + reference = newReference; + lineNumber = lineNoInt; + } + } + } + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Logic/Utilities/Reflection.cs b/BealeEngineering/BealeEngineering.Core/Logic/Utilities/Reflection.cs new file mode 100644 index 0000000..ea23b50 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Logic/Utilities/Reflection.cs @@ -0,0 +1,91 @@ +using System; +using System.Reflection; + +namespace BealeEngineering.Core.Logic.Utilities +{ + public static class Reflection + { + /// + /// Extension for 'Object' that copies the properties to a destination object. + /// + /// The source. + /// The destination. + public static void CopyProperties(this object source, object destination) + { + // If any this null throw an exception + if (source == null || destination == null) + throw new Exception("Source or/and Destination Objects are null"); + // Getting the Types of the objects + Type typeDest = destination.GetType(); + Type typeSrc = source.GetType(); + + // Iterate the Properties of the source instance and + // populate them from their desination counterparts + PropertyInfo[] srcProps = typeSrc.GetProperties(); + foreach (PropertyInfo srcProp in srcProps) + { + if (!srcProp.CanRead) + { + continue; + } + PropertyInfo targetProperty = typeDest.GetProperty(srcProp.Name); + if (targetProperty == null) + { + continue; + } + if (!targetProperty.CanWrite) + { + continue; + } + if (targetProperty.GetSetMethod(true) != null && targetProperty.GetSetMethod(true).IsPrivate) + { + continue; + } + if ((targetProperty.GetSetMethod().Attributes & MethodAttributes.Static) != 0) + { + continue; + } + if (!targetProperty.PropertyType.IsAssignableFrom(srcProp.PropertyType)) + { + continue; + } + // Passed all tests, lets set the value + targetProperty.SetValue(destination, srcProp.GetValue(source, null), null); + } + } + } +} + +/* https://stackoverflow.com/questions/930433 + * USAGE: + * +/// +/// ExampleCopyObject +/// +/// +public object ExampleCopyObject() +{ + object destObject = new object(); + this.CopyProperties(destObject); // inside a class you want to copy from + + 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; +} + +public class TestClass +{ + public string Blah { get; set; } +} +public struct TestStruct +{ + public string Blah { get; set; } +} +*/ diff --git a/BealeEngineering/BealeEngineering.Core/Logic/Utilities/StringCheck.cs b/BealeEngineering/BealeEngineering.Core/Logic/Utilities/StringCheck.cs new file mode 100644 index 0000000..3ad4403 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Logic/Utilities/StringCheck.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Logic.Utilities +{ + class StringCheck + { + public bool AllowEmpty { get; set; } = false; + public bool AllowWhiteSpace { get; set; } = false; + public string ErrorMessage { get; private set; } + public void ResetToDefault() + { + ErrorMessage = null; + AllowEmpty = false; + AllowWhiteSpace = false; + } + public bool IsAlpha(string stringToCheck, bool upperCaseOnly = false, bool allowNull = false) + { + ErrorMessage = null; + if (stringToCheck == null) + { + if (!allowNull) + { + ErrorMessage = "String is null"; + return false; + } + } + else + { + foreach (char c in stringToCheck) + { + if (!((c >= 'A' && c <= 'Z') + || ((c >= 'a' && c <= 'z') && !upperCaseOnly))) + { + if ((c >= 'a' && c <= 'z') && upperCaseOnly) + { + ErrorMessage = "String contains lower case numerical charater(s)."; + return false; + } + else + { + ErrorMessage = "String contains non-alpha charater(s)."; + return false; + } + } + } + } + return true; + } + public bool IsAlphaNumeric(string stringToCheck, bool upperCaseOnly = false, bool allowNull = false) + { + ErrorMessage = null; + if (stringToCheck == null) + { + if (!allowNull) + { + ErrorMessage = "String is null"; + return false; + } + } + else + { + foreach (char c in stringToCheck) + { + if (!((c >= '0' && c <= '9') + || (c >= 'A' && c <= 'Z') + || ((c >= 'a' && c <= 'z') && !upperCaseOnly))) + { + if ((c >= 'a' && c <= 'z') && upperCaseOnly) + { + ErrorMessage = "String contains lower case numerical charater(s)."; + return false; + } + else + { + ErrorMessage = "String contains non-alphanumeric charater(s)."; + return false; + } + } + } + } + return true; + } + public bool IsNumeric(string stringToCheck, bool allowNull = false) + { + ErrorMessage = null; + if (stringToCheck == null) + { + if (allowNull == false) + { + ErrorMessage = "String is null"; + return false; + } + } + else + { + foreach (char c in stringToCheck) + { + if (c < '0' || c > '9') + { + ErrorMessage = "String contains non-numeric charater(s)."; + return false; + } + } + } + return true; + } + public bool Length(string stringToCheck, int stringLength, bool allowNull = false) + { + ErrorMessage = null; + if (!NullOrWhiteSpaceCheck(stringToCheck, allowNull)) + { + return false; + } + + int length = stringToCheck.Length; + if (length != stringLength) + { + ErrorMessage = "String length (" + length + ") does not equal " + stringLength + " charaters."; + return false; + } + return true; + } + public bool MaxLength(string stringToCheck, int maxLength, bool allowNull = false) + { + ErrorMessage = null; + if (!NullOrWhiteSpaceCheck(stringToCheck, allowNull)) + { + return false; + } + + int length = stringToCheck.Length; + if (length > maxLength) + { + ErrorMessage = "String length (" + length + ") is greater than " + maxLength + " charaters."; + return false; + } + return true; + } + public bool MinLength(string stringToCheck, int minLength, bool allowNull = false) + { + ErrorMessage = null; + if (!NullOrWhiteSpaceCheck(stringToCheck, allowNull)) + { + return false; + } + + int length = stringToCheck.Length; + if (length <= minLength) + { + ErrorMessage = "String length (" + length + ") is less than " + minLength + " charaters."; + return false; + } + return true; + } + + private bool NullOrWhiteSpaceCheck(string stringToCheck, bool allowNull = false) + { + ErrorMessage = null; + if (string.IsNullOrWhiteSpace(stringToCheck)) + { + if (stringToCheck == null) + { + if (!allowNull) + { + ErrorMessage = "String is null, empty or white space."; + return false; + } + } + else if (stringToCheck == "") + { + if (!AllowEmpty) + { + ErrorMessage = "String is empty."; + return false; + } + } + else + { + if (!AllowWhiteSpace) + { + ErrorMessage = "String is white space."; + return false; + } + } + } + return true; + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrder.cs b/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrder.cs new file mode 100644 index 0000000..2a5ddba --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrder.cs @@ -0,0 +1,20 @@ +using BealeEngineering.Core.Logic.Utilities; +using System; +using System.Collections.Generic; +using System.Text; + +namespace BealeEngineering.Core.Model.Client +{ + public class PurchaseOrder : PurchaseOrderHeader + { + public int OrderLineCount + { + get + { + if (OrderLineList == null) { return 0; } + else { return OrderLineList.Count; } + } + } + public List OrderLineList { get; set; } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrderHeader.cs b/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrderHeader.cs new file mode 100644 index 0000000..e61bcf1 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrderHeader.cs @@ -0,0 +1,38 @@ +using BealeEngineering.Core.Logic.Utilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Model.Client +{ + public class PurchaseOrderHeader + { + public int ClientPurchaseOrderID { get; set; } + public DateTime PurchaseOrderDate { get; set; } + public int ContactID { 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 new file mode 100644 index 0000000..25141ed --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Model/Client/PurchaseOrderLine.cs @@ -0,0 +1,16 @@ +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/ContactHeader.cs b/BealeEngineering/BealeEngineering.Core/Model/Contact/ContactHeader.cs new file mode 100644 index 0000000..3937b5c --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Model/Contact/ContactHeader.cs @@ -0,0 +1,15 @@ +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 new file mode 100644 index 0000000..022e23d --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Model/Sale/Invoice.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Model.Sale +{ + public class Invoice : InvoiceHeader + { + public List InvoiceLineList { get; set; } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceHeader.cs b/BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceHeader.cs new file mode 100644 index 0000000..6eaa918 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceHeader.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Model.Sale +{ + public class InvoiceHeader + { + public int SaleInvoiceID { get; set; } + public int ContactID { get; set; } + public string SaleInvoiceNumber { get; set; } + public DateTime InvoiceDate { get; set; } + public DateTime DueDate { get; set; } + public string Reference { get; set; } + public string CurrencyCode { get; set; } + public decimal InvoiceTotal { get; set;} + public decimal TaxTotal { get; set; } + public bool IsCreditNote { get; set; } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceLine.cs b/BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceLine.cs new file mode 100644 index 0000000..e9d61fd --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Model/Sale/InvoiceLine.cs @@ -0,0 +1,23 @@ +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/Properties/AssemblyInfo.cs b/BealeEngineering/BealeEngineering.Core/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..23cbc07 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BealeEngineering.Core")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BealeEngineering.Core")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fd88a52a-fde5-4d0a-abdf-ee87d19f21bd")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/BealeEngineering/BealeEngineering.Core/Test/AUtoexec.cs b/BealeEngineering/BealeEngineering.Core/Test/AUtoexec.cs new file mode 100644 index 0000000..26004e1 --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Test/AUtoexec.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Test +{ + public class Autoexec + { + public Autoexec(string sqlConnectionString) + { + SqlConnectionString = sqlConnectionString; + } + private string SqlConnectionString { get; set; } + + public void Start() + { + // 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(); + + + + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Test/Client/PurchaseOrder.cs b/BealeEngineering/BealeEngineering.Core/Test/Client/PurchaseOrder.cs new file mode 100644 index 0000000..9cc347a --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Test/Client/PurchaseOrder.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Test.Client +{ + public class PurchaseOrder + { + public List PurchaseOrderIdList { get; set; } + public string SqlConnectionString { get; set; } + public PurchaseOrder(string sqlConnectionString) + { + SqlConnectionString = sqlConnectionString; + PurchaseOrderIdList = new List { 92, 17, 140 }; + } + public void Start() + { + GetPurchaseOrderById(); + } + public void GetPurchaseOrderById() + { + var inst = new Core.Data.Database.Client.PurchaseOrderGet(SqlConnectionString); + var newList = inst.GetByClientPurchaseOrderId(PurchaseOrderIdList); + } + public void AllocateInvoicesToPurchaseOrders() + { + var inst = new Logic.Client.PurchaseOrderAutoAllocate(SqlConnectionString); + inst.Execute(); + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/Test/Sales/Invoice.cs b/BealeEngineering/BealeEngineering.Core/Test/Sales/Invoice.cs new file mode 100644 index 0000000..d4c4b1d --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/Test/Sales/Invoice.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BealeEngineering.Core.Test.Sales +{ + public class Invoice + { + public Invoice(string sqlConnectionString) + { + SqlConnectionString = sqlConnectionString; + SaleInvoiceIdList = new List { 131, 481, 105, 324 }; + } + private string SqlConnectionString { get; set; } + public List SaleInvoiceIdList { get; set; } + + public void GetInvoice() + { + var InvInst = new Data.Database.Sale.InvoiceGet(SqlConnectionString); + var lkdjflsk = InvInst.GetBySaleInvoiceId(SaleInvoiceIdList); + } + } +} diff --git a/BealeEngineering/BealeEngineering.Core/packages.config b/BealeEngineering/BealeEngineering.Core/packages.config new file mode 100644 index 0000000..e38523d --- /dev/null +++ b/BealeEngineering/BealeEngineering.Core/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/BealeEngineering/BealeEngineering.sln b/BealeEngineering/BealeEngineering.sln new file mode 100644 index 0000000..63414c6 --- /dev/null +++ b/BealeEngineering/BealeEngineering.sln @@ -0,0 +1,33 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29306.81 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Lib", "Lib", "{BC929CBA-5FE7-4A75-9AED-B4699E340B0D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BealeEngineering.Accounts", "BealeEngineering.Accounts\BealeEngineering.Accounts.csproj", "{F025483F-53D1-47FC-9691-EB771FD845EF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BealeEngineering.Core", "BealeEngineering.Core\BealeEngineering.Core.csproj", "{FD88A52A-FDE5-4D0A-ABDF-EE87D19F21BD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F025483F-53D1-47FC-9691-EB771FD845EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F025483F-53D1-47FC-9691-EB771FD845EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F025483F-53D1-47FC-9691-EB771FD845EF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F025483F-53D1-47FC-9691-EB771FD845EF}.Release|Any CPU.Build.0 = Release|Any CPU + {FD88A52A-FDE5-4D0A-ABDF-EE87D19F21BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD88A52A-FDE5-4D0A-ABDF-EE87D19F21BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD88A52A-FDE5-4D0A-ABDF-EE87D19F21BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD88A52A-FDE5-4D0A-ABDF-EE87D19F21BD}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0583C62C-021B-4409-A7C8-85463F2CEA0C} + EndGlobalSection +EndGlobal