Skip to content

Commit

Permalink
Sample Unit Tests (#18)
Browse files Browse the repository at this point in the history
* Sample unit tests

* Updated GitHub action

* Sample unit tests

* Sample Unit Tests
  • Loading branch information
carlosga authored Jun 16, 2024
1 parent c465e38 commit a86170d
Show file tree
Hide file tree
Showing 2 changed files with 312 additions and 36 deletions.
115 changes: 80 additions & 35 deletions src/facturae/Facturae.Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Carlos Guzmán Álvarez. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Security.Cryptography.X509Certificates;

using FacturaE.DataType;

namespace FacturaE;
Expand Down Expand Up @@ -179,11 +181,6 @@ public InvoiceType CreateInvoice()

public partial class InvoiceType
{
public Facturae Root()
{
return Parent;
}

/// <summary>
/// Set the invoice series code.
/// </summary>
Expand Down Expand Up @@ -441,6 +438,28 @@ public InvoiceLineType AddInvoiceItem(string productCode = null, string productD
return item;
}

/// <summary>
/// Adds a new general discount to an invoice.
/// </summary>
/// <param name="discountReason">The discount reason.</param>
/// <param name="discountRate">The discount rate.</param>
/// <returns></returns>
public InvoiceType AddGeneralDiscount(string discountReason, decimal discountRate)
{
InvoiceTotals.GeneralDiscounts ??= new List<DiscountType>(1);

var discount = new DiscountType
{
DiscountReason = discountReason,
DiscountRate = discountRate,
DiscountRateSpecified = true,
};

InvoiceTotals.GeneralDiscounts.Add(discount);

return this;
}

/// <summary>
/// Calculates the invoice totals.
/// </summary>
Expand All @@ -457,31 +476,37 @@ public Facturae CalculateTotals()
TaxRate = g.Key.TaxRate,
TaxableBase = new AmountType
{
TotalAmount = g.Sum(gtax => gtax.TaxableBase.TotalAmount).Round(),
EquivalentInEuros = g.Sum(gtax => gtax.TaxableBase.EquivalentInEuros).Round(),
EquivalentInEurosSpecified = true
},
TaxAmount = new AmountType
{
TotalAmount = g.Sum(gtax => gtax.TaxAmount.TotalAmount).Round(),
EquivalentInEuros = g.Sum(gtax => gtax.TaxAmount.EquivalentInEuros).Round(),
TotalAmount = ApplyGeneralDiscounts(g.Sum(gtax => gtax.TaxableBase.TotalAmount)).Round(),
EquivalentInEuros = ApplyGeneralDiscounts(g.Sum(gtax => gtax.TaxableBase.EquivalentInEuros)).Round(),
EquivalentInEurosSpecified = true
},
EquivalenceSurcharge = g.Key.EquivalenceSurcharge,
EquivalenceSurchargeSpecified = g.Any(gtax => gtax.EquivalenceSurchargeSpecified),
EquivalenceSurchargeAmount = new AmountType
{
TotalAmount = g.Where(gtax => gtax.EquivalenceSurchargeSpecified)
.Sum(gtax => gtax.EquivalenceSurchargeAmount.TotalAmount).Round(),
EquivalentInEuros = g.Where(gtax => gtax.EquivalenceSurchargeSpecified)
.Sum(gtax => gtax.EquivalenceSurchargeAmount.EquivalentInEuros).Round(),
EquivalentInEurosSpecified = true
},
TaxTypeCode = g.Key.TaxTypeCode
TaxTypeCode = g.Key.TaxTypeCode
};

TaxesOutputs = [.. q.OrderBy(x => x.TaxTypeCode).ThenBy(x => x.TaxRate).ThenBy(x => x.EquivalenceSurcharge)];

foreach (var tax in TaxesOutputs)
{
tax.TaxAmount = new AmountType
{
TotalAmount = (tax.TaxableBase.TotalAmount * tax.TaxRate / 100.0M).Round(),
EquivalentInEuros = (tax.TaxableBase.TotalAmount * tax.TaxRate / 100.0M).Round(),
EquivalentInEurosSpecified = true
};

if (tax.EquivalenceSurchargeSpecified)
{
tax.EquivalenceSurchargeAmount = new AmountType
{
TotalAmount = (tax.TaxableBase.TotalAmount * tax.EquivalenceSurcharge / 100.0M).Round(),
EquivalentInEuros = (tax.TaxableBase.TotalAmount * tax.EquivalenceSurcharge / 100.0M).Round(),
EquivalentInEurosSpecified = true
};
}
}

// Taxes Withheld
var w = from tax in Items.SelectMany(x => x.TaxesWithheld)
group tax by new { tax.TaxTypeCode, tax.TaxRate } into g
Expand All @@ -503,9 +528,6 @@ public Facturae CalculateTotals()

TaxesWithheld = [.. w.OrderBy(x => x.TaxTypeCode).ThenBy(x => x.TaxRate)];

// Invoice totals
InvoiceTotals = new InvoiceTotalsType();

// Calculate totals
InvoiceTotals.TotalGrossAmount = Items.Sum(it => it.GrossAmount).Round();

Expand All @@ -514,8 +536,8 @@ public Facturae CalculateTotals()
CalculateGeneralSurchargesTotals();

InvoiceTotals.TotalGrossAmountBeforeTaxes = (InvoiceTotals.TotalGrossAmount
- InvoiceTotals.TotalGeneralDiscounts
+ InvoiceTotals.TotalGeneralSurcharges).Round();
- InvoiceTotals.TotalGeneralDiscounts
+ InvoiceTotals.TotalGeneralSurcharges).Round();

