diff --git a/.gitignore b/.gitignore index add57be..4843887 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,13 @@ bin/ obj/ /packages/ riderModule.iml -/_ReSharper.Caches/ \ No newline at end of file +/_ReSharper.Caches/ +.vs/ +*.db +*.db-shm +*.db-wal +*.suo +*.user +*.testlog +*.cache +TestResults/ \ No newline at end of file diff --git a/RefactorThis.Domain.Tests/InvoicePaymentProcessorTests.cs b/RefactorThis.Domain.Tests/InvoicePaymentProcessorTests.cs index 3a607fd..4d2a94a 100644 --- a/RefactorThis.Domain.Tests/InvoicePaymentProcessorTests.cs +++ b/RefactorThis.Domain.Tests/InvoicePaymentProcessorTests.cs @@ -1,247 +1,262 @@ -using System; +using Moq; +using RefactorThis.Core.entities; +using RefactorThis.Core.Interfaces; +using System; using System.Collections.Generic; -using NUnit.Framework; -using RefactorThis.Persistence; +using Xunit; + namespace RefactorThis.Domain.Tests { - [TestFixture] - public class InvoicePaymentProcessorTests - { - [Test] - public void ProcessPayment_Should_ThrowException_When_NoInoiceFoundForPaymentReference( ) - { - var repo = new InvoiceRepository( ); - - Invoice invoice = null; - var paymentProcessor = new InvoiceService( repo ); - - var payment = new Payment( ); - var failureMessage = ""; - - try - { - var result = paymentProcessor.ProcessPayment( payment ); - } - catch ( InvalidOperationException e ) - { - failureMessage = e.Message; - } - - Assert.AreEqual( "There is no invoice matching this payment", failureMessage ); - } - - [Test] - public void ProcessPayment_Should_ReturnFailureMessage_When_NoPaymentNeeded( ) - { - var repo = new InvoiceRepository( ); - - var invoice = new Invoice( repo ) - { - Amount = 0, - AmountPaid = 0, - Payments = null - }; - - repo.Add( invoice ); - - var paymentProcessor = new InvoiceService( repo ); - - var payment = new Payment( ); - - var result = paymentProcessor.ProcessPayment( payment ); - - Assert.AreEqual( "no payment needed", result ); - } - - [Test] - public void ProcessPayment_Should_ReturnFailureMessage_When_InvoiceAlreadyFullyPaid( ) - { - var repo = new InvoiceRepository( ); - - var invoice = new Invoice( repo ) - { - Amount = 10, - AmountPaid = 10, - Payments = new List - { - new Payment - { - Amount = 10 - } - } - }; - repo.Add( invoice ); - - var paymentProcessor = new InvoiceService( repo ); - - var payment = new Payment( ); - - var result = paymentProcessor.ProcessPayment( payment ); - - Assert.AreEqual( "invoice was already fully paid", result ); - } - - [Test] - public void ProcessPayment_Should_ReturnFailureMessage_When_PartialPaymentExistsAndAmountPaidExceedsAmountDue( ) - { - var repo = new InvoiceRepository( ); - var invoice = new Invoice( repo ) - { - Amount = 10, - AmountPaid = 5, - Payments = new List - { - new Payment - { - Amount = 5 - } - } - }; - repo.Add( invoice ); - - var paymentProcessor = new InvoiceService( repo ); - - var payment = new Payment( ) - { - Amount = 6 - }; - - var result = paymentProcessor.ProcessPayment( payment ); - - Assert.AreEqual( "the payment is greater than the partial amount remaining", result ); - } - - [Test] - public void ProcessPayment_Should_ReturnFailureMessage_When_NoPartialPaymentExistsAndAmountPaidExceedsInvoiceAmount( ) - { - var repo = new InvoiceRepository( ); - var invoice = new Invoice( repo ) - { - Amount = 5, - AmountPaid = 0, - Payments = new List( ) - }; - repo.Add( invoice ); - - var paymentProcessor = new InvoiceService( repo ); - - var payment = new Payment( ) - { - Amount = 6 - }; - - var result = paymentProcessor.ProcessPayment( payment ); - - Assert.AreEqual( "the payment is greater than the invoice amount", result ); - } - - [Test] - public void ProcessPayment_Should_ReturnFullyPaidMessage_When_PartialPaymentExistsAndAmountPaidEqualsAmountDue( ) - { - var repo = new InvoiceRepository( ); - var invoice = new Invoice( repo ) - { - Amount = 10, - AmountPaid = 5, - Payments = new List - { - new Payment - { - Amount = 5 - } - } - }; - repo.Add( invoice ); - - var paymentProcessor = new InvoiceService( repo ); - - var payment = new Payment( ) - { - Amount = 5 - }; - - var result = paymentProcessor.ProcessPayment( payment ); - - Assert.AreEqual( "final partial payment received, invoice is now fully paid", result ); - } - - [Test] - public void ProcessPayment_Should_ReturnFullyPaidMessage_When_NoPartialPaymentExistsAndAmountPaidEqualsInvoiceAmount( ) - { - var repo = new InvoiceRepository( ); - var invoice = new Invoice( repo ) - { - Amount = 10, - AmountPaid = 0, - Payments = new List( ) { new Payment( ) { Amount = 10 } } - }; - repo.Add( invoice ); - - var paymentProcessor = new InvoiceService( repo ); - - var payment = new Payment( ) - { - Amount = 10 - }; - - var result = paymentProcessor.ProcessPayment( payment ); - - Assert.AreEqual( "invoice was already fully paid", result ); - } - - [Test] - public void ProcessPayment_Should_ReturnPartiallyPaidMessage_When_PartialPaymentExistsAndAmountPaidIsLessThanAmountDue( ) - { - var repo = new InvoiceRepository( ); - var invoice = new Invoice( repo ) - { - Amount = 10, - AmountPaid = 5, - Payments = new List - { - new Payment - { - Amount = 5 - } - } - }; - repo.Add( invoice ); - - var paymentProcessor = new InvoiceService( repo ); - - var payment = new Payment( ) - { - Amount = 1 - }; - - var result = paymentProcessor.ProcessPayment( payment ); - - Assert.AreEqual( "another partial payment received, still not fully paid", result ); - } - - [Test] - public void ProcessPayment_Should_ReturnPartiallyPaidMessage_When_NoPartialPaymentExistsAndAmountPaidIsLessThanInvoiceAmount( ) - { - var repo = new InvoiceRepository( ); - var invoice = new Invoice( repo ) - { - Amount = 10, - AmountPaid = 0, - Payments = new List( ) - }; - repo.Add( invoice ); - - var paymentProcessor = new InvoiceService( repo ); - - var payment = new Payment( ) - { - Amount = 1 - }; - - var result = paymentProcessor.ProcessPayment( payment ); - - Assert.AreEqual( "invoice is now partially paid", result ); - } - } + + public class InvoicePaymentProcessorTests + { + private IInvoiceService _invoiceService; + private void SetUpRepository(Invoice invoice) + { + + var mockInvoiceRepo = new Mock(); + mockInvoiceRepo.Setup(x => x.GetInvoice(It.IsAny())).Returns(invoice); + _invoiceService = new InvoiceService(mockInvoiceRepo.Object); + } + + [Fact] + public void ProcessPayment_Should_ThrowException_When_NoInvoiceFoundForPaymentReference() + { + var payment = new Payment(); + SetUpRepository(null); + + Assert.Throws(typeof(ArgumentNullException), () => _invoiceService.ProcessPayment(payment)); + + } + [Fact] + public void ProcessPayment_Should_ThrowException_When_PaymentReferenceIsNull() + { + var payment = new Payment + { + Amount = 1, + Reference = null + }; + SetUpRepository(null); + Assert.Throws(typeof(ArgumentNullException), () => _invoiceService.ProcessPayment(payment)); + + } + [Fact] + public void ProcessPayment_Should_ThrowException_When_PaymentAmountIsLessThanOrEqualsToZero() + { + + var payment = new Payment + { + Amount = 0, + Reference = "TestRef" + }; + SetUpRepository(null); + + Assert.Throws(typeof(InvalidOperationException), () => _invoiceService.ProcessPayment(payment)); + + } + + [Fact] + public void ProcessPayment_Should_ReturnFailureMessage_When_NoPaymentNeeded() + { + + var invoice = new Invoice() + { + Amount = 0, + AmountPaid = 0, + Payments = null + }; + var payment = new Payment + { + Amount = 100, + Reference = "TestRef" + }; + + SetUpRepository(invoice); + + var result = _invoiceService.ProcessPayment(payment); + + Assert.Equal("no payment needed", result); + } + + [Fact] + public void ProcessPayment_Should_ReturnFailureMessage_When_InvoiceAlreadyFullyPaid() + { + var invoice = new Invoice() + { + Amount = 10, + AmountPaid = 10, + Payments = new List + { + new Payment + { + Amount = 10 + } + } + }; + + var payment = new Payment + { + Amount = 100, + Reference = "TestRef" + }; + + SetUpRepository(invoice); + var result = _invoiceService.ProcessPayment(payment); + + Assert.Equal("invoice was already fully paid", result); + } + + [Fact] + public void ProcessPayment_Should_ReturnFailureMessage_When_PartialPaymentExistsAndAmountPaidExceedsAmountDue() + { + + var invoice = new Invoice() + { + Amount = 10, + AmountPaid = 5, + Payments = new List + { + new Payment + { + Amount = 5 + } + } + }; + + var payment = new Payment + { + Amount = 6, + Reference = "TestRef" + }; + + SetUpRepository(invoice); + var result = _invoiceService.ProcessPayment(payment); + + Assert.Equal("the payment is greater than the partial amount remaining", result); + } + + [Fact] + public void ProcessPayment_Should_ReturnFailureMessage_When_NoPartialPaymentExistsAndAmountPaidExceedsInvoiceAmount() + { + + var invoice = new Invoice() + { + Amount = 5, + AmountPaid = 0, + Payments = new List() + }; + var payment = new Payment + { + Amount = 6, + Reference = "TestRef" + }; + + SetUpRepository(invoice); + var result = _invoiceService.ProcessPayment(payment); + + Assert.Equal("the payment is greater than the invoice amount", result); + } + + [Fact] + public void ProcessPayment_Should_ReturnFullyPaidMessage_When_PartialPaymentExistsAndAmountPaidEqualsAmountDue() + { + + var invoice = new Invoice() + { + Amount = 10, + AmountPaid = 5, + Payments = new List + { + new Payment + { + Amount = 5 + } + } + }; + var payment = new Payment() + { + Amount = 5, + Reference = "TestRef" + }; + + SetUpRepository(invoice); + var result = _invoiceService.ProcessPayment(payment); + + Assert.Equal("final partial payment received, invoice is now fully paid", result); + } + + [Fact] + public void ProcessPayment_Should_ReturnFullyPaidMessage_When_NoPartialPaymentExistsAndAmountPaidEqualsInvoiceAmount() + { + + var invoice = new Invoice() + { + Amount = 10, + AmountPaid = 0, + Payments = new List() { new Payment() { Amount = 10 } } + }; + var payment = new Payment() + { + Amount = 10, + Reference = "TestRef" + }; + + SetUpRepository(invoice); + var result = _invoiceService.ProcessPayment(payment); + + Assert.Equal("invoice was already fully paid", result); + } + + [Fact] + public void ProcessPayment_Should_ReturnPartiallyPaidMessage_When_PartialPaymentExistsAndAmountPaidIsLessThanAmountDue() + { + + var invoice = new Invoice() + { + Amount = 10, + AmountPaid = 5, + Payments = new List + { + new Payment + { + Amount = 5 + } + } + }; + var payment = new Payment() + { + Amount = 1, + Reference = "TestRef" + }; + + SetUpRepository(invoice); + var result = _invoiceService.ProcessPayment(payment); + + Assert.Equal("another partial payment received, still not fully paid", result); + } + + [Fact] + public void ProcessPayment_Should_ReturnPartiallyPaidMessage_When_NoPartialPaymentExistsAndAmountPaidIsLessThanInvoiceAmount() + { + + var invoice = new Invoice() + { + Amount = 10, + AmountPaid = 0, + Payments = new List() + }; + + var payment = new Payment() + { + Amount = 1, + Reference = "TestRef" + }; + + SetUpRepository(invoice); + var result = _invoiceService.ProcessPayment(payment); + + Assert.Equal("invoice is now partially paid", result); + } + } } \ No newline at end of file diff --git a/RefactorThis.Domain.Tests/RefactorThis.Domain.Tests.csproj b/RefactorThis.Domain.Tests/RefactorThis.Domain.Tests.csproj deleted file mode 100644 index f118007..0000000 --- a/RefactorThis.Domain.Tests/RefactorThis.Domain.Tests.csproj +++ /dev/null @@ -1,67 +0,0 @@ - - - - - Debug - AnyCPU - {7971BDEC-EAD1-4FB8-A4F5-B1F67E4F6355} - {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - Properties - RefactorThis.Domain.Tests - RefactorThis.Domain.Tests - v4.7.2 - 512 - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - ..\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll - - - - - - - - - {5310b2fe-e26d-414e-b656-1f74c5a70368} - RefactorThis.Domain - - - {33cdc796-ff75-449c-9637-59c2efc46361} - RefactorThis.Persistence - - - - - - diff --git a/RefactorThis.Domain.Tests/RefactorThis.Tests.csproj b/RefactorThis.Domain.Tests/RefactorThis.Tests.csproj new file mode 100644 index 0000000..daca301 --- /dev/null +++ b/RefactorThis.Domain.Tests/RefactorThis.Tests.csproj @@ -0,0 +1,121 @@ + + + + + + + + + Debug + AnyCPU + {7971BDEC-EAD1-4FB8-A4F5-B1F67E4F6355} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + RefactorThis.Domain.Tests + RefactorThis.Domain.Tests + v4.7.2 + 512 + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll + + + ..\packages\Microsoft.CodeCoverage.17.8.0\lib\net462\Microsoft.VisualStudio.CodeCoverage.Shim.dll + + + ..\packages\Moq.4.16.1\lib\net45\Moq.dll + + + + + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + + ..\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll + + + ..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll + + + ..\packages\xunit.assert.2.4.1\lib\netstandard1.1\xunit.assert.dll + + + ..\packages\xunit.extensibility.core.2.4.1\lib\net452\xunit.core.dll + + + ..\packages\xunit.extensibility.execution.2.4.1\lib\net452\xunit.execution.desktop.dll + + + + + + + + + {5310b2fe-e26d-414e-b656-1f74c5a70368} + RefactorThis.Application + + + {50F3F93C-6688-4B4B-8B30-3BDF6FA4485F} + RefactorThis.Core + + + + + + + + + + + + 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/RefactorThis.Domain.Tests/packages.config b/RefactorThis.Domain.Tests/packages.config index c108d44..e8d92b6 100644 --- a/RefactorThis.Domain.Tests/packages.config +++ b/RefactorThis.Domain.Tests/packages.config @@ -1,4 +1,18 @@  + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RefactorThis.Domain/Interface/IInvoiceService.cs b/RefactorThis.Domain/Interface/IInvoiceService.cs new file mode 100644 index 0000000..a900d5c --- /dev/null +++ b/RefactorThis.Domain/Interface/IInvoiceService.cs @@ -0,0 +1,14 @@ +using RefactorThis.Core.entities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RefactorThis.Domain +{ + public interface IInvoiceService + { + string ProcessPayment(Payment payment); + } +} diff --git a/RefactorThis.Domain/InvoiceService.cs b/RefactorThis.Domain/InvoiceService.cs deleted file mode 100644 index fbd674c..0000000 --- a/RefactorThis.Domain/InvoiceService.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using System.Linq; -using RefactorThis.Persistence; - -namespace RefactorThis.Domain -{ - public class InvoiceService - { - private readonly InvoiceRepository _invoiceRepository; - - public InvoiceService( InvoiceRepository invoiceRepository ) - { - _invoiceRepository = invoiceRepository; - } - - public string ProcessPayment( Payment payment ) - { - var inv = _invoiceRepository.GetInvoice( payment.Reference ); - - var responseMessage = string.Empty; - - if ( inv == null ) - { - throw new InvalidOperationException( "There is no invoice matching this payment" ); - } - else - { - if ( inv.Amount == 0 ) - { - if ( inv.Payments == null || !inv.Payments.Any( ) ) - { - responseMessage = "no payment needed"; - } - else - { - throw new InvalidOperationException( "The invoice is in an invalid state, it has an amount of 0 and it has payments." ); - } - } - else - { - if ( inv.Payments != null && inv.Payments.Any( ) ) - { - if ( inv.Payments.Sum( x => x.Amount ) != 0 && inv.Amount == inv.Payments.Sum( x => x.Amount ) ) - { - responseMessage = "invoice was already fully paid"; - } - else if ( inv.Payments.Sum( x => x.Amount ) != 0 && payment.Amount > ( inv.Amount - inv.AmountPaid ) ) - { - responseMessage = "the payment is greater than the partial amount remaining"; - } - else - { - if ( ( inv.Amount - inv.AmountPaid ) == payment.Amount ) - { - switch ( inv.Type ) - { - case InvoiceType.Standard: - inv.AmountPaid += payment.Amount; - inv.Payments.Add( payment ); - responseMessage = "final partial payment received, invoice is now fully paid"; - break; - case InvoiceType.Commercial: - inv.AmountPaid += payment.Amount; - inv.TaxAmount += payment.Amount * 0.14m; - inv.Payments.Add( payment ); - responseMessage = "final partial payment received, invoice is now fully paid"; - break; - default: - throw new ArgumentOutOfRangeException( ); - } - - } - else - { - switch ( inv.Type ) - { - case InvoiceType.Standard: - inv.AmountPaid += payment.Amount; - inv.Payments.Add( payment ); - responseMessage = "another partial payment received, still not fully paid"; - break; - case InvoiceType.Commercial: - inv.AmountPaid += payment.Amount; - inv.TaxAmount += payment.Amount * 0.14m; - inv.Payments.Add( payment ); - responseMessage = "another partial payment received, still not fully paid"; - break; - default: - throw new ArgumentOutOfRangeException( ); - } - } - } - } - else - { - if ( payment.Amount > inv.Amount ) - { - responseMessage = "the payment is greater than the invoice amount"; - } - else if ( inv.Amount == payment.Amount ) - { - switch ( inv.Type ) - { - case InvoiceType.Standard: - inv.AmountPaid = payment.Amount; - inv.TaxAmount = payment.Amount * 0.14m; - inv.Payments.Add( payment ); - responseMessage = "invoice is now fully paid"; - break; - case InvoiceType.Commercial: - inv.AmountPaid = payment.Amount; - inv.TaxAmount = payment.Amount * 0.14m; - inv.Payments.Add( payment ); - responseMessage = "invoice is now fully paid"; - break; - default: - throw new ArgumentOutOfRangeException( ); - } - } - else - { - switch ( inv.Type ) - { - case InvoiceType.Standard: - inv.AmountPaid = payment.Amount; - inv.TaxAmount = payment.Amount * 0.14m; - inv.Payments.Add( payment ); - responseMessage = "invoice is now partially paid"; - break; - case InvoiceType.Commercial: - inv.AmountPaid = payment.Amount; - inv.TaxAmount = payment.Amount * 0.14m; - inv.Payments.Add( payment ); - responseMessage = "invoice is now partially paid"; - break; - default: - throw new ArgumentOutOfRangeException( ); - } - } - } - } - } - - inv.Save(); - - return responseMessage; - } - } -} \ No newline at end of file diff --git a/RefactorThis.Domain/RefactorThis.Application.csproj b/RefactorThis.Domain/RefactorThis.Application.csproj new file mode 100644 index 0000000..e20fe84 --- /dev/null +++ b/RefactorThis.Domain/RefactorThis.Application.csproj @@ -0,0 +1,59 @@ + + + + + Debug + AnyCPU + {5310B2FE-E26D-414E-B656-1F74C5A70368} + Library + Properties + RefactorThis.Domain + RefactorThis.Domain + v4.7.2 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + {50F3F93C-6688-4B4B-8B30-3BDF6FA4485F} + RefactorThis.Core + + + + + \ No newline at end of file diff --git a/RefactorThis.Domain/RefactorThis.Domain.csproj b/RefactorThis.Domain/RefactorThis.Domain.csproj deleted file mode 100644 index 753e893..0000000 --- a/RefactorThis.Domain/RefactorThis.Domain.csproj +++ /dev/null @@ -1,59 +0,0 @@ - - - - - Debug - AnyCPU - {5310B2FE-E26D-414E-B656-1F74C5A70368} - Library - Properties - RefactorThis.Domain - RefactorThis.Domain - v4.7.2 - 512 - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - {33cdc796-ff75-449c-9637-59c2efc46361} - RefactorThis.Persistence - - - - - - diff --git a/RefactorThis.Domain/Service/InvoiceService.cs b/RefactorThis.Domain/Service/InvoiceService.cs new file mode 100644 index 0000000..9f028d9 --- /dev/null +++ b/RefactorThis.Domain/Service/InvoiceService.cs @@ -0,0 +1,132 @@ +using RefactorThis.Core.entities; +using RefactorThis.Core.enums; +using RefactorThis.Core.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace RefactorThis.Domain +{ + public class InvoiceService : IInvoiceService + { + private readonly IInvoiceRepository _invoiceRepository; + + public InvoiceService(IInvoiceRepository invoiceRepository) + { + _invoiceRepository = invoiceRepository; + } + + public string ProcessPayment(Payment payment) + { + if (payment == null) + { + throw new ArgumentNullException("Payment should not be null"); + } + if (payment.Reference == null) + { + throw new ArgumentNullException("Payment reference should not be null"); + } + if(payment.Amount < 0) + { + throw new InvalidOperationException("Payment amount should be a positive value"); + } + + var inv = _invoiceRepository.GetInvoice(payment.Reference); + + if (inv == null) + { + throw new InvalidOperationException("There is no invoice matching this payment"); + } + if (inv.Amount == 0) + { + if (IsPaymentListEmpty(inv.Payments)) + { + return "no payment needed"; + } + else + { + throw new InvalidOperationException("The invoice is in an invalid state, it has an amount of 0 and it has payments."); + } + } + + return HasExistingPayments(inv) ? ProcessExistingPayments(inv, payment) : ProcessInitialPayment(inv, payment); + + + + } + + private string ProcessExistingPayments(Invoice inv, Payment payment) + { + decimal totalPayments = inv.Payments.Sum(p => p.Amount); + decimal remainingBalance = inv.Amount - inv.AmountPaid; + + + if (inv.Amount == totalPayments) + + return "invoice was already fully paid"; + + if (payment.Amount > remainingBalance) + + return "the payment is greater than the partial amount remaining"; + + ApplyPayment(inv, payment,false); + + return remainingBalance == payment.Amount ? "final partial payment received, invoice is now fully paid" + : "another partial payment received, still not fully paid"; + + + } + + private string ProcessInitialPayment(Invoice inv, Payment payment) + { + if (payment.Amount > inv.Amount) + return "the payment is greater than the invoice amount"; + + ApplyPayment(inv, payment,true); + return inv.Amount == payment.Amount ? "invoice is now fully paid" : "invoice is now partially paid"; + + } + + private void ApplyPayment(Invoice inv, Payment payment,bool isInitial) + { + if(inv.Payments == null) + { + inv.Payments = new List(); + } + + // Logic of orginal code + // if "HasExistingPayments = true" and a payment has been made + // for standard tax amount will not increment/change + // for commercial tax amount will increment by 14% of the payment amount + // if Initial Payment has been made + // given that initial value of amountpain and taxamount is defaulted to 0 + // we can use the += operator for both amount paid and taxamount(on commercial type) to set/increment the values accordingly + + + switch (inv.Type) + { + case InvoiceType.Standard: + inv.AmountPaid += payment.Amount; + inv.TaxAmount = isInitial ? payment.Amount * 0.14m : inv.TaxAmount; + inv.Payments.Add(payment); + break; + case InvoiceType.Commercial: + inv.AmountPaid += payment.Amount; + inv.TaxAmount += payment.Amount * 0.14m; + inv.Payments.Add(payment); + break; + default: + throw new ArgumentOutOfRangeException(); + } + _invoiceRepository.SaveInvoice(inv); + } + + private bool HasExistingPayments(Invoice inv) + { + return inv.Payments != null && inv.Payments.Any(); + } + private bool IsPaymentListEmpty(List payments) => + payments == null || !payments.Any(); + } + +} \ No newline at end of file diff --git a/RefactorThis.Infrastructure/DependencyInjection.cs b/RefactorThis.Infrastructure/DependencyInjection.cs new file mode 100644 index 0000000..8ca5829 --- /dev/null +++ b/RefactorThis.Infrastructure/DependencyInjection.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.DependencyInjection; +using RefactorThis.Core.Interfaces; +using RefactorThis.Persistence; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RefactorThis.Infrastructure +{ + public static class DependencyInjection + { + public static IServiceCollection AddInfrastructureDI(this IServiceCollection services) + { + services.AddScoped(); + return services; + } + } +} diff --git a/RefactorThis.Infrastructure/RefactorThis.Infrastructure.csproj b/RefactorThis.Infrastructure/RefactorThis.Infrastructure.csproj new file mode 100644 index 0000000..9cffd0f --- /dev/null +++ b/RefactorThis.Infrastructure/RefactorThis.Infrastructure.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.0 + + + + + + + + + + + diff --git a/RefactorThis.Persistence/InvoiceRepository.cs b/RefactorThis.Infrastructure/Repositories/InvoiceRepository.cs similarity index 57% rename from RefactorThis.Persistence/InvoiceRepository.cs rename to RefactorThis.Infrastructure/Repositories/InvoiceRepository.cs index 38548c7..7503131 100644 --- a/RefactorThis.Persistence/InvoiceRepository.cs +++ b/RefactorThis.Infrastructure/Repositories/InvoiceRepository.cs @@ -1,11 +1,14 @@ +using RefactorThis.Core.entities; +using RefactorThis.Core.Interfaces; + namespace RefactorThis.Persistence { - public class InvoiceRepository - { - private Invoice _invoice; + public class InvoiceRepository : IInvoiceRepository + { + private Invoice _invoice = new Invoice(); public Invoice GetInvoice( string reference ) { - return _invoice; + return _invoice; } public void SaveInvoice( Invoice invoice ) diff --git a/RefactorThis.Persistence/Entities/Invoice.cs b/RefactorThis.Persistence/Entities/Invoice.cs new file mode 100644 index 0000000..60920d2 --- /dev/null +++ b/RefactorThis.Persistence/Entities/Invoice.cs @@ -0,0 +1,15 @@ +using RefactorThis.Core.enums; +using System.Collections.Generic; + +namespace RefactorThis.Core.entities +{ + public class Invoice + { + public decimal Amount { get; set; } + public decimal AmountPaid { get; set; } + public decimal TaxAmount { get; set; } + public List Payments { get; set; } + public InvoiceType Type { get; set; } + } + +} \ No newline at end of file diff --git a/RefactorThis.Persistence/Entities/Payment.cs b/RefactorThis.Persistence/Entities/Payment.cs new file mode 100644 index 0000000..90458bd --- /dev/null +++ b/RefactorThis.Persistence/Entities/Payment.cs @@ -0,0 +1,8 @@ +namespace RefactorThis.Core.entities +{ + public class Payment + { + public decimal Amount { get; set; } + public string Reference { get; set; } + } +} \ No newline at end of file diff --git a/RefactorThis.Persistence/Enums/InvoiceType.cs b/RefactorThis.Persistence/Enums/InvoiceType.cs new file mode 100644 index 0000000..bf7f012 --- /dev/null +++ b/RefactorThis.Persistence/Enums/InvoiceType.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RefactorThis.Core.enums +{ + + public enum InvoiceType + { + Standard, + Commercial + } + +} diff --git a/RefactorThis.Persistence/Interface/IInvoiceRepository.cs b/RefactorThis.Persistence/Interface/IInvoiceRepository.cs new file mode 100644 index 0000000..8ebd83e --- /dev/null +++ b/RefactorThis.Persistence/Interface/IInvoiceRepository.cs @@ -0,0 +1,16 @@ +using RefactorThis.Core.entities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RefactorThis.Core.Interfaces +{ + public interface IInvoiceRepository + { + Invoice GetInvoice(string reference); + void SaveInvoice(Invoice invoice); + void Add(Invoice invoice); + } +} diff --git a/RefactorThis.Persistence/Invoice.cs b/RefactorThis.Persistence/Invoice.cs deleted file mode 100644 index bd4370d..0000000 --- a/RefactorThis.Persistence/Invoice.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections.Generic; - -namespace RefactorThis.Persistence -{ - public class Invoice - { - private readonly InvoiceRepository _repository; - public Invoice( InvoiceRepository repository ) - { - _repository = repository; - } - - public void Save( ) - { - _repository.SaveInvoice( this ); - } - - public decimal Amount { get; set; } - public decimal AmountPaid { get; set; } - public decimal TaxAmount { get; set; } - public List Payments { get; set; } - - public InvoiceType Type { get; set; } - } - - public enum InvoiceType - { - Standard, - Commercial - } -} \ No newline at end of file diff --git a/RefactorThis.Persistence/Payment.cs b/RefactorThis.Persistence/Payment.cs deleted file mode 100644 index db29372..0000000 --- a/RefactorThis.Persistence/Payment.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace RefactorThis.Persistence -{ - public class Payment - { - public decimal Amount { get; set; } - public string Reference { get; set; } - } -} \ No newline at end of file diff --git a/RefactorThis.Persistence/RefactorThis.Persistence.csproj b/RefactorThis.Persistence/RefactorThis.Core.csproj similarity index 100% rename from RefactorThis.Persistence/RefactorThis.Persistence.csproj rename to RefactorThis.Persistence/RefactorThis.Core.csproj diff --git a/RefactorThis.sln b/RefactorThis.sln index e235699..55bf5f6 100644 --- a/RefactorThis.sln +++ b/RefactorThis.sln @@ -1,10 +1,15 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RefactorThis.Domain", "RefactorThis.Domain\RefactorThis.Domain.csproj", "{5310B2FE-E26D-414E-B656-1F74C5A70368}" +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35527.113 d17.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RefactorThis.Application", "RefactorThis.Domain\RefactorThis.Application.csproj", "{5310B2FE-E26D-414E-B656-1F74C5A70368}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RefactorThis.Domain.Tests", "RefactorThis.Domain.Tests\RefactorThis.Domain.Tests.csproj", "{7971BDEC-EAD1-4FB8-A4F5-B1F67E4F6355}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RefactorThis.Tests", "RefactorThis.Domain.Tests\RefactorThis.Tests.csproj", "{7971BDEC-EAD1-4FB8-A4F5-B1F67E4F6355}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RefactorThis.Persistence", "RefactorThis.Persistence\RefactorThis.Persistence.csproj", "{50F3F93C-6688-4B4B-8B30-3BDF6FA4485F}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RefactorThis.Core", "RefactorThis.Persistence\RefactorThis.Core.csproj", "{50F3F93C-6688-4B4B-8B30-3BDF6FA4485F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RefactorThis.Infrastructure", "RefactorThis.Infrastructure\RefactorThis.Infrastructure.csproj", "{DF8D9EAE-49B4-4BF1-8127-F5DEF5A4CDD7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -24,7 +29,12 @@ Global {50F3F93C-6688-4B4B-8B30-3BDF6FA4485F}.Debug|Any CPU.Build.0 = Debug|Any CPU {50F3F93C-6688-4B4B-8B30-3BDF6FA4485F}.Release|Any CPU.ActiveCfg = Release|Any CPU {50F3F93C-6688-4B4B-8B30-3BDF6FA4485F}.Release|Any CPU.Build.0 = Release|Any CPU + {DF8D9EAE-49B4-4BF1-8127-F5DEF5A4CDD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DF8D9EAE-49B4-4BF1-8127-F5DEF5A4CDD7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DF8D9EAE-49B4-4BF1-8127-F5DEF5A4CDD7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DF8D9EAE-49B4-4BF1-8127-F5DEF5A4CDD7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection - GlobalSection(NestedProjects) = preSolution + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection EndGlobal