diff --git a/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj b/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj
index b537fc2..e3000cb 100644
--- a/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj
+++ b/TechTest/AnyCompany.Tests/AnyCompany.Tests.csproj
@@ -1,16 +1,19 @@
-
+
+
Debug
AnyCPU
- cd5d577e-bdc9-4dfc-ac6a-b1da474995f3
+ {CD5D577E-BDC9-4DFC-AC6A-B1DA474995F3}
Library
Properties
AnyCompany.Tests
AnyCompany.Tests
v4.6.1
512
+
+
true
@@ -30,24 +33,69 @@
4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll
+
+
+ ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll
+
+
+ ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll
+
+
+ ..\packages\MSTest.TestFramework.2.1.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll
+
+
+ ..\packages\MSTest.TestFramework.2.1.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll
+
+
+ ..\packages\Moq.4.14.5\lib\net45\Moq.dll
+
+
+ ..\packages\NSubstitute.4.2.2\lib\net46\NSubstitute.dll
+
+
+
+
+
+
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+
+
+ ..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+ {C7E15594-7D8F-4C18-9DD7-14F3FBB1572D}
+ AnyCompany
+
-
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany.Tests/App.config b/TechTest/AnyCompany.Tests/App.config
new file mode 100644
index 0000000..95fd945
--- /dev/null
+++ b/TechTest/AnyCompany.Tests/App.config
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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/CustomerSpec.cs b/TechTest/AnyCompany.Tests/CustomerSpec.cs
new file mode 100644
index 0000000..62687df
--- /dev/null
+++ b/TechTest/AnyCompany.Tests/CustomerSpec.cs
@@ -0,0 +1,65 @@
+using AnyCompany.DataAccessLayer;
+using AnyCompany.Models;
+using AnyCompany.RepositoryLayer;
+using AnyCompany.RepositoryLayer.Contracts;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using NSubstitute;
+using System;
+using System.Collections.Generic;
+using System.Data.Entity;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.Tests
+{
+ [TestClass]
+ public class CustomerSpec
+ {
+ private Mock contextMock;
+
+ [TestInitialize]
+ public void Init()
+ {
+ contextMock = new Mock();
+
+ var mockCustomer = new List
+ {
+ new Customer
+ {
+ Id = 1,
+ Name = "Senzo",
+ Surname = "Meyiwa",
+ Email = "senzomeyiwa@gmail.com",
+ DateOfBirth = DateTime.Now,
+ Country = "UK"
+ }
+ }.AsQueryable();
+
+ contextMock.Setup(c => c.Customers).Returns((DbSet)mockCustomer);
+ }
+
+ [TestMethod]
+ public void GivenAValidCustomerId_WhenRequestingCustomerDetails_ReturnCustomerDetails()
+ {
+
+ var customer = Substitute.For>();
+ var result = customer.GetCustomer(1);
+
+ Assert.AreEqual("Senzo",result.Name);
+ Assert.AreEqual("Meyiwa", result.Surname);
+ }
+
+ [TestMethod]
+ public void GivenAnInvalidCustomerId_WhenRequestingCustomerDetails_DontReturnCustomerDetails()
+ {
+ var customer = Substitute.For>();
+ var result = customer.GetCustomer(2);
+
+ Assert.AreEqual("", result.Name);
+ Assert.AreEqual("", result.Surname);
+ }
+
+ }
+}
diff --git a/TechTest/AnyCompany.Tests/DbTestHelper.cs b/TechTest/AnyCompany.Tests/DbTestHelper.cs
new file mode 100644
index 0000000..1329344
--- /dev/null
+++ b/TechTest/AnyCompany.Tests/DbTestHelper.cs
@@ -0,0 +1,38 @@
+using Moq;
+using System;
+using System.Collections.Generic;
+using System.Data.Entity;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.Tests
+{
+ public static class DbTestHelper
+ {
+ public static DbSet ToDbSet(this IEnumerable data) where T : class
+ {
+ var fakeData = data.AsQueryable();
+ var mockSet = new Mock>();
+
+ mockSet.As>().Setup(m => m.Provider).Returns(fakeData.Provider);
+ mockSet.As>().Setup(m => m.Expression).Returns(fakeData.Expression);
+ mockSet.As>().Setup(m => m.ElementType).Returns(fakeData.ElementType);
+ mockSet.As>().Setup(m => m.GetEnumerator()).Returns(fakeData.GetEnumerator());
+
+ return mockSet.Object;
+ }
+
+ public static Mock> ToDbMock(this IEnumerable data) where T : class
+ {
+ var fakeData = data.AsQueryable();
+ var mockSet = new Mock>();
+ mockSet.As>().Setup(m => m.Provider).Returns(fakeData.Provider);
+ mockSet.As>().Setup(m => m.Expression).Returns(fakeData.Expression);
+ mockSet.As>().Setup(m => m.ElementType).Returns(fakeData.ElementType);
+ mockSet.As>().Setup(m => m.GetEnumerator()).Returns(fakeData.GetEnumerator());
+
+ return mockSet;
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Tests/OrderServiceSpec.cs b/TechTest/AnyCompany.Tests/OrderServiceSpec.cs
new file mode 100644
index 0000000..df28f0d
--- /dev/null
+++ b/TechTest/AnyCompany.Tests/OrderServiceSpec.cs
@@ -0,0 +1,20 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.Tests
+{
+ [TestClass]
+ class OrderServiceSpec
+ {
+ [TestInitialize]
+ public void Init()
+ {
+
+ }
+
+ }
+}
diff --git a/TechTest/AnyCompany.Tests/OrderSpec.cs b/TechTest/AnyCompany.Tests/OrderSpec.cs
new file mode 100644
index 0000000..2f4e7a7
--- /dev/null
+++ b/TechTest/AnyCompany.Tests/OrderSpec.cs
@@ -0,0 +1,111 @@
+using AnyCompany.DataAccessLayer;
+using AnyCompany.Models;
+using AnyCompany.RepositoryLayer.Contracts;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using NSubstitute;
+using System;
+using System.Collections.Generic;
+using System.Data.Entity;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.Tests
+{
+ [TestClass]
+ class OrderSpec
+ {
+ private Mock contextMock;
+ private Mock> mockOrderRepository;
+
+ [TestInitialize]
+ public void Init()
+ {
+ contextMock = new Mock();
+ mockOrderRepository = new Mock>(contextMock.Object);
+
+ var mockCustomer = new List
+ {
+ new Customer
+ {
+ Id = 1,
+ Name = "Senzo",
+ Surname = "Meyiwa",
+ Email = "senzomeyiwa@gmail.com",
+ DateOfBirth = DateTime.Now,
+ Country = "UK"
+ },
+ new Customer
+ {
+ Id = 2,
+ Name = "Sipho",
+ Surname = "Khumalo",
+ Email = "siphokhumalo@gmail.com",
+ DateOfBirth = DateTime.Now,
+ Country = "ZAF"
+ }
+ }.AsQueryable();
+
+ var mockOrder = new List
+ {
+ new Order
+ {
+ Id = 1,
+ Amount = 200,
+ OrderNumber = "ABCDEF1234",
+ VAT = 0
+ },
+ new Order
+ {
+ Id = 2,
+ Amount = 500,
+ OrderNumber = "ABCDEF0123",
+ VAT = 0
+ }
+ }.AsQueryable();
+
+ var mockCustomerOrder = new List
+ {
+ new CustomerOrder
+ {
+ Id = 1,
+ CustomerId = 1,
+ OrderId = 1,
+ Completed = false
+ },
+ new CustomerOrder
+ {
+ Id = 1,
+ CustomerId = 1,
+ OrderId = 2,
+ Completed = false
+ }
+ }.AsQueryable();
+
+ contextMock.Setup(c => c.Customers).Returns((DbSet)mockCustomer);
+ contextMock.Setup(c => c.Orders).Returns((DbSet)mockOrder);
+ contextMock.Setup(c => c.CustomerOrders).Returns((DbSet)mockCustomerOrder);
+ }
+
+ [TestMethod]
+ public void GivenAValidCustomerId_WhenSearchingForCustomerOrders_ReturnCustomerOrders()
+ {
+ var order = Substitute.For>();
+ var result = order.GetCustomerOrders(1);
+
+ Assert.AreEqual("Senzo", result.Name);
+ Assert.AreEqual(2, result.Orders.Count());
+ }
+
+ [TestMethod]
+ public void GivenAnInvalidCustomerId_WhenSearchingForCustomerOrders_DoNotReturnCustomerOrders()
+ {
+ var order = Substitute.For>();
+ var result = order.GetCustomerOrders(3);
+
+ Assert.AreEqual("", result.Name);
+ Assert.AreEqual("", result.Email);
+ }
+ }
+}
diff --git a/TechTest/AnyCompany.Tests/UnitofWorkSpec.cs b/TechTest/AnyCompany.Tests/UnitofWorkSpec.cs
new file mode 100644
index 0000000..7139cde
--- /dev/null
+++ b/TechTest/AnyCompany.Tests/UnitofWorkSpec.cs
@@ -0,0 +1,20 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.Tests
+{
+ [TestClass]
+ class UnitofWorkSpec
+ {
+ [TestInitialize]
+ public void Init()
+ {
+
+ }
+
+ }
+}
diff --git a/TechTest/AnyCompany.Tests/packages.config b/TechTest/AnyCompany.Tests/packages.config
new file mode 100644
index 0000000..5fd9d58
--- /dev/null
+++ b/TechTest/AnyCompany.Tests/packages.config
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany/AnyCompany.csproj b/TechTest/AnyCompany/AnyCompany.csproj
index 5b0498d..0106dac 100644
--- a/TechTest/AnyCompany/AnyCompany.csproj
+++ b/TechTest/AnyCompany/AnyCompany.csproj
@@ -1,5 +1,6 @@
+
Debug
@@ -11,6 +12,8 @@
AnyCompany
v4.6.1
512
+
+
true
@@ -30,22 +33,132 @@
4
+
+ ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll
+
+
+ ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll
+
+
+ ..\packages\Microsoft.Data.SqlClient.2.0.0\lib\net46\Microsoft.Data.SqlClient.dll
+
+
+ ..\packages\Microsoft.Extensions.Primitives.3.1.6\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll
+
+
+ ..\packages\Microsoft.Identity.Client.4.14.0\lib\net45\Microsoft.Identity.Client.dll
+
+
+ ..\packages\Microsoft.IdentityModel.JsonWebTokens.5.6.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.dll
+
+
+ ..\packages\Microsoft.IdentityModel.Logging.5.6.0\lib\net461\Microsoft.IdentityModel.Logging.dll
+
+
+ ..\packages\Microsoft.IdentityModel.Protocols.5.6.0\lib\net461\Microsoft.IdentityModel.Protocols.dll
+
+
+ ..\packages\Microsoft.IdentityModel.Protocols.OpenIdConnect.5.6.0\lib\net461\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll
+
+
+ ..\packages\Microsoft.IdentityModel.Tokens.5.6.0\lib\net461\Microsoft.IdentityModel.Tokens.dll
+
+
+ ..\packages\Newtonsoft.Json.10.0.1\lib\net45\Newtonsoft.Json.dll
+
+
+ ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll
+
+
+
+
+ ..\packages\System.Configuration.ConfigurationManager.4.7.0\lib\net461\System.Configuration.ConfigurationManager.dll
+
+
+
+ ..\packages\System.Data.SqlClient.4.8.1\lib\net461\System.Data.SqlClient.dll
+
+
+
+
+ ..\packages\System.IdentityModel.Tokens.Jwt.5.6.0\lib\net461\System.IdentityModel.Tokens.Jwt.dll
+
+
+ ..\packages\System.Memory.4.5.2\lib\netstandard2.0\System.Memory.dll
+
+
+
+
+ ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll
+
+
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
+
+
+
+ ..\packages\System.Security.AccessControl.4.7.0\lib\net461\System.Security.AccessControl.dll
+
+
+ ..\packages\System.Security.Permissions.4.7.0\lib\net461\System.Security.Permissions.dll
+
+
+ ..\packages\System.Security.Principal.Windows.4.7.0\lib\net461\System.Security.Principal.Windows.dll
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+ 202008052050395_v1.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 202008052050395_v1.cs
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany/App.config b/TechTest/AnyCompany/App.config
new file mode 100644
index 0000000..fd5234c
--- /dev/null
+++ b/TechTest/AnyCompany/App.config
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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/DataAccessLayer/CompanyContext.cs b/TechTest/AnyCompany/DataAccessLayer/CompanyContext.cs
new file mode 100644
index 0000000..9efa5a1
--- /dev/null
+++ b/TechTest/AnyCompany/DataAccessLayer/CompanyContext.cs
@@ -0,0 +1,28 @@
+using AnyCompany.Models;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data.Entity;
+using System.Data.Entity.ModelConfiguration.Conventions;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.DataAccessLayer
+{
+ public class CompanyContext : DbContext, ICompanyContext
+ {
+ public CompanyContext() : base("CompanyContext")
+ {
+ }
+
+ public DbSet Orders { get; set; }
+ public DbSet Customers { get; set; }
+ public DbSet CustomerOrders { get; set; }
+
+ protected override void OnModelCreating(DbModelBuilder modelBuilder)
+ {
+ modelBuilder.Conventions.Remove();
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/DataAccessLayer/ICompanyContext.cs b/TechTest/AnyCompany/DataAccessLayer/ICompanyContext.cs
new file mode 100644
index 0000000..3452ea4
--- /dev/null
+++ b/TechTest/AnyCompany/DataAccessLayer/ICompanyContext.cs
@@ -0,0 +1,17 @@
+using AnyCompany.Models;
+using System;
+using System.Collections.Generic;
+using System.Data.Entity;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.DataAccessLayer
+{
+ public interface ICompanyContext
+ {
+ DbSet Orders { get; set; }
+ DbSet Customers { get; set; }
+ DbSet CustomerOrders { get; set; }
+ }
+}
diff --git a/TechTest/AnyCompany/Entities/CustomerOrderSet.cs b/TechTest/AnyCompany/Entities/CustomerOrderSet.cs
new file mode 100644
index 0000000..468e8d8
--- /dev/null
+++ b/TechTest/AnyCompany/Entities/CustomerOrderSet.cs
@@ -0,0 +1,17 @@
+using AnyCompany.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.Entities
+{
+ public class CustomerOrderSet
+ {
+ public string Name { get; set; }
+ public string Surname { get; set; }
+ public string Email { get; set; }
+ public IEnumerable Orders { get; set; }
+ }
+}
diff --git a/TechTest/AnyCompany/Entities/NewOrder.cs b/TechTest/AnyCompany/Entities/NewOrder.cs
new file mode 100644
index 0000000..0a9b2f3
--- /dev/null
+++ b/TechTest/AnyCompany/Entities/NewOrder.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.Entities
+{
+ public class NewOrder
+ {
+ public int CustomerId { get; set; }
+ public string OrderNumber { get; set; }
+ public double Amount { get; set; }
+ public double VAT { get; set; }
+ }
+}
diff --git a/TechTest/AnyCompany/IOrderService.cs b/TechTest/AnyCompany/IOrderService.cs
new file mode 100644
index 0000000..6e442cf
--- /dev/null
+++ b/TechTest/AnyCompany/IOrderService.cs
@@ -0,0 +1,17 @@
+using AnyCompany.Entities;
+using AnyCompany.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany
+{
+ public interface IOrderService
+ {
+ bool PlaceOrder(Order order, int customerId);
+ CustomerOrderSet GetCustomerOrders(int customerId);
+ IEnumerable GetCustomersWithOrders();
+ }
+}
diff --git a/TechTest/AnyCompany/Migrations/202008052050395_v1.Designer.cs b/TechTest/AnyCompany/Migrations/202008052050395_v1.Designer.cs
new file mode 100644
index 0000000..c757f1c
--- /dev/null
+++ b/TechTest/AnyCompany/Migrations/202008052050395_v1.Designer.cs
@@ -0,0 +1,29 @@
+//
+namespace AnyCompany.Migrations
+{
+ using System.CodeDom.Compiler;
+ using System.Data.Entity.Migrations;
+ using System.Data.Entity.Migrations.Infrastructure;
+ using System.Resources;
+
+ [GeneratedCode("EntityFramework.Migrations", "6.4.4")]
+ public sealed partial class v1 : IMigrationMetadata
+ {
+ private readonly ResourceManager Resources = new ResourceManager(typeof(v1));
+
+ string IMigrationMetadata.Id
+ {
+ get { return "202008052050395_v1"; }
+ }
+
+ string IMigrationMetadata.Source
+ {
+ get { return null; }
+ }
+
+ string IMigrationMetadata.Target
+ {
+ get { return Resources.GetString("Target"); }
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/Migrations/202008052050395_v1.cs b/TechTest/AnyCompany/Migrations/202008052050395_v1.cs
new file mode 100644
index 0000000..698b6af
--- /dev/null
+++ b/TechTest/AnyCompany/Migrations/202008052050395_v1.cs
@@ -0,0 +1,54 @@
+namespace AnyCompany.Migrations
+{
+ using System;
+ using System.Data.Entity.Migrations;
+
+ public partial class v1 : DbMigration
+ {
+ public override void Up()
+ {
+ CreateTable(
+ "dbo.CustomerOrder",
+ c => new
+ {
+ Id = c.Int(nullable: false, identity: true),
+ CustomerId = c.Int(nullable: false),
+ OrderId = c.Int(nullable: false),
+ Completed = c.Boolean(nullable: false),
+ })
+ .PrimaryKey(t => t.Id);
+
+ CreateTable(
+ "dbo.Customer",
+ c => new
+ {
+ Id = c.Int(nullable: false, identity: true),
+ Name = c.String(),
+ Surname = c.String(),
+ Email = c.String(),
+ Country = c.String(),
+ DateOfBirth = c.DateTime(nullable: false),
+ })
+ .PrimaryKey(t => t.Id);
+
+ CreateTable(
+ "dbo.Order",
+ c => new
+ {
+ Id = c.Int(nullable: false, identity: true),
+ OrderNumber = c.String(),
+ Amount = c.Double(nullable: false),
+ VAT = c.Double(nullable: false),
+ })
+ .PrimaryKey(t => t.Id);
+
+ }
+
+ public override void Down()
+ {
+ DropTable("dbo.Order");
+ DropTable("dbo.Customer");
+ DropTable("dbo.CustomerOrder");
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/Migrations/202008052050395_v1.resx b/TechTest/AnyCompany/Migrations/202008052050395_v1.resx
new file mode 100644
index 0000000..8cca66f
--- /dev/null
+++ b/TechTest/AnyCompany/Migrations/202008052050395_v1.resx
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+ H4sIAAAAAAAEAO1Z227jNhB9L9B/EPTUAlkrl5c2kHfhOEkRNImDVZJ3Who7RClSJanA/rY+9JP6Cx3qfrMt2UmwWCwMGNaIPDMcHg2Pxv/986/7ZRUy6xWkooKP7ZPRsW0B90VA+XJsx3rx6Tf7y+eff3KvgnBlPefjzsw4nMnV2H7ROjp3HOW/QEjUKKS+FEos9MgXoUMC4ZweH//unJw4gBA2YlmW+zXmmoaQXODlVHAfIh0TdicCYCqz4x0vQbXuSQgqIj6M7QlfT0UYEb4eXRJNJr4PSt2SNUjbmjBKMCIP2MK2COdCE43xnj8p8LQUfOlFaCDscR0BjlsQpiBbx3k5vO+Sjk/NkpxyYg7lx0qLcCDgyVmWI6c5fa9M20UOMYtXmG29NqtOMjm2p4kLkDMZmLw1PZ5PmTSja9lOt2ZUm3pklQOOCnogi8znyJrGTMcSxhxiLQk7sh7iOaP+n7B+FH8BH/OYsWqgGCreqxnQ9CBFBFKvv8IiC/8msC2nPs9pTiymVeaka7rh+uzUtu7ROZkzKHhQWb+nhYQ/gIMkGoIHojVIbjAgyWTLe8NXnqPdPrfjJDk+FMRsDwNcRg5zIQQDwncAuU7Jml5c2o9GPxjU6ct8596wdGE1tq07sroFvtQvYxt/2tY1XUGQW7IInjjF4o2TtIx3MsOLJf8IP1choezdvUwFHipy/e5+8NSB2eKCSv2S+zKmR2oy+TaP1B5l+Uc53uwryc19HM5NUt+ZHZPQ0LAghsAM76JFG+R58jgIYTuxUF1pQjF5lQOB8MQMK91BM5RLGdNUtuh6tCmsB7pLTSjbKoNJtdioITecfnDbkHaCbIylI4Y8fUWiSv3ppAI0F6rOBqXq3pEoQkJVlGtmsbxUtk4/ecN1XJhiOL7qkHNFtIUnfErIEhp3zX4HcE2l0kYvz4khzzQIO4bVaLEhvbmzzp1vlooy+fk08zt7UDbq+AZdGqBlaq9xtSFWgGThUETYVLet+clrBWFEdpSkqWBxyDeVtW2zq5qvilK190crlF8VqjAOiKoUf7WgSnMby3UaCW5uq9Pa10bxb7JlEJfenEYHMOijyJPKver81NIfodByVZDC2B8n02pVlMw0hHSZEqtTLjP2x6kprSpW7cY3Q+C3LYL7Fr8PLXo1ZdUqVfmN/ni5eqpC5bb+KIl8qkIkhg/mSUtUNIcU3gtx0RARbnag7+6JtU74dIhtYWJeaWBOd2+tNIQJy0be32zKKJik5gPuCKcLUDp9EbBPj09OG+20b6e15SgVsCH9rQ9/paEmtTtfWob2cVpNpcTNYS2lfSBaDaU53QUyvJn0fexZtY3DX4n0X4j8JSSrX6tIe7RqDsKqtWMOQmq0XA7C6mirBGjSb95W+T6Y1dHTOCj99b7FggkyvDBU2hZ9AIZ2LZpvsQOaErt7EumJiZybC1xDGvN+bYutXYttbvr1NDa3NLqwD+t2tAWI61T/unMvQdFlCWH+yOPgm5O9BM3H3PCFyAmDa6pGlA9p8OkONAmMLJaaLoiv8bbRx0nj7pmwOKllcwhu+CzWUawnSkE4Z7V3DNfZ7j9p6dRjdmeRuVJvsQQMk5oyNuMXMWVBEfd1x+OwAcIQPyscGJWnTQFZrguke8F7AmXpu4QIuCk7j4DnOIKpGffIK+wT25OCW1gSf53ryM0guzeinnb3kpKlJKHKMMr5eIkcDsLV5/8Blv8xosEeAAA=
+
+
+ dbo
+
+
\ No newline at end of file
diff --git a/TechTest/AnyCompany/Migrations/Configuration.cs b/TechTest/AnyCompany/Migrations/Configuration.cs
new file mode 100644
index 0000000..4d21a13
--- /dev/null
+++ b/TechTest/AnyCompany/Migrations/Configuration.cs
@@ -0,0 +1,35 @@
+namespace AnyCompany.Migrations
+{
+ using AnyCompany.DataAccessLayer;
+ using AnyCompany.Models;
+ using System;
+ using System.Collections.Generic;
+ using System.Data.Entity;
+ using System.Data.Entity.Migrations;
+ using System.Linq;
+
+ internal sealed class Configuration : DbMigrationsConfiguration
+ {
+ public Configuration()
+ {
+ AutomaticMigrationsEnabled = false;
+ }
+
+ protected override void Seed(CompanyContext context)
+ {
+ var customers = new List
+ {
+ //Create some dummy customers
+ new Customer { Id = 1, Name = "Geja", Surname = "Khoza", Email = "gejakhoza@gmail.com",
+ Country = "South Africa", DateOfBirth = DateTime.Parse("1980-09-06") },
+ new Customer { Id = 2, Name = "Ndo", Surname = "Mlondo", Email = "ndomlondo@gmail.com",
+ Country = "South Africa", DateOfBirth = DateTime.Parse("1984-06-01") },
+ new Customer { Id = 3, Name = "Khehla", Surname = "Ceza", Email = "khahlaceza@gmail.com",
+ Country = "South Africa", DateOfBirth = DateTime.Parse("1986-04-09") }
+ };
+
+ customers.ForEach(c => context.Customers.Add(c));
+ context.SaveChanges();
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/Models/Customer.cs b/TechTest/AnyCompany/Models/Customer.cs
new file mode 100644
index 0000000..b2a2a8e
--- /dev/null
+++ b/TechTest/AnyCompany/Models/Customer.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.Models
+{
+ public class Customer
+ {
+ public int Id { get; set; }
+ public string Name { get; set; }
+ public string Surname { get; set; }
+ public string Email { get; set; }
+ public string Country { get; set; }
+ public DateTime DateOfBirth { get; set; }
+ }
+}
diff --git a/TechTest/AnyCompany/Models/CustomerOrder.cs b/TechTest/AnyCompany/Models/CustomerOrder.cs
new file mode 100644
index 0000000..d47ae26
--- /dev/null
+++ b/TechTest/AnyCompany/Models/CustomerOrder.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.Models
+{
+ public class CustomerOrder
+ {
+ public int Id { get; set; }
+ public int CustomerId { get; set; }
+ public int OrderId { get; set; }
+ public bool Completed { get; set; }
+ }
+}
diff --git a/TechTest/AnyCompany/Models/Order.cs b/TechTest/AnyCompany/Models/Order.cs
new file mode 100644
index 0000000..4cb98f1
--- /dev/null
+++ b/TechTest/AnyCompany/Models/Order.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.Models
+{
+ public class Order
+ {
+ public int Id { get; set; }
+ public string OrderNumber { get; set; }
+ public double Amount { get; set; }
+ public double VAT { get; set; }
+ }
+}
diff --git a/TechTest/AnyCompany/Order.cs b/TechTest/AnyCompany/Order.cs
deleted file mode 100644
index fec8e7b..0000000
--- a/TechTest/AnyCompany/Order.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace AnyCompany
-{
- 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..e8b82ca 100644
--- a/TechTest/AnyCompany/OrderService.cs
+++ b/TechTest/AnyCompany/OrderService.cs
@@ -1,12 +1,21 @@
-namespace AnyCompany
+using AnyCompany.Entities;
+using AnyCompany.Models;
+using AnyCompany.RepositoryLayer;
+using System.Collections.Generic;
+
+namespace AnyCompany
{
- public class OrderService
+ public class OrderService : IOrderService
{
- private readonly OrderRepository orderRepository = new OrderRepository();
+ private readonly UnitofWork _unitofWork;
+ public OrderService(UnitofWork unitofWork)
+ {
+ _unitofWork = unitofWork;
+ }
public bool PlaceOrder(Order order, int customerId)
{
- Customer customer = CustomerRepository.Load(customerId);
+ var customer = _unitofWork.GetCustomer(customerId);
if (order.Amount == 0)
return false;
@@ -16,9 +25,26 @@ public bool PlaceOrder(Order order, int customerId)
else
order.VAT = 0;
- orderRepository.Save(order);
+ var newOrder = _unitofWork.SaveOrder(
+ new NewOrder
+ {
+ Amount = order.Amount,
+ CustomerId = customerId,
+ OrderNumber = order.OrderNumber,
+ VAT = order.VAT
+ });
+
+ return newOrder;
+ }
- return true;
+ public CustomerOrderSet GetCustomerOrders(int customerId)
+ {
+ return _unitofWork.GetCustomerOrderSets(customerId);
+ }
+
+ public IEnumerable GetCustomersWithOrders()
+ {
+ return _unitofWork.GetCustomersWithOrders();
}
}
}
diff --git a/TechTest/AnyCompany/RepositoryLayer/Contracts/ICustomerRepository.cs b/TechTest/AnyCompany/RepositoryLayer/Contracts/ICustomerRepository.cs
new file mode 100644
index 0000000..a38a3a5
--- /dev/null
+++ b/TechTest/AnyCompany/RepositoryLayer/Contracts/ICustomerRepository.cs
@@ -0,0 +1,14 @@
+using AnyCompany.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.RepositoryLayer.Contracts
+{
+ public interface ICustomerRepository where T : class
+ {
+ Customer GetCustomer(int customerId);
+ }
+}
diff --git a/TechTest/AnyCompany/RepositoryLayer/Contracts/IOrderRepository.cs b/TechTest/AnyCompany/RepositoryLayer/Contracts/IOrderRepository.cs
new file mode 100644
index 0000000..9c87555
--- /dev/null
+++ b/TechTest/AnyCompany/RepositoryLayer/Contracts/IOrderRepository.cs
@@ -0,0 +1,16 @@
+using AnyCompany.Entities;
+using AnyCompany.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.RepositoryLayer.Contracts
+{
+ public interface IOrderRepository where T : class
+ {
+ IEnumerable GetOrders();
+ CustomerOrderSet GetCustomerOrders(int customerId);
+ }
+}
diff --git a/TechTest/AnyCompany/RepositoryLayer/Contracts/ISaveOrderRepository.cs b/TechTest/AnyCompany/RepositoryLayer/Contracts/ISaveOrderRepository.cs
new file mode 100644
index 0000000..7e68c5c
--- /dev/null
+++ b/TechTest/AnyCompany/RepositoryLayer/Contracts/ISaveOrderRepository.cs
@@ -0,0 +1,15 @@
+using AnyCompany.Entities;
+using AnyCompany.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.RepositoryLayer.Contracts
+{
+ public interface ISaveOrderRepository where T : class
+ {
+ bool SaveOrder(NewOrder order);
+ }
+}
diff --git a/TechTest/AnyCompany/RepositoryLayer/Contracts/IUnitofWork.cs b/TechTest/AnyCompany/RepositoryLayer/Contracts/IUnitofWork.cs
new file mode 100644
index 0000000..70dc2e4
--- /dev/null
+++ b/TechTest/AnyCompany/RepositoryLayer/Contracts/IUnitofWork.cs
@@ -0,0 +1,18 @@
+using AnyCompany.Entities;
+using AnyCompany.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.RepositoryLayer
+{
+ public interface IUnitofWork
+ {
+ CustomerOrderSet GetCustomerOrderSets(int cutomerId);
+ List GetCustomersWithOrders();
+ Customer GetCustomer(int customerId);
+ bool SaveOrder(NewOrder newOrder);
+ }
+}
diff --git a/TechTest/AnyCompany/RepositoryLayer/CustomerRepository.cs b/TechTest/AnyCompany/RepositoryLayer/CustomerRepository.cs
new file mode 100644
index 0000000..10b7ccb
--- /dev/null
+++ b/TechTest/AnyCompany/RepositoryLayer/CustomerRepository.cs
@@ -0,0 +1,20 @@
+using AnyCompany.DataAccessLayer;
+using AnyCompany.Models;
+using AnyCompany.RepositoryLayer.Contracts;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.RepositoryLayer
+{
+ public static class CustomerRepository
+ {
+ private static readonly CompanyContext companyContext = new CompanyContext();
+ public static Customer Load(int customerId)
+ {
+ return companyContext.Customers.FirstOrDefault(c => c.Id == customerId);
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/RepositoryLayer/OrderRepository.cs b/TechTest/AnyCompany/RepositoryLayer/OrderRepository.cs
new file mode 100644
index 0000000..17ca434
--- /dev/null
+++ b/TechTest/AnyCompany/RepositoryLayer/OrderRepository.cs
@@ -0,0 +1,107 @@
+using AnyCompany.DataAccessLayer;
+using AnyCompany.Entities;
+using AnyCompany.Models;
+using AnyCompany.RepositoryLayer.Contracts;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.RepositoryLayer
+{
+ internal class OrderRepository : IOrderRepository, ISaveOrderRepository
+ {
+
+ private readonly CompanyContext _companyContext;
+
+ public OrderRepository(CompanyContext companyContext)
+ {
+ _companyContext = companyContext;
+ }
+ public CustomerOrderSet GetCustomerOrders(int customerId)
+ {
+ List orders = new List();
+ var customer = _companyContext.Customers.Single(c => c.Id == customerId);
+ var candidateCustomerOrders = from c in _companyContext.CustomerOrders
+ join o in _companyContext.Orders on
+ c.OrderId equals o.Id
+ select new {
+ customerId = c.Id,
+ oId = o.Id,
+ oNumber = o.OrderNumber,
+ oAmnt = o.Amount,
+ oVat = o.VAT };
+
+ foreach (var item in candidateCustomerOrders)
+ {
+ if (item.customerId == customerId)
+ orders.Add(new Order
+ {
+ Id = item.oId,
+ OrderNumber = item.oNumber,
+ Amount = item.oAmnt,
+ VAT = item.oVat
+ });
+ }
+
+
+ return new CustomerOrderSet
+ {
+ Name = customer.Name,
+ Surname = customer.Surname,
+ Email = customer.Email,
+ Orders = orders
+ };
+ }
+
+ public IEnumerable GetOrders()
+ {
+ return _companyContext.Orders.AsEnumerable();
+ }
+
+ public bool SaveOrder(NewOrder newOrder)
+ {
+ var orderSaved = false;
+ var order = new Order
+ {
+ Amount = newOrder.Amount,
+ OrderNumber = newOrder.OrderNumber,
+ VAT = newOrder.VAT
+ };
+
+ try
+ {
+ _companyContext.Orders.Add(order);
+ _companyContext.SaveChanges();
+ }
+ catch
+ {
+ orderSaved = false;
+ }
+
+ var latestOrder = _companyContext.Orders.FirstOrDefault(o => o.OrderNumber == order.OrderNumber).Id;
+
+ var customerOrder = new CustomerOrder
+ {
+ OrderId = latestOrder,
+ CustomerId = newOrder.CustomerId,
+ Completed = false
+ };
+
+ try
+ {
+ _companyContext.CustomerOrders.Add(customerOrder);
+ _companyContext.SaveChanges();
+ orderSaved = true;
+ }
+ catch
+ {
+ orderSaved = false;
+ }
+
+ return orderSaved;
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/RepositoryLayer/UnitofWork.cs b/TechTest/AnyCompany/RepositoryLayer/UnitofWork.cs
new file mode 100644
index 0000000..5709aa5
--- /dev/null
+++ b/TechTest/AnyCompany/RepositoryLayer/UnitofWork.cs
@@ -0,0 +1,83 @@
+using AnyCompany.DataAccessLayer;
+using AnyCompany.Entities;
+using AnyCompany.Models;
+using AnyCompany.RepositoryLayer.Contracts;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AnyCompany.RepositoryLayer
+{
+ public class UnitofWork : IUnitofWork
+ {
+ private readonly IOrderRepository _orderRepository;
+ private readonly ISaveOrderRepository _saveOrderRepository;
+ private readonly CompanyContext _companyContext;
+ public UnitofWork(IOrderRepository orderRepository, CompanyContext companyContext, ISaveOrderRepository saveOrderRepository)
+ {
+ _companyContext = companyContext;
+ _orderRepository = orderRepository;
+ _saveOrderRepository = saveOrderRepository;
+ }
+
+ public Customer GetCustomer(int customerId)
+ {
+ return _companyContext.Customers.Single(c => c.Id == customerId);
+ }
+
+ public CustomerOrderSet GetCustomerOrderSets(int cutomerId)
+ {
+ return _orderRepository.GetCustomerOrders(cutomerId);
+ }
+
+ public List GetCustomersWithOrders()
+ {
+ List customerOrderSets = new List();
+ List orders = new List();
+
+ var candidateCustomerOrders = from co in _companyContext.CustomerOrders
+ join o in _companyContext.Orders on
+ co.OrderId equals o.Id
+ join c in _companyContext.Customers on
+ co.CustomerId equals c.Id
+ select new
+ {
+ customerId = co.Id,
+ customerName = c.Name,
+ customerSurname = c.Surname,
+ customerEmail = c.Email,
+ oId = o.Id,
+ oNumber = o.OrderNumber,
+ oAmnt = o.Amount,
+ oVat = o.VAT
+ };
+ foreach (var item in candidateCustomerOrders)
+ {
+ var customerOrderSet = new CustomerOrderSet
+ {
+ Name = item.customerName,
+ Surname = item.customerSurname,
+ Email = item.customerEmail,
+ Orders = candidateCustomerOrders.Where(c => c.customerId == item.customerId).Select(x => new Order
+ {
+ Amount = x.oAmnt,
+ OrderNumber = x.oNumber,
+ VAT = x.oVat
+ }).ToList()
+ };
+
+ if (!customerOrderSets.Contains(customerOrderSet))
+ customerOrderSets.Add(customerOrderSet);
+ };
+
+ return customerOrderSets;
+ }
+
+ public bool SaveOrder(NewOrder newOrder)
+ {
+ return _saveOrderRepository.SaveOrder(newOrder);
+ }
+ }
+}
diff --git a/TechTest/AnyCompany/packages.config b/TechTest/AnyCompany/packages.config
new file mode 100644
index 0000000..1c91d8e
--- /dev/null
+++ b/TechTest/AnyCompany/packages.config
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file