diff --git a/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj b/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj
index b537fc2..da78990 100644
--- a/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj
+++ b/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj
@@ -1,11 +1,11 @@
-
+
Debug
AnyCPU
- cd5d577e-bdc9-4dfc-ac6a-b1da474995f3
- Library
+ {CD5D577E-BDC9-4DFC-AC6A-B1DA474995F3}
+ Exe
Properties
AnyCompany.Tests
AnyCompany.Tests
@@ -29,25 +29,28 @@
prompt
4
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
+
+
+ {c7e15594-7d8f-4c18-9dd7-14f3fbb1572d}
+ AnyCompany
+
+
-
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany.Tests/Class1.cs b/TechTest/AnyCompany.Tests/Class1.cs
deleted file mode 100644
index 5957505..0000000
--- a/TechTest/AnyCompany.Tests/Class1.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace AnyCompany.Tests
-{
- public class Class1
- {
- }
-}
diff --git a/TechTest/AnyCompany.Tests/Program.cs b/TechTest/AnyCompany.Tests/Program.cs
new file mode 100644
index 0000000..05e291a
--- /dev/null
+++ b/TechTest/AnyCompany.Tests/Program.cs
@@ -0,0 +1,27 @@
+using AnyCompany.Model;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.Tests
+{
+ public class Program
+ {
+ static void Main(string[] args)
+ {
+ //Orderservice should be injected using a dependency injection container(e.g. Unity)
+ IOrderService orderService = new OrderService();
+
+ List customers = orderService.LoadAllCustomersAndOrders();
+
+ Order order = new Order
+ {
+ Amount = 22d
+ };
+
+ orderService.PlaceOrder(order, 1);
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/AnyCompany.csproj b/TechTest/AnyCompany/AnyCompany.csproj
index 5b0498d..ec07820 100644
--- a/TechTest/AnyCompany/AnyCompany.csproj
+++ b/TechTest/AnyCompany/AnyCompany.csproj
@@ -31,6 +31,7 @@
+
@@ -40,11 +41,16 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
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/IOrderService.cs b/TechTest/AnyCompany/IOrderService.cs
new file mode 100644
index 0000000..bce55cd
--- /dev/null
+++ b/TechTest/AnyCompany/IOrderService.cs
@@ -0,0 +1,12 @@
+using AnyCompany.Model;
+using System.Collections.Generic;
+
+namespace AnyCompany
+{
+ public interface IOrderService
+ {
+ bool PlaceOrder(Order order, int customerId);
+
+ List LoadAllCustomersAndOrders();
+ }
+}
diff --git a/TechTest/AnyCompany/Customer.cs b/TechTest/AnyCompany/Model/Customer.cs
similarity index 55%
rename from TechTest/AnyCompany/Customer.cs
rename to TechTest/AnyCompany/Model/Customer.cs
index aa994b6..59ee8f1 100644
--- a/TechTest/AnyCompany/Customer.cs
+++ b/TechTest/AnyCompany/Model/Customer.cs
@@ -1,13 +1,18 @@
using System;
+using System.Collections.Generic;
-namespace AnyCompany
+namespace AnyCompany.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; }
}
}
diff --git a/TechTest/AnyCompany/Order.cs b/TechTest/AnyCompany/Model/Order.cs
similarity index 83%
rename from TechTest/AnyCompany/Order.cs
rename to TechTest/AnyCompany/Model/Order.cs
index fec8e7b..294ad17 100644
--- a/TechTest/AnyCompany/Order.cs
+++ b/TechTest/AnyCompany/Model/Order.cs
@@ -1,9 +1,11 @@
-namespace AnyCompany
+namespace AnyCompany.Model
{
public class Order
{
public int OrderId { get; set; }
+
public double Amount { get; set; }
+
public double VAT { 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
index ebfb103..417d31b 100644
--- a/TechTest/AnyCompany/OrderService.cs
+++ b/TechTest/AnyCompany/OrderService.cs
@@ -1,24 +1,60 @@
-namespace AnyCompany
+using AnyCompany.Model;
+using System;
+using System.Collections.Generic;
+
+namespace AnyCompany
{
- public class OrderService
+ public class OrderService : IOrderService
{
private readonly OrderRepository orderRepository = new OrderRepository();
+ public List LoadAllCustomersAndOrders()
+ {
+ try
+ {
+ List customers = CustomerRepository.LoadAllCustomers();
+
+ return customers;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Failed to load customers.", ex);
+ }
+ }
+
public bool PlaceOrder(Order order, int customerId)
{
- Customer customer = CustomerRepository.Load(customerId);
+ if (order == null)
+ throw new ArgumentNullException();
+
+ try
+ {
+ Customer customer = CustomerRepository.Load(customerId);
+
+ if (order.Amount == 0)
+ return false;
- if (order.Amount == 0)
- return false;
+ if (customer == null)
+ return false;
- if (customer.Country == "UK")
- order.VAT = 0.2d;
- else
- order.VAT = 0;
+ switch (customer.Country)
+ {
+ case "UK":
+ order.VAT = 0.2d;
+ break;
+ default:
+ order.VAT = 0;
+ break;
+ }
- orderRepository.Save(order);
+ orderRepository.Save(order, customerId);
- return true;
+ return true;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception($"Failed to save order for customer with customer ID {customerId}", ex);
+ }
}
}
}
diff --git a/TechTest/AnyCompany/Persistence/CustomerRepository.cs b/TechTest/AnyCompany/Persistence/CustomerRepository.cs
new file mode 100644
index 0000000..3b80639
--- /dev/null
+++ b/TechTest/AnyCompany/Persistence/CustomerRepository.cs
@@ -0,0 +1,161 @@
+using AnyCompany.Model;
+using AnyCompany.Persistence;
+using System;
+using System.Collections.Generic;
+
+namespace AnyCompany
+{
+ public static class CustomerRepository
+ {
+ private static string ConnectionString = @"Data Source=(local);Database=Customers;User Id=admin;Password=password;";
+
+ private static OrderRepository _orderRepository;
+ private static IDataAccessObject _dataAccessObject;
+ private static DataAccessObjectFactory _dataAccessObjectFactory;
+
+ private static OrderRepository OrderRepository
+ {
+ get
+ {
+ if (_orderRepository == null)
+ {
+ _orderRepository = new OrderRepository();
+ }
+
+ return _orderRepository;
+ }
+ }
+
+ private static IDataAccessObject DataAccessObject
+ {
+ get
+ {
+ if (_dataAccessObject == null)
+ {
+ _dataAccessObject = DataAccessObjectFactory.CreateDataAccess();
+ }
+
+ return _dataAccessObject;
+ }
+ }
+
+ private static DataAccessObjectFactory DataAccessObjectFactory
+ {
+ get
+ {
+ if (_dataAccessObjectFactory == null)
+ {
+ _dataAccessObjectFactory = new DataAccessObjectFactory(ConnectionString);
+ }
+
+ return _dataAccessObjectFactory;
+ }
+ }
+
+ public static Customer Load(int customerId)
+ {
+ Customer customer = new Customer();
+
+ using (var connection = DataAccessObject.CreateConnection())
+ {
+ connection.Open();
+
+ string commandString = $"SELECT* FROM Customer WHERE CustomerId = {customerId}";
+
+ var command = DataAccessObject.CreateCommand(commandString, System.Data.CommandType.Text, connection);
+
+ 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();
+ }
+
+ DataAccessObject.CloseConnection(connection);
+ }
+
+ return customer;
+ }
+
+ public static Customer LoadCustomerAndOrders(int customerId)
+ {
+ Customer customer = Load(customerId);
+
+ if (!string.IsNullOrEmpty(customer.Name))
+ {
+ LoadCustomerOrders(customer);
+ }
+ else { return null; }
+
+ return customer;
+ }
+
+ private static void LoadCustomerOrders(Customer customer)
+ {
+ customer.Orders = OrderRepository.GetCustomerOrders(customer.CustomerId);
+ }
+
+ public static void Save(Customer customer)
+ {
+ using (var connection = DataAccessObject.CreateConnection())
+ {
+ connection.Open();
+
+ string commandString = "INSERT INTO Customer VALUES (@Name, @DateOfBirth, @Country)";
+
+ var command = DataAccessObject.CreateCommand(commandString, System.Data.CommandType.Text, connection);
+
+ command.Parameters.Add(DataParameterHelper.CreateParameter(string.Empty, "@Name", 150, customer.Name, System.Data.DbType.String));
+ command.Parameters.Add(DataParameterHelper.CreateParameter(string.Empty, "@DateOfBirth", customer.DateOfBirth, System.Data.DbType.Date));
+ command.Parameters.Add(DataParameterHelper.CreateParameter(string.Empty, "@Country", 150, customer.Country, System.Data.DbType.String));
+
+ command.ExecuteNonQuery();
+
+ DataAccessObject.CloseConnection(connection);
+ }
+ }
+
+ public static List LoadAllCustomers()
+ {
+ List customers = new List();
+
+ using (var connection = DataAccessObject.CreateConnection())
+ {
+ connection.Open();
+
+ string commandString = $"SELECT * FROM Customer";
+
+ var command = DataAccessObject.CreateCommand(commandString, System.Data.CommandType.Text, connection);
+
+ var reader = command.ExecuteReader();
+
+ while (reader.Read())
+
+ {
+ var customer = new Customer
+ {
+ CustomerId = int.Parse(reader["CustomerId"].ToString()),
+ Name = reader["Name"].ToString(),
+ DateOfBirth = DateTime.Parse(reader["DateOfBirth"].ToString()),
+ Country = reader["Country"].ToString()
+ };
+
+ customers.Add(customer);
+ }
+
+ DataAccessObject.CloseConnection(connection);
+ }
+
+ foreach (var customer in customers)
+ {
+ LoadCustomerOrders(customer);
+ }
+
+ return customers;
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/Persistence/DataAccessObjectFactory.cs b/TechTest/AnyCompany/Persistence/DataAccessObjectFactory.cs
new file mode 100644
index 0000000..afdb9d1
--- /dev/null
+++ b/TechTest/AnyCompany/Persistence/DataAccessObjectFactory.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Configuration;
+
+namespace AnyCompany.Persistence
+{
+ class DataAccessObjectFactory
+ {
+ private string _connectionString;
+ private ConnectionStringSettings _connectionStringSettings;
+
+ public DataAccessObjectFactory(ConnectionStringSettings connectionStringSettings)
+ {
+ if (connectionStringSettings == null)
+ throw new ArgumentNullException();
+
+ _connectionStringSettings = connectionStringSettings;
+ }
+
+ public DataAccessObjectFactory(string connectionString)
+ {
+ if (string.IsNullOrEmpty(connectionString))
+ throw new ArgumentNullException();
+
+ _connectionString = connectionString;
+ }
+
+ public IDataAccessObject CreateDataAccess()
+ {
+ IDataAccessObject databaseObject;
+
+ if (_connectionStringSettings != null)
+ {
+ switch (_connectionStringSettings.ProviderName.ToLower())
+ {
+ case "system.data.sqlclient":
+ default:
+ databaseObject = new SqlDataAccessObject(_connectionStringSettings.ConnectionString);
+ break;
+ }
+ }
+ else
+ {
+ //Default to Sql Client connection. More work can be done to attempt to find the correct provider and create the correct object
+ databaseObject = new SqlDataAccessObject(_connectionString);
+ }
+
+ return databaseObject;
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/Persistence/DataParameterHelper.cs b/TechTest/AnyCompany/Persistence/DataParameterHelper.cs
new file mode 100644
index 0000000..4480d97
--- /dev/null
+++ b/TechTest/AnyCompany/Persistence/DataParameterHelper.cs
@@ -0,0 +1,55 @@
+using System.Data;
+using System.Data.SqlClient;
+
+namespace AnyCompany.Persistence
+{
+ class DataParameterHelper
+ {
+ public static IDbDataParameter CreateParameter(string providerName, string name, object value, DbType dbType, ParameterDirection direction = ParameterDirection.Input)
+ {
+ switch (providerName.ToLower())
+ {
+ case "system.data.sqlclient":
+ default:
+ return CreateSqlParameter(name, value, dbType, direction);
+ }
+ }
+
+ public static IDbDataParameter CreateParameter(string providerName, string name, int size, object value, DbType dbType, ParameterDirection direction = ParameterDirection.Input)
+ {
+ switch (providerName.ToLower())
+ {
+ case "system.data.sqlclient":
+ default:
+ return CreateSqlParameter(name, size, value, dbType, direction);
+ }
+ }
+
+ private static IDbDataParameter CreateSqlParameter(string name, object value, DbType dbType, ParameterDirection direction)
+ {
+ SqlParameter sqlParameter = new SqlParameter
+ {
+ DbType = dbType,
+ ParameterName = name,
+ Direction = direction,
+ Value = value
+ };
+
+ return sqlParameter;
+ }
+
+ private static IDbDataParameter CreateSqlParameter(string name, int size, object value, DbType dbType, ParameterDirection direction)
+ {
+ SqlParameter sqlParameter = new SqlParameter
+ {
+ DbType = dbType,
+ Size = size,
+ ParameterName = name,
+ Direction = direction,
+ Value = value
+ };
+
+ return sqlParameter;
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/Persistence/IDataAccessObject.cs b/TechTest/AnyCompany/Persistence/IDataAccessObject.cs
new file mode 100644
index 0000000..7bdc38e
--- /dev/null
+++ b/TechTest/AnyCompany/Persistence/IDataAccessObject.cs
@@ -0,0 +1,13 @@
+using System.Data;
+
+namespace AnyCompany.Persistence
+{
+ interface IDataAccessObject
+ {
+ IDbConnection CreateConnection();
+
+ void CloseConnection(IDbConnection connection);
+
+ IDbCommand CreateCommand(string commandText, CommandType commandType, IDbConnection connection);
+ }
+}
diff --git a/TechTest/AnyCompany/Persistence/OrderRepository.cs b/TechTest/AnyCompany/Persistence/OrderRepository.cs
new file mode 100644
index 0000000..9520ecb
--- /dev/null
+++ b/TechTest/AnyCompany/Persistence/OrderRepository.cs
@@ -0,0 +1,93 @@
+using AnyCompany.Model;
+using AnyCompany.Persistence;
+using System.Collections.Generic;
+using System.Data.SqlClient;
+
+namespace AnyCompany
+{
+ internal class OrderRepository
+ {
+ private static string ConnectionString = @"Data Source=(local);Database=Orders;User Id=admin;Password=password;";
+
+ private IDataAccessObject _dataAccessObject;
+ private DataAccessObjectFactory _dataAccessObjectFactory;
+
+ private IDataAccessObject DataAccessObject
+ {
+ get
+ {
+ if (_dataAccessObject == null)
+ {
+ _dataAccessObject = DataAccessObjectFactory.CreateDataAccess();
+ }
+
+ return _dataAccessObject;
+ }
+ }
+
+ private DataAccessObjectFactory DataAccessObjectFactory
+ {
+ get
+ {
+ if (_dataAccessObjectFactory == null)
+ {
+ _dataAccessObjectFactory = new DataAccessObjectFactory(ConnectionString);
+ }
+
+ return _dataAccessObjectFactory;
+ }
+ }
+
+ public void Save(Order order, int customerId)
+
+ {
+ using (var connection = DataAccessObject.CreateConnection())
+ {
+ connection.Open();
+
+ string commandString = "INSERT INTO [Orders] VALUES (@CustomerId, @Amount, @VAT)";
+
+ var command = DataAccessObject.CreateCommand(commandString, System.Data.CommandType.Text, connection);
+
+ command.Parameters.Add(DataParameterHelper.CreateParameter(string.Empty, "@CustomerId", customerId, System.Data.DbType.Int32));
+ command.Parameters.Add(DataParameterHelper.CreateParameter(string.Empty, "@Amount", order.Amount, System.Data.DbType.Double));
+ command.Parameters.Add(DataParameterHelper.CreateParameter(string.Empty, "@VAT", order.VAT, System.Data.DbType.Double));
+
+ command.ExecuteNonQuery();
+
+ DataAccessObject.CloseConnection(connection);
+ }
+ }
+
+ public List GetCustomerOrders(int customerId)
+ {
+ var orders = new List();
+
+ using (var connection = DataAccessObject.CreateConnection())
+ {
+ connection.Open();
+
+ string commandString = $"SELECT * FROM [Orders] WHERE CustomerId = {customerId}";
+
+ var command = DataAccessObject.CreateCommand(commandString, System.Data.CommandType.Text, connection);
+
+ var reader = command.ExecuteReader();
+
+ while (reader.Read())
+ {
+ var order = new Order
+ {
+ Amount = double.Parse(reader["Amount"].ToString()),
+ VAT = double.Parse(reader["VAT"].ToString()),
+ OrderId = int.Parse(reader["OrderId"].ToString())
+ };
+ orders.Add(order);
+ }
+
+ DataAccessObject.CloseConnection(connection);
+ }
+
+ return orders;
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/Persistence/SqlDataAccessObject.cs b/TechTest/AnyCompany/Persistence/SqlDataAccessObject.cs
new file mode 100644
index 0000000..be7026d
--- /dev/null
+++ b/TechTest/AnyCompany/Persistence/SqlDataAccessObject.cs
@@ -0,0 +1,42 @@
+using System.Data;
+using System.Data.SqlClient;
+
+namespace AnyCompany.Persistence
+{
+ class SqlDataAccessObject : IDataAccessObject
+ {
+ private string _connectionString;
+
+ public SqlDataAccessObject(string connectionString)
+ {
+ _connectionString = connectionString;
+ }
+
+ public void CloseConnection(IDbConnection connection)
+ {
+ var sqlConnection = (SqlConnection)connection;
+
+ sqlConnection.Close();
+ sqlConnection.Dispose();
+ }
+
+ public IDbCommand CreateCommand(string commandText, CommandType commandType, IDbConnection connection)
+ {
+ SqlCommand sqlCommand = new SqlCommand
+ {
+ CommandText = commandText,
+ Connection = (SqlConnection)connection,
+ CommandType = commandType
+ };
+
+ return sqlCommand;
+ }
+
+ public IDbConnection CreateConnection()
+ {
+ SqlConnection sqlConnection = new SqlConnection(_connectionString);
+
+ return sqlConnection;
+ }
+ }
+}
diff --git a/TechTest/TechTest.sln b/TechTest/TechTest.sln
index 1c1c57a..d49b783 100644
--- a/TechTest/TechTest.sln
+++ b/TechTest/TechTest.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27004.2005
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29728.190
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyCompany", "AnyCompany\AnyCompany.csproj", "{C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}"
EndProject