Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 65 additions & 137 deletions RefactorThis.Domain/InvoiceService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
104 changes: 78 additions & 26 deletions RefactorThis.Persistence/Invoice.cs
Original file line number Diff line number Diff line change
@@ -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<Payment> 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<Payment> 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;
}
}

}