Skip to content
Merged
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
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [6.7.0] - 2026-08-21
## [6.8.0] - 2026-09-04
### Added
- Added `GetPaymentSummaryAsync` to get the related-document object needed to build a payment complement (complemento de pago): installment number, previous balance, and taxes prorated to the paid amount.

## [6.7.0] - 2026-08-24
### Added
- Added invoice ZIP request methods: `CreateZipRequestAsync`, `ListZipRequestsAsync`, `RetrieveZipRequestAsync`, and `DownloadZipRequestAsync`.

### Fixed
- Expose `InvoiceItem.PropertyTaxAccount` as a list of property tax account numbers.

## [6.6.0] - 2026-07-01
### Added
- Added retention draft methods: `UpdateDraftAsync`, `StampDraftAsync`, and `CopyToDraftAsync`.
Expand Down
20 changes: 20 additions & 0 deletions FacturapiTest/WrapperBehaviorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,26 @@ public async Task InvoiceCreateAsync_UsesPostAndQueryString()
Assert.Equal("inv_001", result.Id);
}

[Fact]
public async Task InvoiceGetPaymentSummaryAsync_UsesPaymentSummaryRoute()
{
var handler = new RecordingHandler((request, cancellationToken) =>
{
Assert.Equal(HttpMethod.Get, request.Method);
Assert.NotNull(request.RequestUri);
Assert.Equal("/v2/invoices/inv_123/payment-summary?amount=58", request.RequestUri.PathAndQuery);
return Task.FromResult(JsonResponse("{\"uuid\":\"6CF6CE33-1BD2-4F88-A443-33013C069169\",\"installment\":1,\"last_balance\":100,\"total\":100,\"currency\":\"MXN\",\"amount\":58,\"taxes\":[{\"base\":50,\"rate\":0.16,\"type\":\"IVA\",\"factor\":\"Tasa\",\"withholding\":false}]}"));
});

var wrapper = new InvoiceWrapper("test_key", "v2", CreateHttpClient(handler));
var result = await wrapper.GetPaymentSummaryAsync("inv_123", 58);

Assert.Equal("6CF6CE33-1BD2-4F88-A443-33013C069169", result.Uuid);
Assert.Equal(1, result.Installment);
Assert.Equal(50m, result.Taxes[0].Base);
Assert.False(result.Taxes[0].Withholding);
}

[Fact]
public async Task ReceiptCancelAsync_UsesReceiptDeleteRoute()
{
Expand Down
26 changes: 26 additions & 0 deletions Models/PaymentSummary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Collections.Generic;

namespace Facturapi
{
public class PaymentSummary
{
public string Uuid { get; set; }
public decimal? FolioNumber { get; set; }
public string Series { get; set; }
public int Installment { get; set; }
public decimal LastBalance { get; set; }
public decimal Total { get; set; }
public string Currency { get; set; }
public decimal Amount { get; set; }
public List<PaymentSummaryTax> Taxes { get; set; }
}

public class PaymentSummaryTax
{
public decimal Base { get; set; }
public decimal Rate { get; set; }
public string Type { get; set; }
public string Factor { get; set; }
public bool Withholding { get; set; }
}
}
10 changes: 9 additions & 1 deletion Router/InvoiceRouter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
Expand All @@ -18,6 +18,14 @@ public static string RetrieveInvoice(string id)
return $"invoices/{id}";
}

public static string RetrieveInvoicePaymentSummary(string id, double amount)
{
return UriWithQuery($"{RetrieveInvoice(id)}/payment-summary", new Dictionary<string, object>
{
["amount"] = amount
});
}

public static string CreateInvoice(Dictionary<string, object> query = null)
{
return UriWithQuery("invoices", query);
Expand Down
1 change: 1 addition & 0 deletions Wrappers/IInvoiceWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public interface IInvoiceWrapper
Task<SearchResult<Invoice>> ListAsync(Dictionary<string, object> query = null, CancellationToken cancellationToken = default);
Task<Invoice> CreateAsync(Dictionary<string, object> data, Dictionary<string, object> options = null, CancellationToken cancellationToken = default);
Task<Invoice> RetrieveAsync(string id, CancellationToken cancellationToken = default);
Task<PaymentSummary> GetPaymentSummaryAsync(string id, double amount, CancellationToken cancellationToken = default);
Task<Invoice> CancelAsync(string id, Dictionary<string, object> query = null, CancellationToken cancellationToken = default);
Task SendByEmailAsync(string id, Dictionary<string, object> data = null, CancellationToken cancellationToken = default);
Task<Stream> DownloadZipAsync(string id, CancellationToken cancellationToken = default);
Expand Down
13 changes: 12 additions & 1 deletion Wrappers/InvoiceWrapper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
Expand Down Expand Up @@ -50,6 +50,17 @@ public async Task<Invoice> RetrieveAsync(string id, CancellationToken cancellati
}
}

public async Task<PaymentSummary> GetPaymentSummaryAsync(string id, double amount, CancellationToken cancellationToken = default)
{
using (var response = await client.GetAsync(Router.RetrieveInvoicePaymentSummary(id, amount), cancellationToken).ConfigureAwait(false))
{
await this.ThrowIfErrorAsync(response, cancellationToken).ConfigureAwait(false);
var resultString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var summary = JsonConvert.DeserializeObject<PaymentSummary>(resultString, this.jsonSettings);
return summary;
}
}

public async Task<Invoice> CancelAsync(string id, Dictionary<string, object> query = null, CancellationToken cancellationToken = default)
{
using (var response = await client.DeleteAsync(Router.CancelInvoice(id, query), cancellationToken).ConfigureAwait(false))
Expand Down
2 changes: 1 addition & 1 deletion facturapi-net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<Summary>SDK oficial de Facturapi para .NET para facturación electrónica en México (CFDI), envío de documentos, búsqueda y trazabilidad.</Summary>
<PackageTags>factura factura-electronica facturacion cfdi cfdi40 sat invoice invoicing facturapi mexico</PackageTags>
<Title>Facturapi</Title>
<Version>6.7.0</Version>
<Version>6.8.0</Version>
<PackageVersion>$(Version)</PackageVersion>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
Expand Down
Loading