diff --git a/RefactorThis.Domain/InvoiceService.cs b/RefactorThis.Domain/InvoiceService.cs index fbd674c..714ebfa 100644 --- a/RefactorThis.Domain/InvoiceService.cs +++ b/RefactorThis.Domain/InvoiceService.cs @@ -4,146 +4,74 @@ namespace RefactorThis.Domain { - public class InvoiceService - { - private readonly InvoiceRepository _invoiceRepository; + public class InvoiceService + { + private readonly InvoiceRepository _invoiceRepository; - public InvoiceService( InvoiceRepository invoiceRepository ) - { - _invoiceRepository = invoiceRepository; - } + public InvoiceService(InvoiceRepository invoiceRepository) + { + _invoiceRepository = invoiceRepository; + } - public string ProcessPayment( Payment payment ) - { - var inv = _invoiceRepository.GetInvoice( payment.Reference ); + public string ProcessPayment(Payment payment) + { + var invoice = _invoiceRepository.GetInvoice(payment.Reference); - var responseMessage = string.Empty; + 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(); + if (invoice == null) + { + throw new InvalidOperationException("There is no invoice matching this payment"); + } + else + { + if (invoice.Amount == 0) + { + if (!invoice.InvoiceHasPayments) + { + 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 (invoice.InvoiceHasPayments) + { + if (invoice.InvoiceIsAlreadyFullyPaid) + { + responseMessage = "invoice was already fully paid"; + } + else if (invoice.IsPaymentsGreaterThanThePartial(payment)) + { + responseMessage = "the payment is greater than the partial amount remaining"; + } + else + { + responseMessage = invoice.PartialPay(payment); - return responseMessage; - } - } + } + } + else + { + if (payment.Amount > invoice.Amount) + { + responseMessage = "the payment is greater than the invoice amount"; + } + else + { + responseMessage = invoice.FullPay(payment); + + } + } + } + } + + invoice.Save(); + + return responseMessage; + } + } } \ No newline at end of file diff --git a/RefactorThis.Persistence/Invoice.cs b/RefactorThis.Persistence/Invoice.cs index bd4370d..6e112fc 100644 --- a/RefactorThis.Persistence/Invoice.cs +++ b/RefactorThis.Persistence/Invoice.cs @@ -1,31 +1,83 @@ +using System; using System.Collections.Generic; +using System.Linq; 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 - } + public class Invoice + { + private readonly decimal _taxPercentage = 0.14m; + 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 bool InvoiceHasPayments { get => Payments != null && Payments.Any(); } + public bool InvoiceIsAlreadyFullyPaid { get => Payments.Sum(x => x.Amount) != 0 && Amount == Payments.Sum(x => x.Amount); } + public bool IsPaymentsGreaterThanThePartial(Payment payment) => Payments.Sum(x => x.Amount) != 0 && payment.Amount > (Amount - AmountPaid); + public string PartialPay(Payment payment) + { + if (!Type.IsInvoiceTypeSupported()) + { + throw new ArgumentOutOfRangeException(); + } + bool isPaymentFinalPartial = (Amount - AmountPaid) == payment.Amount; + + string responseMessage = isPaymentFinalPartial ? "final partial payment received, invoice is now fully paid" : "another partial payment received, still not fully paid"; + + if (Type == InvoiceType.Commercial) + { + TaxAmount += payment.Amount * _taxPercentage; + } + + AmountPaid += payment.Amount; + Payments.Add(payment); + + return responseMessage; + } + + public string FullPay(Payment payment) + { + if (!Type.IsInvoiceTypeSupported()) + { + throw new ArgumentOutOfRangeException(); + } + + bool isFullPayment = Amount == payment.Amount; + string responseMessage = isFullPayment ? "invoice is now fully paid" : "invoice is now partially paid"; + + AmountPaid = payment.Amount; + TaxAmount = payment.Amount * _taxPercentage; + Payments.Add(payment); + + return responseMessage; + } + } + + public enum InvoiceType + { + Standard, + Commercial + } + + public static class InvoiceTypeExtension + { + public static bool IsInvoiceTypeSupported(this InvoiceType invoiceType) + { + return invoiceType == InvoiceType.Standard || invoiceType == InvoiceType.Commercial; + } + } + } \ No newline at end of file