172 lines
5.3 KiB
C#
172 lines
5.3 KiB
C#
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));
|
|
}
|
|
}
|
|
}
|
|
}
|