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