Move logic out the the class libs
This commit is contained in:
171
PointOfSale/Pos.Service/SalesTransactionService.cs
Normal file
171
PointOfSale/Pos.Service/SalesTransactionService.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Pos.Models;
|
||||
|
||||
namespace Pos.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// Holder styr på den igangværende handel og dens beregninger.
|
||||
/// Servicen har ingen afhængighed til WPF eller web.
|
||||
/// </summary>
|
||||
public class SalesTransactionService
|
||||
{
|
||||
private readonly List<PriceLineModel> _saleLines = new List<PriceLineModel>();
|
||||
private readonly List<AmountGridModel> _payments = new List<AmountGridModel>();
|
||||
|
||||
public IReadOnlyList<PriceLineModel> SaleLines => _saleLines;
|
||||
public IReadOnlyList<AmountGridModel> Payments => _payments;
|
||||
|
||||
public decimal TotalPrice =>
|
||||
_saleLines.Sum(line =>
|
||||
CalculateLineTotal(line.Price, line.NumberProducts));
|
||||
|
||||
public decimal AmountPaid =>
|
||||
_payments.Sum(payment => payment.Amount);
|
||||
|
||||
public decimal RemainingAmount =>
|
||||
Math.Max(TotalPrice - AmountPaid, 0);
|
||||
|
||||
public decimal Change =>
|
||||
Math.Max(AmountPaid - TotalPrice, 0);
|
||||
|
||||
public bool IsFullyPaid =>
|
||||
TotalPrice > 0 && AmountPaid >= TotalPrice;
|
||||
|
||||
/// <summary>
|
||||
/// Beregner totalen for en enkelt salgslinje.
|
||||
/// Parsing og visning af resultatet er fortsat UI-ansvar.
|
||||
/// </summary>
|
||||
public decimal CalculateLineTotal(decimal price, int numberOfProducts)
|
||||
{
|
||||
ValidatePriceAndQuantity(price, numberOfProducts);
|
||||
return price * numberOfProducts;
|
||||
}
|
||||
|
||||
public PriceLineModel AddSaleLine(
|
||||
int id,
|
||||
string name,
|
||||
int numberOfProducts,
|
||||
decimal price,
|
||||
bool isProductGroup)
|
||||
{
|
||||
if (id <= 0)
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(id),
|
||||
"Id skal være større end 0.");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
throw new ArgumentException(
|
||||
"Navn skal være udfyldt.",
|
||||
nameof(name));
|
||||
|
||||
ValidatePriceAndQuantity(price, numberOfProducts);
|
||||
|
||||
PriceLineModel saleLine = new PriceLineModel
|
||||
{
|
||||
Id = id,
|
||||
Name = name,
|
||||
NumberProducts = numberOfProducts,
|
||||
Price = price,
|
||||
IsProductGroup = isProductGroup
|
||||
};
|
||||
|
||||
_saleLines.Add(saleLine);
|
||||
return saleLine;
|
||||
}
|
||||
|
||||
public void RemoveSaleLineAt(int index)
|
||||
{
|
||||
if (index < 0 || index >= _saleLines.Count)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
_saleLines.RemoveAt(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registrerer en betaling. Hvis amount er null, betales restbeløbet.
|
||||
/// </summary>
|
||||
public AmountGridModel AddPayment(
|
||||
PaymentMethod paymentMethod,
|
||||
decimal? amount = null)
|
||||
{
|
||||
if (_saleLines.Count == 0)
|
||||
throw new InvalidOperationException(
|
||||
"Der kan ikke registreres betaling på et tomt salg.");
|
||||
|
||||
decimal paymentAmount = amount ?? RemainingAmount;
|
||||
|
||||
if (paymentAmount <= 0)
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(amount),
|
||||
"Betalingsbeløbet skal være større end 0.");
|
||||
|
||||
AmountGridModel payment = new AmountGridModel
|
||||
{
|
||||
Amount = paymentAmount,
|
||||
PaymentMethodText = GetPaymentMethodText(paymentMethod)
|
||||
};
|
||||
|
||||
_payments.Add(payment);
|
||||
return payment;
|
||||
}
|
||||
|
||||
public void RemovePaymentAt(int index)
|
||||
{
|
||||
if (index < 0 || index >= _payments.Count)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
_payments.RemoveAt(index);
|
||||
}
|
||||
|
||||
public void EnsureCanComplete()
|
||||
{
|
||||
if (_saleLines.Count == 0)
|
||||
throw new InvalidOperationException(
|
||||
"Et tomt salg kan ikke afsluttes.");
|
||||
|
||||
if (!IsFullyPaid)
|
||||
throw new InvalidOperationException(
|
||||
"Salget er ikke fuldt betalt.");
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_saleLines.Clear();
|
||||
_payments.Clear();
|
||||
}
|
||||
|
||||
private static void ValidatePriceAndQuantity(
|
||||
decimal price,
|
||||
int numberOfProducts)
|
||||
{
|
||||
if (price < 0)
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(price),
|
||||
"Prisen må ikke være negativ.");
|
||||
|
||||
if (numberOfProducts <= 0)
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(numberOfProducts),
|
||||
"Antal skal være større end 0.");
|
||||
}
|
||||
|
||||
private static string GetPaymentMethodText(PaymentMethod paymentMethod)
|
||||
{
|
||||
switch (paymentMethod)
|
||||
{
|
||||
case PaymentMethod.Card:
|
||||
return "Kort";
|
||||
case PaymentMethod.Cash:
|
||||
return "Kontant";
|
||||
case PaymentMethod.GiftCard:
|
||||
return "Gavekort";
|
||||
case PaymentMethod.MobilePay:
|
||||
return "MobilePay";
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(paymentMethod));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user