diff --git a/README.md b/README.md
index cd01e89..bb3721e 100644
--- a/README.md
+++ b/README.md
@@ -24,3 +24,93 @@ The overall objective is to refactor the code and keep the tests passing. There
+### Code refactoring improvements
+* Validation Separation: Moved validation logic to dedicated InvoiceValidator
+* Process Decomposition: Split payment processing into discrete, focused methods
+* Interface Contracts: Established clear interfaces for all dependencies
+* Method Simplification: Broke down monolithic ProcessPayment into single-responsibility methods
+* Control Flow: Eliminated nested conditionals for linear readability
+* Error Handling: Implemented structured exception handling with code safety
+* Added logging for issues investigation
+
+* The string return type in ProcessPayment is problematic as it forces client to parse unstructured messages;
+* a strongly-typed response object would provide clearer contracts and better programmability.
+
+
+* Client side, before:
+
+// Returns unstructured string messages
+
+ string result = _invoiceService.ProcessPayment(payment);
+
+// Client must parse strings to determine outcome. How to do that efficiently?
+
+* Client side, after:
+
+ PaymentResult result = _invoiceService.ProcessPayment(payment);
+
+ if (result.IsSuccess)
+ {
+ switch (result.Code)
+ {
+ case ResultCode.FinalPaymentComplete:
+ _receiptService.Generate(invoice, result.AmountPaid);
+ _auditService.LogPaymentComplete(result.TransactionId);
+ break;
+
+ case ResultCode.PartialPaymentComplete:
+ _paymentTracker.ScheduleFollowUp(
+ result.RemainingAmount,
+ DateTime.Now.AddDays(7));
+ break;
+
+ case ResultCode.NoPaymentNeeded:
+ case ResultCode.AlreadyFullyPaid:
+ // Handle these cases as needed
+ break;
+ }
+ }
+ else
+ {
+ // Handle failure scenarios
+ switch (result.Code)
+ {
+ case ResultCode.InvoiceNotFound:
+ _alertService.TriggerSupportAlert(result);
+ break;
+
+ case ResultCode.PaymentExceedsRemainingAmount:
+ case ResultCode.PaymentExceedsInvoiceAmount:
+ // Handle these cases as needed
+ break;
+
+ case ResultCode.ProcessingError:
+ case ResultCode.InvalidInvoiceState:
+ // Handle these cases as needed
+ break;
+
+ default:
+ _alertService.TriggerSupportAlert(result);
+ break;
+ }
+ }
+
+*** Architectural improvements
+* Proper layering with domain entities, services, and persistence
+* Dependency injection for better testability
+* Clear boundaries between components
+* Each class has a single responsibility, easier to modify or extend behavior. Clear separation makes it easier to add new features.
+
+
+*** Suggested Business Object Enhancements (not implemented):
+
+
+* Invoice/Payment Data Enrichment
+* Currently missing critical transaction details: Payer/recipient identification (names, contact info)
+* Banking/payment details
+* Transaction references
+
+
+
+
+
diff --git a/RefactorThis.Domain.Tests/App.config b/RefactorThis.Domain.Tests/App.config
new file mode 100644
index 0000000..5367091
--- /dev/null
+++ b/RefactorThis.Domain.Tests/App.config
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RefactorThis.Domain.Tests/InvoicePaymentProcessorTests.cs b/RefactorThis.Domain.Tests/InvoicePaymentProcessorTests.cs
index 3a607fd..4d68065 100644
--- a/RefactorThis.Domain.Tests/InvoicePaymentProcessorTests.cs
+++ b/RefactorThis.Domain.Tests/InvoicePaymentProcessorTests.cs
@@ -1,247 +1,191 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using NUnit.Framework;
-using RefactorThis.Persistence;
+using RefactorThis.Domain.Loggers;
+using RefactorThis.Domain.Models;
+using RefactorThis.Domain.Services;
+using RefactorThis.Domain.Tests.Mocks;
+using RefactorThis.Domain.Validators;
+using RefactorThis.Persistence.Entities;
+using RefactorThis.Persistence.Repositories;
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 );
- }
- }
+ [TestFixture]
+ public class InvoicePaymentProcessorTests
+ {
+ private IInvoiceService _invoiceService;
+ private IInvoiceRepository _invoiceRepository;
+ private IInvoiceValidator _invoiceValidator;
+ private IAppLogger _logger;
+
+ [SetUp]
+ public void BeforeEachTest()
+ {
+ _invoiceRepository = new MockInvoiceRepository();
+ _invoiceValidator = new InvoiceValidator();
+ _logger = new AppLogger();
+ _invoiceService = new InvoiceService(_invoiceRepository, _invoiceValidator, _logger);
+ }
+
+ [Test]
+ public void ProcessPayment_Should_ReturnFailure_When_NoInvoiceFoundForPaymentReference()
+ {
+ var payment = new Payment();
+ var result = _invoiceService.ProcessPayment(payment);
+
+ Assert.IsFalse(result.IsSuccess);
+ Assert.AreEqual(ResultCode.InvoiceNotFound, result.Code);
+ Assert.AreEqual("There is no invoice matching this payment", result.Message);
+ }
+
+ [Test]
+ public void ProcessPayment_Should_ReturnSuccess_When_NoPaymentNeeded()
+ {
+ var invoice = new Invoice { Amount = 0, Payments = null };
+ _invoiceRepository.Add(invoice);
+
+ var payment = new Payment();
+ var result = _invoiceService.ProcessPayment(payment);
+
+ Assert.IsTrue(result.IsSuccess);
+ Assert.AreEqual(ResultCode.NoPaymentNeeded, result.Code);
+ Assert.AreEqual("no payment needed", result.Message);
+ }
+
+ [Test]
+ public void ProcessPayment_Should_ReturnSuccess_When_InvoiceAlreadyFullyPaid()
+ {
+ var invoice = new Invoice
+ {
+ Amount = 10,
+ Payments = new List { new Payment { Amount = 10 } }
+ };
+ _invoiceRepository.Add(invoice);
+
+ var payment = new Payment();
+
+ var result = _invoiceService.ProcessPayment(payment);
+
+ Assert.IsTrue(result.IsSuccess);
+ Assert.AreEqual(ResultCode.AlreadyFullyPaid, result.Code);
+ Assert.AreEqual("invoice was already fully paid", result.Message);
+ }
+
+ [Test]
+ public void ProcessPayment_Should_ReturnFailure_When_PartialPaymentExistsAndAmountPaidExceedsAmountDue()
+ {
+ // Arrange
+ var invoice = new Invoice
+ {
+ Amount = 10,
+ Payments = new List { new Payment { Amount = 5 } }
+ };
+ _invoiceRepository.Add(invoice);
+
+ var payment = new Payment { Amount = 6 };
+
+ var result = _invoiceService.ProcessPayment(payment);
+
+ Assert.IsFalse(result.IsSuccess);
+ Assert.AreEqual(ResultCode.PaymentExceedsRemainingAmount, result.Code);
+ Assert.AreEqual("the payment is greater than the partial amount remaining", result.Message);
+ }
+
+ [Test]
+ public void ProcessPayment_Should_ReturnFailure_When_NoPartialPaymentExistsAndAmountPaidExceedsInvoiceAmount()
+ {
+ // Arrange
+ var invoice = new Invoice { Amount = 5, Payments = new List() };
+ _invoiceRepository.Add(invoice);
+ var payment = new Payment { Amount = 6 };
+
+ // Act
+ var result = _invoiceService.ProcessPayment(payment);
+
+ // Assert
+ Assert.IsFalse(result.IsSuccess);
+ Assert.AreEqual(ResultCode.PaymentExceedsInvoiceAmount, result.Code);
+ Assert.AreEqual("the payment is greater than the invoice amount", result.Message);
+ }
+
+ [Test]
+ public void ProcessPayment_Should_ReturnSuccess_When_PartialPaymentExistsAndAmountPaidEqualsAmountDue()
+ {
+ // Arrange
+ var invoice = new Invoice
+ {
+ Amount = 10,
+ Payments = new List { new Payment { Amount = 5 } }
+ };
+ _invoiceRepository.Add(invoice);
+ var payment = new Payment { Amount = 5 };
+
+ // Act
+ var result = _invoiceService.ProcessPayment(payment);
+
+ // Assert
+ Assert.IsTrue(result.IsSuccess);
+ Assert.AreEqual(ResultCode.FinalPaymentComplete, result.Code);
+ Assert.AreEqual("final partial payment received, invoice is now fully paid", result.Message);
+ }
+
+ [Test]
+ public void ProcessPayment_Should_ReturnSuccess_When_PartialPaymentExistsAndAmountPaidIsLessThanAmountDue()
+ {
+ // Arrange
+ var invoice = new Invoice
+ {
+ Amount = 10,
+ Payments = new List { new Payment { Amount = 5 } }
+ };
+ _invoiceRepository.Add(invoice);
+ var payment = new Payment { Amount = 1 };
+
+ // Act
+ var result = _invoiceService.ProcessPayment(payment);
+
+ // Assert
+ Assert.IsTrue(result.IsSuccess);
+ Assert.AreEqual(ResultCode.PartialPaymentComplete, result.Code);
+ Assert.AreEqual("partial payment received, invoice is still not fully paid", result.Message);
+ }
+
+ [Test]
+ public void ProcessPayment_Should_ReturnSuccess_When_NoPartialPaymentExistsAndAmountPaidIsLessThanInvoiceAmount()
+ {
+ // Arrange
+ var invoice = new Invoice { Amount = 10, Payments = new List() };
+ _invoiceRepository.Add(invoice);
+ var payment = new Payment { Amount = 1 };
+
+ // Act
+ var result = _invoiceService.ProcessPayment(payment);
+
+ // Assert
+ Assert.IsTrue(result.IsSuccess);
+ Assert.AreEqual(ResultCode.PartialPaymentComplete, result.Code);
+ Assert.AreEqual("invoice is now partially paid", result.Message);
+ }
+
+ [Test]
+ public void ProcessPayment_Should_CalculateTax_When_CommercialInvoice()
+ {
+ // Arrange
+ var invoice = new Invoice
+ {
+ Amount = 10,
+ Payments = new List(),
+ Type = InvoiceType.Commercial
+ };
+ _invoiceRepository.Add(invoice);
+ var payment = new Payment { Amount = 10 };
+
+ // Act
+ var result = _invoiceService.ProcessPayment(payment);
+
+ // Assert
+ Assert.AreEqual(1.4m, invoice.TaxAmount);
+ Assert.IsTrue(result.IsSuccess);
+ }
+ }
}
\ No newline at end of file
diff --git a/RefactorThis.Domain.Tests/Mocks/MockInvoiceRepository.cs b/RefactorThis.Domain.Tests/Mocks/MockInvoiceRepository.cs
new file mode 100644
index 0000000..be55f70
--- /dev/null
+++ b/RefactorThis.Domain.Tests/Mocks/MockInvoiceRepository.cs
@@ -0,0 +1,25 @@
+using RefactorThis.Persistence.Entities;
+using RefactorThis.Persistence.Repositories;
+
+namespace RefactorThis.Domain.Tests.Mocks
+{
+ public class MockInvoiceRepository : IInvoiceRepository
+ {
+ private Invoice _invoice;
+
+ public Invoice GetInvoice(string reference)
+ {
+ return _invoice;
+ }
+
+ public void SaveInvoice(Invoice invoice)
+ {
+ // In memory implementation for testing
+ }
+
+ public void Add(Invoice invoice)
+ {
+ _invoice = invoice;
+ }
+ }
+}
\ No newline at end of file
diff --git a/RefactorThis.Domain.Tests/RefactorThis.Domain.Tests.csproj b/RefactorThis.Domain.Tests/RefactorThis.Domain.Tests.csproj
index f118007..935774c 100644
--- a/RefactorThis.Domain.Tests/RefactorThis.Domain.Tests.csproj
+++ b/RefactorThis.Domain.Tests/RefactorThis.Domain.Tests.csproj
@@ -43,6 +43,7 @@
+
diff --git a/RefactorThis.Domain.Tests/packages.config b/RefactorThis.Domain.Tests/packages.config
index c108d44..55738bc 100644
--- a/RefactorThis.Domain.Tests/packages.config
+++ b/RefactorThis.Domain.Tests/packages.config
@@ -1,4 +1,11 @@
-
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RefactorThis.Domain/Exceptions/InvoiceValidationException.cs b/RefactorThis.Domain/Exceptions/InvoiceValidationException.cs
new file mode 100644
index 0000000..d29387e
--- /dev/null
+++ b/RefactorThis.Domain/Exceptions/InvoiceValidationException.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace RefactorThis.Domain.Exceptions
+{
+ public class InvoiceValidationException : Exception
+ {
+ public InvoiceValidationException(string message)
+ : base(message)
+ {}
+
+ public InvoiceValidationException(string message, Exception innerException)
+ : base(message, innerException)
+ {}
+ }
+}
\ No newline at end of file
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/Loggers/AppLoggger.cs b/RefactorThis.Domain/Loggers/AppLoggger.cs
new file mode 100644
index 0000000..f188546
--- /dev/null
+++ b/RefactorThis.Domain/Loggers/AppLoggger.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace RefactorThis.Domain.Loggers
+{
+ public class AppLogger : IAppLogger
+ {
+ private readonly string _typeName = typeof(T).Name;
+
+ public void LogInformation(string message, params object[] args)
+ {
+ Console.WriteLine($"[INFO] [{_typeName}] {string.Format(message, args)}");
+ }
+
+ public void LogWarning(string message, params object[] args)
+ {
+ Console.WriteLine($"[WARN] [{_typeName}] {string.Format(message, args)}");
+ }
+
+ public void LogError(Exception ex, string message, params object[] args)
+ {
+ Console.WriteLine($"[ERROR] [{_typeName}] {string.Format(message, args)}");
+ Console.WriteLine($"Exception: {ex.GetType().Name} - {ex.Message}");
+ Console.WriteLine($"Stack Trace: {ex.StackTrace}");
+ }
+ }
+}
\ No newline at end of file
diff --git a/RefactorThis.Domain/Loggers/IAppLogger.cs b/RefactorThis.Domain/Loggers/IAppLogger.cs
new file mode 100644
index 0000000..3c74159
--- /dev/null
+++ b/RefactorThis.Domain/Loggers/IAppLogger.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace RefactorThis.Domain.Loggers
+{
+ public interface IAppLogger
+ {
+ void LogInformation(string message, params object[] args);
+ void LogWarning(string message, params object[] args);
+ void LogError(Exception ex, string message, params object[] args);
+ }
+}
\ No newline at end of file
diff --git a/RefactorThis.Domain/Models/PaymentResult.cs b/RefactorThis.Domain/Models/PaymentResult.cs
new file mode 100644
index 0000000..de3199e
--- /dev/null
+++ b/RefactorThis.Domain/Models/PaymentResult.cs
@@ -0,0 +1,39 @@
+namespace RefactorThis.Domain.Models
+{
+ public class PaymentResult
+ {
+ public bool IsSuccess { get; }
+ public ResultCode? Code { get; }
+ public string Message { get; }
+
+ public static PaymentResult SuccessResult(ResultCode? code = null, string message = null)
+ => new PaymentResult(true, code, message);
+
+ public static PaymentResult FailureResult(ResultCode? code = null, string message = null)
+ => new PaymentResult(false, code, message);
+
+ private PaymentResult(bool isSuccess, ResultCode? code = null, string message = null)
+ {
+ IsSuccess = isSuccess;
+ Code = code ?? ResultCode.Unknown;
+ Message = string.IsNullOrEmpty(message) ? "No comments" : message;
+ }
+ }
+
+ public enum ResultCode
+ {
+ Unknown,
+ // Success
+ NoPaymentNeeded,
+ AlreadyFullyPaid,
+ FinalPaymentComplete,
+ PartialPaymentComplete,
+
+ // Failure
+ InvoiceNotFound,
+ InvalidInvoiceState,
+ PaymentExceedsRemainingAmount,
+ PaymentExceedsInvoiceAmount,
+ ProcessingError
+ }
+}
\ No newline at end of file
diff --git a/RefactorThis.Domain/RefactorThis.Domain.csproj b/RefactorThis.Domain/RefactorThis.Domain.csproj
index 753e893..20c3dc7 100644
--- a/RefactorThis.Domain/RefactorThis.Domain.csproj
+++ b/RefactorThis.Domain/RefactorThis.Domain.csproj
@@ -32,20 +32,42 @@
4
+
+
+ ..\packages\System.Linq.4.3.0\lib\net463\System.Linq.dll
+
-
+
+
+
+
+
+
+
+
{33cdc796-ff75-449c-9637-59c2efc46361}
RefactorThis.Persistence
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+