CalculatePaymentsOnAccountTotals();

Expand Down Expand Up @@ -557,10 +579,25 @@ public Facturae CalculateTotals()
return Parent;
}

private decimal ApplyGeneralDiscounts(decimal baseAmount)
{
var discount = 0.0M;

if (InvoiceTotals.GeneralDiscounts is not null && InvoiceTotals.GeneralDiscounts.Count > 0)
{
foreach (var gd in InvoiceTotals.GeneralDiscounts)
{
discount += baseAmount * gd.DiscountRate / 100;
}
}

return baseAmount - discount;
}

private void CalculateSubsidyAmounts()
{
// Rate applied to the Invoice Total.
InvoiceTotals.Subsidies.ForEach(s => s.SubsidyAmount = (InvoiceTotals.InvoiceTotal * s.SubsidyRate / 100).Round());
InvoiceTotals.Subsidies.ForEach(s => s.SubsidyAmount = (InvoiceTotals.InvoiceTotal * s.SubsidyRate / 100.0M).Round());
}

private void CalculateReimbursableExpensesTotals()
Expand Down Expand Up @@ -588,7 +625,7 @@ private void CalculateGeneralSurchargesTotals()
{
InvoiceTotals.GeneralSurcharges.ForEach
(
gs => gs.ChargeAmount = (InvoiceTotals.TotalGrossAmount * gs.ChargeRate / 100).Round()
gs => gs.ChargeAmount = (InvoiceTotals.TotalGrossAmount * gs.ChargeRate / 100.0M).Round()
);

InvoiceTotals.TotalGeneralSurcharges = InvoiceTotals.GeneralSurcharges.Sum(gs => gs.ChargeAmount).Round();
Expand All @@ -601,7 +638,7 @@ private void CalculateGeneralDiscountTotals()
{
InvoiceTotals.GeneralDiscounts.ForEach
(
gd => gd.DiscountAmount = (InvoiceTotals.TotalGrossAmount * gd.DiscountRate / 100).Round()
gd => gd.DiscountAmount = (InvoiceTotals.TotalGrossAmount * gd.DiscountRate / 100.0M).Round()
);

InvoiceTotals.TotalGeneralDiscounts = InvoiceTotals.GeneralDiscounts.Sum(gd => gd.DiscountAmount).Round();
Expand Down Expand Up @@ -651,6 +688,14 @@ public InvoiceLineType SetIssuerTransactionDate(DateTime? value)
return this;
}

public InvoiceLineType SetTransactionDate(DateTime? value)
{
TransactionDate = value ?? DateTime.Today;
TransactionDateSpecified = value.HasValue;

return this;
}

public InvoiceLineType SetDescription(string description)
{
ItemDescription = description;
Expand Down Expand Up @@ -753,7 +798,7 @@ public InvoiceType CalculateTotals()
{
foreach (var dar in DiscountsAndRebates)
{
dar.DiscountAmount = (TotalCost * dar.DiscountRate / 100).Round();
dar.DiscountAmount = (TotalCost * dar.DiscountRate / 100.0M).Round();
totalDiscounts = (totalDiscounts + dar.DiscountAmount).Round();
}
}
Expand All @@ -762,7 +807,7 @@ public InvoiceType CalculateTotals()
{
foreach (var chr in Charges)
{
chr.ChargeAmount = (TotalCost * chr.ChargeRate / 100).Round();
chr.ChargeAmount = (TotalCost * chr.ChargeRate / 100.0M).Round();
totalCharges = (totalCharges + chr.ChargeAmount).Round();
}
}
Expand All @@ -782,14 +827,14 @@ public InvoiceType CalculateTotals()

tax.TaxAmount ??= new AmountType();

tax.TaxAmount.TotalAmount = (tax.TaxableBase.TotalAmount * tax.TaxRate / 100).Round();
tax.TaxAmount.TotalAmount = (tax.TaxableBase.TotalAmount * tax.TaxRate / 100.0M).Round();
tax.TaxAmount.EquivalentInEuros = tax.TaxAmount.TotalAmount;

if (tax.EquivalenceSurchargeSpecified)
{
tax.EquivalenceSurchargeAmount ??= new AmountType();

tax.EquivalenceSurchargeAmount.TotalAmount = (tax.TaxableBase.TotalAmount * tax.EquivalenceSurcharge / 100).Round();
tax.EquivalenceSurchargeAmount.TotalAmount = (tax.TaxableBase.TotalAmount * tax.EquivalenceSurcharge / 100.0M).Round();
tax.EquivalenceSurchargeAmount.EquivalentInEuros = tax.EquivalenceSurchargeAmount.TotalAmount;
tax.EquivalenceSurchargeAmount.EquivalentInEurosSpecified = true;
}
Expand All @@ -810,7 +855,7 @@ public InvoiceType CalculateTotals()

tax.TaxAmount ??= new AmountType();

tax.TaxAmount.TotalAmount = (tax.TaxableBase.TotalAmount * tax.TaxRate / 100).Round();
tax.TaxAmount.TotalAmount = (tax.TaxableBase.TotalAmount * tax.TaxRate / 100.0M).Round();
tax.TaxAmount.EquivalentInEuros = tax.TaxAmount.TotalAmount;
tax.TaxAmount.EquivalentInEurosSpecified = true;
}
Expand Down
Loading

0 comments on commit a86170d

Please sign in to comment.