Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
cfbd649
docs: adicionar auditoria de conformidade e plano de implementacao v3.0
cloviscoli May 24, 2026
1f38c06
fix: usar PUT em vez de POST em metodos de Update
cloviscoli May 24, 2026
efa67d8
fix(fiscalInfo)!: corrigir rota para /fiscalInfo e renomear manager
cloviscoli May 24, 2026
a654dcd
fix(finance)!: Balance retorna objeto { balance: decimal }
cloviscoli May 24, 2026
f7e682d
fix(anticipation)!: remover SignAgreement (endpoint inexistente)
cloviscoli May 24, 2026
bcd0e02
feat(installments): adicionar Create e endpoints faltantes
cloviscoli May 24, 2026
c1ceeaa
feat(webhooks)!: migrar para CRUD por ID em /v3/webhooks
cloviscoli May 24, 2026
8cd732e
feat(payment): adicionar 14 endpoints faltantes + completar models
cloviscoli May 24, 2026
2f912d6
feat(subscription): adicionar UpdateCreditCard
cloviscoli May 24, 2026
e95d185
feat(anticipation): adicionar cancel, limits e configuracoes
cloviscoli May 24, 2026
b827307
feat(creditCard): adicionar configuracao de pre-autorizacao
cloviscoli May 24, 2026
e3d3101
feat(transfer)!: Cancel + roteamento correto para /transfers/
cloviscoli May 24, 2026
94a3c64
feat(pix): adicionar FindTransaction, DeleteStaticQrCode e GetAddress…
cloviscoli May 24, 2026
6249ede
feat(myAccount)!: commercialInfo, status e documents
cloviscoli May 24, 2026
d28e9f0
feat(asaasAccount): adicionar Find, ResendActivationLink e AccessTokens
cloviscoli May 24, 2026
d624b6c
feat: novo ChargebackManager
cloviscoli May 24, 2026
9e4a523
feat: novo EscrowManager
cloviscoli May 24, 2026
5618e81
feat: novo CheckoutManager
cloviscoli May 24, 2026
d39717c
feat: novo MobilePhoneRechargeManager
cloviscoli May 24, 2026
ba4afd1
feat(payment): adicionar splits queries
cloviscoli May 24, 2026
ea8db99
feat: novo SandboxManager (apenas sandbox)
cloviscoli May 24, 2026
480a7f0
feat: novo PixAutomaticManager
cloviscoli May 24, 2026
6a11d76
feat: novo PixRecurringManager
cloviscoli May 24, 2026
f8dc0b8
refactor(customer): completar campos faltantes em Customer model
cloviscoli May 24, 2026
1853c36
refactor(payment): completar Payment model + bool? em opcionais
cloviscoli May 24, 2026
882395d
refactor(core): compartilhar SocketsHttpHandler estatico entre requis…
cloviscoli May 24, 2026
6ce0da6
chore: corrigir typo WasSucessfull -> WasSuccessful
cloviscoli May 24, 2026
d0a8184
chore(release): bump version to 3.0.0
cloviscoli May 24, 2026
b3ac4fd
fix(review): bugs criticos da revisao apos audit
cloviscoli May 24, 2026
8cd6446
fix(payment): reescrever PaymentLimits, SimulatePaymentRequest e Simu…
cloviscoli May 24, 2026
b122eeb
fix(checkout): reescrever schema conforme API oficial (B-04)
cloviscoli May 24, 2026
2e77791
fix(pixAutomatic): reescrever PixAutomaticAuthorization conforme API …
cloviscoli May 24, 2026
70eadfb
fix(review): B-07 + I-02 + ajustes finais da revisao
cloviscoli May 24, 2026
83d47bd
refactor(review): I-01 e I-09 da revisao
cloviscoli May 24, 2026
98778d7
test: I-03 e P-01 - SerializationTests usa JsonSerializerConfiguratio…
cloviscoli May 24, 2026
f42708d
test: I-05 e I-08 - testes faltantes dos managers novos
cloviscoli May 24, 2026
88bffae
refactor(api)!: I-06 - renomear ReceivableAnticipation para Anticipation
cloviscoli May 24, 2026
9045db4
refactor: I-07 + P-02 + P-03 - 1 classe por arquivo + polimento
cloviscoli May 24, 2026
4ae31f1
fix: schemas Escrow e PixRecurring conforme API (REVIEW2 B-09..B-14)
cloviscoli May 24, 2026
263f57b
fix: REVIEW2 - bool query case + Subscription.Deleted + comentario Ch…
cloviscoli May 24, 2026
bb7a2f9
docs: atualizar README v3.0 + REVIEW2.md com achados da 2a revisao
cloviscoli May 24, 2026
005f536
test(infra): infraestrutura schema-first (Contract + Integration + Fi…
cloviscoli May 24, 2026
fd6ae36
fix(core): query params com cultura invariante + contract tests siste…
cloviscoli May 24, 2026
f4dffdb
test(contract): F3a - PaymentLimits + SimulatePayment auditados
cloviscoli May 24, 2026
68016b3
test(contract): F3b - Checkout auditado + fix Cycle.BIMONTHLY pre-exi…
cloviscoli May 24, 2026
768b6c1
test(contract): F3c - Escrow auditado (todos 6 endpoints)
cloviscoli May 24, 2026
6f511d4
fix(pixAutomatic): B-16 PaymentInstruction + B-17 ListFilter
cloviscoli May 24, 2026
dd74d0c
audit(pix-recurring): adicionar filter de List + contract tests schem…
cloviscoli May 24, 2026
a46748a
audit(mobile-phone-recharge): fix B-19 (Provider.values shape) + cont…
cloviscoli May 24, 2026
90cf387
audit(account-document): typar enums + remover modelos chutados (B-20)
cloviscoli May 24, 2026
8e54284
audit(invoice): completar Taxes + fixar filter casing (B-21)
cloviscoli May 24, 2026
e02ae81
audit(payment-dunning): fix B-22 a-m (8 bugs criticos)
cloviscoli May 24, 2026
47dc2f0
audit(credit-bureau): remover campos ficticios + adicionar filter (B-23)
cloviscoli May 24, 2026
9d778ea
audit(bill-payment): completar BillPayment/BankSlipInfo + status enum…
cloviscoli May 24, 2026
7aa1b6b
test(integration): adicionar 5 tests sandbox para Customer + Payment
cloviscoli May 24, 2026
8d8baff
chore(quality): remover anotacoes string? sem #nullable context
cloviscoli May 24, 2026
06d477b
docs(audit): finalizar CONFORMANCE + atualizar CHANGELOG/README (v3.1.0)
cloviscoli May 24, 2026
041b1fe
audit(customer): schema-first + adicionar GetNotifications (B-25)
cloviscoli May 24, 2026
2bdadd6
audit(payment): Payment response nullable + 9 filtros faltantes (B-26)
cloviscoli May 25, 2026
5b6701c
audit(subscription): INACTIVE enum + filtros + nullable dates (B-27)
cloviscoli May 25, 2026
c30806c
audit(pix): reescrever PixTransaction/AddressKey + 4 enums novos (B-28)
cloviscoli May 25, 2026
632779d
audit(transfer): completar BaseTransfer + enum AsaasAccountTransferSt…
cloviscoli May 25, 2026
0c4fd4d
audit(anticipation): nullable dates + Object field (B-30)
cloviscoli May 25, 2026
d23e9d6
audit(installment): Refunds array + CreditCard + ExpirationDay nullab…
cloviscoli May 25, 2026
03876c7
audit(webhook): contract tests + fixture (B-32, model ja correto)
cloviscoli May 25, 2026
462cf78
audit(wallet+notification): Object/Event enum + nullable bools (B-33,…
cloviscoli May 25, 2026
aa8b421
audit(credit-card): PreAuthorizationConfig + Brand enum (B-35)
cloviscoli May 25, 2026
36dba3d
audit(payment-link): SubscriptionCycle enum + nullable + campos novos…
cloviscoli May 25, 2026
d1da0a2
audit(finance): SplitStatistics shape + 11 filtros statistics (B-37)
cloviscoli May 25, 2026
54f431b
audit(my-account): Status enum + campos novos commercialInfo (B-38)
cloviscoli May 25, 2026
c2f14cb
audit(asaas-account): Account.City int + campos novos (B-39)
cloviscoli May 25, 2026
8d1e614
audit(fiscal-info): RpsNumber/LoteNumber int + 5 campos novos (B-40)
cloviscoli May 25, 2026
35ca6e5
audit(chargeback): CreditCard nested object + Reason nullable (B-41)
cloviscoli May 25, 2026
43888ed
audit(sandbox): contract test sanity check (B-42, manager ja correto)
cloviscoli May 25, 2026
56f9595
test(integration) + ci: expandir cobertura sandbox + workflow dedicado
cloviscoli May 25, 2026
2aeb83f
docs(audit): CONFORMANCE 27/27 + cross-pattern bug list + riscos clas…
cloviscoli May 25, 2026
455d72f
docs: CHANGELOG [3.2.0] + README atualizados (27/27 + 664 tests + 15 …
cloviscoli May 25, 2026
c62ac0d
docs(audit): adicionar instrucao explicita pra fechar Fase 29 via GH …
cloviscoli May 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ jobs:
- name: Build library
run: dotnet build Codout.Apis.Asaas/Codout.Apis.Asaas.csproj --configuration Release --no-restore

- name: Test
run: dotnet test Codout.Apis.Asaas.Tests/Codout.Apis.Asaas.Tests.csproj --configuration Release --logger "console;verbosity=normal"
- name: Test (unit + contract — integration are auto-skipped without ASAAS_SANDBOX_TOKEN)
run: dotnet test Codout.Apis.Asaas.Tests/Codout.Apis.Asaas.Tests.csproj --configuration Release --logger "console;verbosity=normal" --filter "Category!=Integration"
51 changes: 51 additions & 0 deletions .github/workflows/integration-sandbox.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Integration (sandbox)

# Roda os integration tests reais contra api-sandbox.asaas.com.
# Requer secret ASAAS_SANDBOX_TOKEN configurado no repositorio
# (Settings -> Secrets and variables -> Actions).
#
# Triggers:
# - manual (workflow_dispatch): permite rodar sob demanda
# - schedule (nightly): valida o SDK contra mudancas no sandbox
#
# Nao bloqueia PRs comuns (rodar em job separado).

on:
workflow_dispatch:
schedule:
# Diariamente as 04:00 UTC (01:00 BRT)
- cron: '0 4 * * *'

jobs:
integration:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'

- name: Restore library
run: dotnet restore Codout.Apis.Asaas/Codout.Apis.Asaas.csproj

- name: Restore tests
run: dotnet restore Codout.Apis.Asaas.Tests/Codout.Apis.Asaas.Tests.csproj

- name: Build library
run: dotnet build Codout.Apis.Asaas/Codout.Apis.Asaas.csproj --configuration Release --no-restore

- name: Integration tests (sandbox)
env:
ASAAS_SANDBOX_TOKEN: ${{ secrets.ASAAS_SANDBOX_TOKEN }}
run: |
if [ -z "$ASAAS_SANDBOX_TOKEN" ]; then
echo "::warning::ASAAS_SANDBOX_TOKEN secret nao configurado. Integration tests serao todos skipados."
fi
dotnet test Codout.Apis.Asaas.Tests/Codout.Apis.Asaas.Tests.csproj \
--configuration Release \
--logger "console;verbosity=normal" \
--filter "Category=Integration"
8 changes: 8 additions & 0 deletions .mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"mcpServers": {
"asaas": {
"type": "http",
"url": "https://docs.asaas.com/mcp"
}
}
}
369 changes: 369 additions & 0 deletions AUDIT.md

Large diffs are not rendered by default.

413 changes: 413 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

608 changes: 608 additions & 0 deletions CONFORMANCE.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Codout.Apis.Asaas.Sample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

ResponseObject<Customer> customerResponse = await asaasApi.Customer.Find("cus_13bFHumeyglN");

if (customerResponse.WasSucessfull())
if (customerResponse.WasSuccessful())
{
Customer customer = customerResponse.Data;

Expand Down
8 changes: 8 additions & 0 deletions Codout.Apis.Asaas.Tests/Codout.Apis.Asaas.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,12 @@
<ProjectReference Include="..\Codout.Apis.Asaas\Codout.Apis.Asaas.csproj" />
</ItemGroup>

<ItemGroup>
<!-- Fixtures JSON extraidas da documentacao oficial Asaas; copiadas para o
diretorio de saida para serem lidas pelos contract tests em runtime. -->
<None Update="Fixtures\**\*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
183 changes: 183 additions & 0 deletions Codout.Apis.Asaas.Tests/Contract/AccountDocumentContractTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
using System;
using System.Text.Json;
using Codout.Apis.Asaas.Models.MyAccount;
using Codout.Apis.Asaas.Models.MyAccount.Enums;

namespace Codout.Apis.Asaas.Tests.Contract;

/// <summary>
/// Contract tests para os endpoints de Account Document (MyAccountManager).
/// Schemas verificados via MCP em 2026-05-24:
/// - GET /v3/myAccount/documents (envelope {data:[...]} sem paginacao + rejectReasons)
/// - POST /v3/myAccount/documents/{id} (multipart, retorna AccountDocument {id,status})
/// - GET /v3/myAccount/documents/files/{id} (retorna AccountDocument {id,status})
/// - POST /v3/myAccount/documents/files/{id} (multipart, retorna AccountDocument)
/// - DELETE /v3/myAccount/documents/files/{id} ({deleted, id})
/// </summary>
public class AccountDocumentContractTests
{
// ─────────────────────────────────────────────────────────────
// GET /v3/myAccount/documents -> AccountDocumentShowResponseDTO
// Envelope minimalista: { rejectReasons, data: [...] } (sem paginacao!)
// ─────────────────────────────────────────────────────────────

[Fact]
public void PendingDocumentsResponse_DeserializesFromOfficialFixture()
{
var json = FixtureLoader.Load("AccountDocument/pending-documents-response.json");

var result = JsonContractAssert.DeserializeFixture<AccountDocumentResponse>(json);

Assert.Null(result.RejectReasons);
Assert.Single(result.Data);

var group = result.Data[0];
Assert.Equal("172ed152-4fa4-43ad-9b69-39c323e9526c", group.Id);
Assert.Equal(AccountDocumentGroupStatus.NOT_SENT, group.Status);
Assert.Equal(AccountDocumentType.MINUTES_OF_CONSTITUTION, group.Type);
Assert.Equal("Minutes of election of the last board", group.Title);
Assert.Equal("No description", group.Description);
Assert.Equal("https://example.com/cadastro.io/8ad196d6cbfcc5d05bfabcbb5c730f6a", group.OnboardingUrl);
Assert.Equal(new DateTime(2025, 3, 4), group.OnboardingUrlExpirationDate);

Assert.NotNull(group.Responsible);
Assert.Equal("John Doe", group.Responsible.Name);
Assert.Single(group.Responsible.Type);
Assert.Equal(AccountDocumentResponsibleType.ASSOCIATION, group.Responsible.Type[0]);

Assert.Single(group.Documents);
Assert.Equal("8d257732-2220-11ec-b695-b6af4a64184d", group.Documents[0].Id);
Assert.Equal(AccountDocumentStatus.PENDING, group.Documents[0].Status);
}

[Fact]
public void PendingDocumentsResponse_UsesMinimalEnvelopeWithoutPagination()
{
// B-07 regression: o envelope tem APENAS {rejectReasons, data},
// sem hasMore/totalCount/limit/offset. Usar ResponseList aqui
// resultaria em propriedades vazias.
var json = FixtureLoader.Load("AccountDocument/pending-documents-response.json");

JsonContractAssert.HasRootProperty(json, "data", JsonValueKind.Array);
JsonContractAssert.HasRootProperty(json, "rejectReasons", JsonValueKind.Null);

using var doc = JsonDocument.Parse(json);
Assert.False(doc.RootElement.TryGetProperty("hasMore", out _));
Assert.False(doc.RootElement.TryGetProperty("totalCount", out _));
Assert.False(doc.RootElement.TryGetProperty("limit", out _));
Assert.False(doc.RootElement.TryGetProperty("offset", out _));
}

// ─────────────────────────────────────────────────────────────
// POST/GET /v3/myAccount/documents[/files]/{id} -> AccountDocumentGetResponseDTO
// B-20f/B-20g regression: ViewDocumentFile e SubmitDocument antes retornavam
// AccountDocumentFile (com Name/Url ficticios) e AccountDocumentGroup
// (objeto rico). Schema real retorna apenas {id, status}.
// ─────────────────────────────────────────────────────────────

[Fact]
public void DocumentResponse_HasOnlyIdAndStatus()
{
var json = FixtureLoader.Load("AccountDocument/document-response.json");

var result = JsonContractAssert.DeserializeFixture<AccountDocument>(json);

Assert.Equal("8d257732-2220-11ec-b695-b6af4a64184d", result.Id);
Assert.Equal(AccountDocumentStatus.PENDING, result.Status);

// Regressao B-20f: schema NAO retorna name nem url
using var doc = JsonDocument.Parse(json);
Assert.False(doc.RootElement.TryGetProperty("name", out _));
Assert.False(doc.RootElement.TryGetProperty("url", out _));
}

[Fact]
public void DocumentStatus_AllFourValuesDeserialize()
{
// Schema AccountDocumentGetResponseDTO.status: NOT_SENT, PENDING, APPROVED, REJECTED
foreach (var status in new[] { "NOT_SENT", "PENDING", "APPROVED", "REJECTED" })
{
var json = $"{{\"id\":\"x\",\"status\":\"{status}\"}}";
var result = JsonContractAssert.DeserializeFixture<AccountDocument>(json);
Assert.Equal(status, result.Status.ToString());
}
}

[Fact]
public void DocumentGroupStatus_AllFiveValuesDeserialize()
{
// Schema AccountDocumentGroupResponseDTO.status tem 5 valores
// (Group ganha IGNORED em relacao ao Document).
foreach (var status in new[] { "NOT_SENT", "PENDING", "APPROVED", "REJECTED", "IGNORED" })
{
var json = $"{{\"id\":\"x\",\"status\":\"{status}\",\"type\":\"CUSTOM\",\"documents\":[]}}";
var result = JsonContractAssert.DeserializeFixture<AccountDocumentGroup>(json);
Assert.Equal(status, result.Status.ToString());
}
}

[Fact]
public void DocumentType_AllTwelveValuesDeserialize()
{
var values = new[] {
"ALLOW_BANK_ACCOUNT_DEPOSIT_STATEMENT", "CUSTOM", "EMANCIPATION_OF_MINORS",
"ENTREPRENEUR_REQUIREMENT", "IDENTIFICATION_SELFIE", "IDENTIFICATION",
"INVOICE", "MEI_CERTIFICATE", "MINUTES_OF_CONSTITUTION",
"MINUTES_OF_ELECTION", "POWER_OF_ATTORNEY", "SOCIAL_CONTRACT"
};

foreach (var type in values)
{
var json = $"{{\"id\":\"x\",\"status\":\"NOT_SENT\",\"type\":\"{type}\",\"documents\":[]}}";
var result = JsonContractAssert.DeserializeFixture<AccountDocumentGroup>(json);
Assert.Equal(type, result.Type.ToString());
}
}

[Fact]
public void ResponsibleType_AllThirteenValuesDeserialize()
{
var values = new[] {
"ALLOW_BANK_ACCOUNT_DEPOSIT_STATEMENT", "ASAAS_ACCOUNT_OWNER_EMANCIPATION_AGE",
"ASAAS_ACCOUNT_OWNER", "ASSOCIATION", "BANK_ACCOUNT_OWNER_EMANCIPATION_AGE",
"BANK_ACCOUNT_OWNER", "CUSTOM", "DIRECTOR", "INDIVIDUAL_COMPANY",
"LIMITED_COMPANY", "MEI", "PARTNER", "POWER_OF_ATTORNEY"
};

foreach (var t in values)
{
var json = $"{{\"name\":\"John\",\"type\":[\"{t}\"]}}";
var result = JsonContractAssert.DeserializeFixture<AccountDocumentResponsible>(json);
Assert.Single(result.Type);
Assert.Equal(t, result.Type[0].ToString());
}
}

// ─────────────────────────────────────────────────────────────
// POST multipart request — B-20h regression
// Schema oficial: campos sao "documentFile" (binary) e "type" (enum).
// C# properties devem ser DocumentFile e Type (FirstCharToLower converte).
// ─────────────────────────────────────────────────────────────

[Fact]
public void UploadRequest_HasCorrectMultipartFieldNames()
{
// Reflexao sobre as propriedades: garantir que C# property names viram
// os field names esperados pelo schema apos firstCharToLower do BaseManager.
var props = typeof(UploadAccountDocumentRequest).GetProperties();
var names = new System.Collections.Generic.HashSet<string>();
foreach (var p in props)
{
var firstLower = char.ToLowerInvariant(p.Name[0]) + p.Name.Substring(1);
names.Add(firstLower);
}

Assert.Contains("documentFile", names);
Assert.Contains("type", names);

// Regressao B-20h: nao deve mais existir "file" (antes era File: IAsaasFile)
// nem "documentType" (antes era DocumentType: string).
Assert.DoesNotContain("file", names);
Assert.DoesNotContain("documentType", names);
}
}
60 changes: 60 additions & 0 deletions Codout.Apis.Asaas.Tests/Contract/AnticipationContractTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using Codout.Apis.Asaas.Models.Anticipation;
using Codout.Apis.Asaas.Models.Anticipation.Enums;

namespace Codout.Apis.Asaas.Tests.Contract;

/// <summary>
/// Contract tests para AnticipationManager (B-30).
/// Schemas verificados via MCP em 2026-05-24.
/// </summary>
public class AnticipationContractTests
{
[Fact]
public void AnticipationResponse_DeserializesFromOfficialFixture()
{
var json = FixtureLoader.Load("Anticipation/anticipation-response.json");

var result = JsonContractAssert.DeserializeFixture<Anticipation>(json);

Assert.Equal("receivableAnticipation", result.Object);
Assert.Equal("9e7d8639-350f-45c0-8bc3-d4ddc5f4ebac", result.Id);
Assert.Equal("pay_626366773834", result.PaymentId);
Assert.Null(result.InstallmentId);
Assert.Equal(AnticipationStatus.PENDING, result.Status);
Assert.Equal(new DateTime(2019, 5, 20), result.AnticipationDate);
Assert.Equal(new DateTime(2019, 5, 26), result.DueDate);
Assert.Equal(new DateTime(2019, 5, 14), result.RequestDate);
Assert.Equal(2.33m, result.Fee);
Assert.Equal(5, result.AnticipationDays);
Assert.Equal(73.68m, result.NetValue);
Assert.Equal(80m, result.TotalValue);
Assert.Equal(76.01m, result.Value);
Assert.Null(result.DenialObservation);
}

[Fact]
public void AnticipationResponse_NullableDatesHandleMissing()
{
// B-30a: AnticipationDate, DueDate, RequestDate eram non-nullable.
var json = "{\"id\":\"a_x\",\"status\":\"PENDING\"}";

var result = JsonContractAssert.DeserializeFixture<Anticipation>(json);

Assert.Null(result.AnticipationDate);
Assert.Null(result.DueDate);
Assert.Null(result.RequestDate);
}

[Fact]
public void AnticipationStatus_AllSevenValuesDeserialize()
{
foreach (var status in new[] {
"PENDING", "DENIED", "CREDITED", "DEBITED", "CANCELLED", "OVERDUE", "SCHEDULED" })
{
var json = $"{{\"id\":\"x\",\"status\":\"{status}\"}}";
var result = JsonContractAssert.DeserializeFixture<Anticipation>(json);
Assert.Equal(status, result.Status.ToString());
}
}
}
36 changes: 36 additions & 0 deletions Codout.Apis.Asaas.Tests/Contract/AsaasAccountContractTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using Codout.Apis.Asaas.Models.AsaasAccount;
using Codout.Apis.Asaas.Models.Common.Enums;

namespace Codout.Apis.Asaas.Tests.Contract;

/// <summary>
/// Contract tests para AsaasAccountManager (B-39).
/// Schemas verificados via MCP em 2026-05-24.
/// </summary>
public class AsaasAccountContractTests
{
[Fact]
public void AccountResponse_DeserializesAllFields()
{
var json = "{\"object\":\"account\",\"id\":\"4f468235-cec3-482f-b3d0-348af4c7194\",\"name\":\"John Doe\",\"email\":\"john.doe@asaas.com.br\",\"loginEmail\":\"john.doe@asaas.com.br\",\"phone\":null,\"mobilePhone\":null,\"address\":\"Rua Fernando Orlandi\",\"addressNumber\":\"544\",\"province\":\"Jardim Pedra Branca\",\"postalCode\":\"14079-452\",\"cpfCnpj\":\"35381637000150\",\"birthDate\":\"1995-04-12\",\"personType\":\"JURIDICA\",\"companyType\":\"MEI\",\"city\":15478,\"state\":\"SP\",\"country\":\"Brasil\",\"tradingName\":null,\"site\":\"https://www.example.com\",\"walletId\":\"c0c1688f-636b-42c0-b6ee-7339182276b7\",\"accountNumber\":{\"agency\":\"0001\",\"account\":\"3514\",\"accountDigit\":\"3\"},\"commercialInfoExpiration\":{\"isExpired\":false,\"scheduledDate\":\"2025-05-05 00:00:00\"}}";

var result = JsonContractAssert.DeserializeFixture<Account>(json);

Assert.Equal("account", result.Object);
Assert.Equal("4f468235-cec3-482f-b3d0-348af4c7194", result.Id);
Assert.Equal("John Doe", result.Name);
Assert.Equal(PersonType.JURIDICA, result.PersonType);
Assert.Equal(CompanyType.MEI, result.CompanyType);
// B-39a: City era string, agora int
Assert.Equal(15478L, result.City);
Assert.Equal("SP", result.State);
Assert.Equal(new DateTime(1995, 4, 12), result.BirthDate);
Assert.Equal("c0c1688f-636b-42c0-b6ee-7339182276b7", result.WalletId);
// B-39b: campos novos
Assert.NotNull(result.AccountNumber);
Assert.Equal("0001", result.AccountNumber.Agency);
Assert.NotNull(result.CommercialInfoExpiration);
Assert.False(result.CommercialInfoExpiration.IsExpired);
}
}
Loading
Loading