diff --git a/TechTest/AnyCompany/AnyCompany.csproj b/TechTest/AnyCompany/AnyCompany.csproj
index 5b0498d..fcb208e 100644
--- a/TechTest/AnyCompany/AnyCompany.csproj
+++ b/TechTest/AnyCompany/AnyCompany.csproj
@@ -40,12 +40,25 @@
-
-
-
-
-
+
+
+
+ True
+ True
+ Settings.settings
+
+
+
+
+
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany/Customer.cs b/TechTest/AnyCompany/Customer.cs
deleted file mode 100644
index aa994b6..0000000
--- a/TechTest/AnyCompany/Customer.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-
-namespace AnyCompany
-{
- public class Customer
- {
- public string Country { get; set; }
-
- public DateTime DateOfBirth { get; set; }
-
- public string Name { get; set; }
- }
-}
diff --git a/TechTest/AnyCompany/CustomerRepository.cs b/TechTest/AnyCompany/CustomerRepository.cs
deleted file mode 100644
index e3de9b7..0000000
--- a/TechTest/AnyCompany/CustomerRepository.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System;
-using System.Data.SqlClient;
-
-namespace AnyCompany
-{
- public static class CustomerRepository
- {
- private static string ConnectionString = @"Data Source=(local);Database=Customers;User Id=admin;Password=password;";
-
- public static Customer Load(int customerId)
- {
- Customer customer = new Customer();
-
- SqlConnection connection = new SqlConnection(ConnectionString);
- connection.Open();
-
- SqlCommand command = new SqlCommand("SELECT * FROM Customer WHERE CustomerId = " + customerId,
- connection);
- var reader = command.ExecuteReader();
-
- while (reader.Read())
- {
- customer.Name = reader["Name"].ToString();
- customer.DateOfBirth = DateTime.Parse(reader["DateOfBirth"].ToString());
- customer.Country = reader["Country"].ToString();
- }
-
- connection.Close();
-
- return customer;
- }
- }
-}
diff --git a/TechTest/AnyCompany/Helpers/VatHelper.cs b/TechTest/AnyCompany/Helpers/VatHelper.cs
new file mode 100644
index 0000000..d473d5c
--- /dev/null
+++ b/TechTest/AnyCompany/Helpers/VatHelper.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Specialized;
+
+namespace AnyCompany.Helpers
+{
+ ///
+ /// This class contains VAT helper functions.
+ ///
+ public static class VatHelper
+ {
+
+ ///
+ /// Finds the correct VAT rate in settings based on the given country.
+ ///
+ /// The country code to use for the VAT lookup.
+ public static double GetVatRateByCountry(string countryCode)
+ {
+ StringCollection vatSettings = Properties.Settings.Default.VatSettings;
+
+ foreach (string setting in vatSettings)
+ {
+ // Confirm that this settings matches the 'CountryCode:Rate' pattern, split into an array, and confirm the second array element is indeed double compatible.
+ if (setting.Contains(":"))
+ {
+ string[] settingsPart = setting.Split(':');
+
+ if (settingsPart.Length == 2 && settingsPart[0].Equals(countryCode, StringComparison.OrdinalIgnoreCase))
+ {
+ double testVal = 0;
+
+ if (double.TryParse(settingsPart[1], out testVal))
+ {
+ return testVal;
+ }
+ }
+ }
+ }
+
+ return 0;
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/Models/Customer.cs b/TechTest/AnyCompany/Models/Customer.cs
new file mode 100644
index 0000000..a7cadc3
--- /dev/null
+++ b/TechTest/AnyCompany/Models/Customer.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+
+namespace AnyCompany.Models
+{
+ ///
+ /// This is the Customer Model
+ ///
+ public class Customer
+ {
+ public int CustomerId { get; set; }
+
+ public string Country { get; set; }
+
+ public DateTime DateOfBirth { get; set; }
+
+ public string Name { get; set; }
+
+ public List Orders { get; set; }
+
+ public Customer()
+ {
+ Orders = new List();
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/Order.cs b/TechTest/AnyCompany/Models/Order.cs
similarity index 52%
rename from TechTest/AnyCompany/Order.cs
rename to TechTest/AnyCompany/Models/Order.cs
index fec8e7b..d48ae45 100644
--- a/TechTest/AnyCompany/Order.cs
+++ b/TechTest/AnyCompany/Models/Order.cs
@@ -1,9 +1,14 @@
-namespace AnyCompany
+namespace AnyCompany.Models
{
+ ///
+ /// This is the Order Model
+ ///
public class Order
{
public int OrderId { get; set; }
public double Amount { get; set; }
public double VAT { get; set; }
+
+ public int CustomerId { get; set; }
}
}
diff --git a/TechTest/AnyCompany/OrderRepository.cs b/TechTest/AnyCompany/OrderRepository.cs
deleted file mode 100644
index 3229885..0000000
--- a/TechTest/AnyCompany/OrderRepository.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System.Data.SqlClient;
-
-namespace AnyCompany
-{
- internal class OrderRepository
- {
- private static string ConnectionString = @"Data Source=(local);Database=Orders;User Id=admin;Password=password;";
-
- public void Save(Order order)
- {
- SqlConnection connection = new SqlConnection(ConnectionString);
- connection.Open();
-
- SqlCommand command = new SqlCommand("INSERT INTO Orders VALUES (@OrderId, @Amount, @VAT)", connection);
-
- command.Parameters.AddWithValue("@OrderId", order.OrderId);
- command.Parameters.AddWithValue("@Amount", order.Amount);
- command.Parameters.AddWithValue("@VAT", order.VAT);
-
- command.ExecuteNonQuery();
-
- connection.Close();
- }
- }
-}
diff --git a/TechTest/AnyCompany/OrderService.cs b/TechTest/AnyCompany/OrderService.cs
deleted file mode 100644
index ebfb103..0000000
--- a/TechTest/AnyCompany/OrderService.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-namespace AnyCompany
-{
- public class OrderService
- {
- private readonly OrderRepository orderRepository = new OrderRepository();
-
- public bool PlaceOrder(Order order, int customerId)
- {
- Customer customer = CustomerRepository.Load(customerId);
-
- if (order.Amount == 0)
- return false;
-
- if (customer.Country == "UK")
- order.VAT = 0.2d;
- else
- order.VAT = 0;
-
- orderRepository.Save(order);
-
- return true;
- }
- }
-}
diff --git a/TechTest/AnyCompany/Properties/Settings.Designer.cs b/TechTest/AnyCompany/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..e563077
--- /dev/null
+++ b/TechTest/AnyCompany/Properties/Settings.Designer.cs
@@ -0,0 +1,55 @@
+//------------------------------------------------------------------------------
+//
+// 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 AnyCompany.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.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;
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("Data Source=(local);Database=Orders;User Id=admin;Password=password;")]
+ public string OrderConnectionString {
+ get {
+ return ((string)(this["OrderConnectionString"]));
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("Data Source=(local);Database=Customers;User Id=admin;Password=password;")]
+ public string CustomerConnectionString {
+ get {
+ return ((string)(this["CustomerConnectionString"]));
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("\r\n\r\n UK: 0.2\r\n")]
+ public global::System.Collections.Specialized.StringCollection VatSettings {
+ get {
+ return ((global::System.Collections.Specialized.StringCollection)(this["VatSettings"]));
+ }
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/Properties/Settings.settings b/TechTest/AnyCompany/Properties/Settings.settings
new file mode 100644
index 0000000..715ce80
--- /dev/null
+++ b/TechTest/AnyCompany/Properties/Settings.settings
@@ -0,0 +1,18 @@
+
+
+
+
+
+ Data Source=(local);Database=Orders;User Id=admin;Password=password;
+
+
+ Data Source=(local);Database=Customers;User Id=admin;Password=password;
+
+
+ <?xml version="1.0" encoding="utf-16"?>
+<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <string>UK:0.2</string>
+</ArrayOfString>
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany/Repositories/CustomerRepository.cs b/TechTest/AnyCompany/Repositories/CustomerRepository.cs
new file mode 100644
index 0000000..dc275b2
--- /dev/null
+++ b/TechTest/AnyCompany/Repositories/CustomerRepository.cs
@@ -0,0 +1,70 @@
+using AnyCompany.Models;
+using System;
+using System.Collections.Generic;
+using System.Data.SqlClient;
+
+namespace AnyCompany.Repositories
+{
+ ///
+ /// This is the Customer Repository, responsible for managing customer persistance and retrieval.
+ ///
+ public static class CustomerRepository
+ {
+ ///
+ /// This loads a Customer object.
+ ///
+ /// The Id of the customer this order is placed agains.
+ public static Customer Load(int customerId)
+ {
+ Customer customer = new Customer();
+
+ SqlConnection connection = new SqlConnection(Properties.Settings.Default.CustomerConnectionString);
+ connection.Open();
+
+ SqlCommand command = new SqlCommand("SELECT * FROM Customer WHERE CustomerId = @CustomerId", connection);
+
+ command.Parameters.AddWithValue("@CustomerId", customerId);
+
+ var reader = command.ExecuteReader();
+
+ while (reader.Read())
+ {
+ customer.CustomerId = int.Parse(reader["CustomerId"].ToString());
+ customer.Name = reader["Name"].ToString();
+ customer.DateOfBirth = DateTime.Parse(reader["DateOfBirth"].ToString());
+ customer.Country = reader["Country"].ToString();
+ }
+
+ connection.Close();
+
+ return customer;
+ }
+
+ public static List GetAll()
+ {
+ List customers = new List();
+
+ SqlConnection connection = new SqlConnection(Properties.Settings.Default.CustomerConnectionString);
+ connection.Open();
+
+ SqlCommand command = new SqlCommand("SELECT * FROM Customer", connection);
+
+ var reader = command.ExecuteReader();
+
+ while (reader.Read())
+ {
+ customers.Add(new Customer()
+ {
+ CustomerId = int.Parse(reader["CustomerId"].ToString()),
+ Name = reader["Name"].ToString(),
+ DateOfBirth = DateTime.Parse(reader["DateOfBirth"].ToString()),
+ Country = reader["Country"].ToString()
+ });
+ }
+
+ connection.Close();
+
+ return customers;
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/Repositories/OrderRepository.cs b/TechTest/AnyCompany/Repositories/OrderRepository.cs
new file mode 100644
index 0000000..b1a498b
--- /dev/null
+++ b/TechTest/AnyCompany/Repositories/OrderRepository.cs
@@ -0,0 +1,62 @@
+using AnyCompany.Models;
+using System.Collections.Generic;
+using System.Data.SqlClient;
+
+namespace AnyCompany.Repositories
+{
+ ///
+ /// This is the OrderRepository Repository, responsible for managing customer persistance and retrieval.
+ ///
+ internal class OrderRepository
+ {
+ ///
+ /// This stores an Order object.
+ ///
+ /// The order information.
+ public void Save(Order order)
+ {
+ SqlConnection connection = new SqlConnection(Properties.Settings.Default.OrderConnectionString);
+ connection.Open();
+
+ SqlCommand command = new SqlCommand("INSERT INTO Orders VALUES (@OrderId, @Amount, @VAT, @CustomerId)", connection);
+
+ command.Parameters.AddWithValue("@OrderId", order.OrderId);
+ command.Parameters.AddWithValue("@Amount", order.Amount);
+ command.Parameters.AddWithValue("@VAT", order.VAT);
+ command.Parameters.AddWithValue("@CustomerId", order.CustomerId);
+
+ command.ExecuteNonQuery();
+
+ connection.Close();
+ }
+
+ public List GetAllByCustomerId(int customerId)
+ {
+ List orders = new List();
+
+ SqlConnection connection = new SqlConnection(Properties.Settings.Default.CustomerConnectionString);
+ connection.Open();
+
+ SqlCommand command = new SqlCommand("SELECT * FROM Orders WHERE CustomerId = @CustomerId", connection);
+
+ command.Parameters.AddWithValue("@CustomerId", customerId);
+
+ var reader = command.ExecuteReader();
+
+ while (reader.Read())
+ {
+ orders.Add(new Order()
+ {
+ OrderId = int.Parse(reader["OrderId"].ToString()),
+ Amount = double.Parse(reader["Amount"].ToString()),
+ VAT = double.Parse(reader["VAT"].ToString()),
+ CustomerId = int.Parse(reader["CustomerId"].ToString())
+ });
+ }
+
+ connection.Close();
+
+ return orders;
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/Services/OrderService.cs b/TechTest/AnyCompany/Services/OrderService.cs
new file mode 100644
index 0000000..3154455
--- /dev/null
+++ b/TechTest/AnyCompany/Services/OrderService.cs
@@ -0,0 +1,56 @@
+using AnyCompany.Helpers;
+using AnyCompany.Models;
+using AnyCompany.Repositories;
+using System;
+using System.Collections.Generic;
+
+namespace AnyCompany.Services
+{
+ ///
+ /// This is the Order Service, and main entry point for this library. Orders are managed from here.
+ ///
+ public class OrderService
+ {
+ private readonly OrderRepository orderRepository = new OrderRepository();
+
+ ///
+ /// This places and persists an order.
+ ///
+ /// The order information.
+ /// The Id of the customer this order is placed agains.
+ public bool PlaceOrder(Order order, int customerId)
+ {
+ Customer customer = CustomerRepository.Load(customerId);
+
+ if (customer == null)
+ throw new ArgumentException("Customer could not be loaded. Invalid customer Id.");
+
+ if (order.Amount == 0)
+ return false;
+
+ order.VAT = VatHelper.GetVatRateByCountry(customer.Country);
+ order.CustomerId = customer.CustomerId;
+ orderRepository.Save(order);
+
+ return true;
+ }
+
+ public List ListCustomers(bool includeOrders)
+ {
+ // Fetch all customers from the customer database
+ List customers = CustomerRepository.GetAll();
+
+ // Now, fetch all orders for each customer from the orders database
+ // This method is slow due to a unique call per customer. A future update should perhaps investigate passing a list of customers, and splitting in memory after retrieval.
+ if (includeOrders)
+ {
+ foreach (Customer customer in customers)
+ {
+ customer.Orders = orderRepository.GetAllByCustomerId(customer.CustomerId);
+ }
+ }
+
+ return customers;
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/app.config b/TechTest/AnyCompany/app.config
new file mode 100644
index 0000000..1f98457
--- /dev/null
+++ b/TechTest/AnyCompany/app.config
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+ Data Source=(local);Database=Orders;User Id=admin;Password=password;
+
+
+ Data Source=(local);Database=Customers;User Id=admin;Password=password;
+
+
+
+
+ UK: 0.2
+
+
+
+
+
+
\ No newline at end of file