@polymorphism-tech/morph-spec 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +314 -1673
- package/LICENSE +72 -72
- package/README.md +515 -516
- package/bin/detect-agents.js +225 -225
- package/bin/morph-spec.js +358 -173
- package/bin/render-template.js +302 -302
- package/bin/semantic-detect-agents.js +246 -246
- package/bin/task-manager.js +429 -0
- package/bin/validate-agents-skills.js +251 -251
- package/bin/validate-agents.js +69 -69
- package/bin/validate-phase.js +263 -263
- package/bin/validate.js +369 -0
- package/content/.azure/README.md +293 -293
- package/content/.azure/docs/azure-devops-setup.md +454 -454
- package/content/.azure/docs/branch-strategy.md +398 -398
- package/content/.azure/docs/local-development.md +515 -515
- package/content/.azure/pipelines/pipeline-variables.yml +34 -34
- package/content/.azure/pipelines/prod-pipeline.yml +319 -319
- package/content/.azure/pipelines/staging-pipeline.yml +234 -234
- package/content/.azure/pipelines/templates/build-dotnet.yml +75 -75
- package/content/.azure/pipelines/templates/deploy-app-service.yml +94 -94
- package/content/.azure/pipelines/templates/deploy-container-app.yml +120 -120
- package/content/.azure/pipelines/templates/infra-deploy.yml +90 -90
- package/content/.claude/commands/morph-apply.md +221 -158
- package/content/.claude/commands/morph-archive.md +79 -79
- package/content/.claude/commands/morph-infra.md +209 -209
- package/content/.claude/commands/morph-preflight.md +227 -0
- package/content/.claude/commands/morph-proposal.md +122 -101
- package/content/.claude/commands/morph-status.md +86 -86
- package/content/.claude/commands/morph-troubleshoot.md +122 -0
- package/content/.claude/settings.local.json +15 -15
- package/content/.claude/skills/checklists/code-review.md +226 -0
- package/content/.claude/skills/checklists/morph-checklist.md +117 -0
- package/content/.claude/skills/checklists/simulation-checklist.md +77 -0
- package/content/.claude/skills/infra/bicep-architect.md +126 -419
- package/content/.claude/skills/infra/container-specialist.md +131 -437
- package/content/.claude/skills/infra/devops-engineer.md +119 -405
- package/content/.claude/skills/integrations/asaas-financial.md +130 -333
- package/content/.claude/skills/integrations/azure-identity.md +142 -309
- package/content/.claude/skills/integrations/clerk-auth.md +108 -290
- package/content/.claude/skills/integrations/resend-email.md +119 -0
- package/content/.claude/skills/specialists/ai-system-architect.md +192 -604
- package/content/.claude/skills/specialists/azure-architect.md +142 -142
- package/content/.claude/skills/specialists/code-analyzer.md +235 -0
- package/content/.claude/skills/specialists/dotnet-senior.md +287 -0
- package/content/.claude/skills/specialists/ef-modeler.md +113 -200
- package/content/.claude/skills/specialists/hangfire-orchestrator.md +126 -245
- package/content/.claude/skills/specialists/ms-agent-expert.md +109 -263
- package/content/.claude/skills/specialists/po-pm-advisor.md +197 -197
- package/content/.claude/skills/specialists/standards-architect.md +156 -78
- package/content/.claude/skills/specialists/testing-specialist.md +126 -0
- package/content/.claude/skills/specialists/ui-ux-designer.md +191 -1060
- package/content/.claude/skills/stacks/dotnet-blazor.md +210 -588
- package/content/.claude/skills/stacks/dotnet-nextjs.md +154 -402
- package/content/.claude/skills/workflows/morph-replicate.md +213 -0
- package/content/.claude/{commands/morph-clarify.md → skills/workflows/phase-clarify.md} +5 -58
- package/content/.claude/{commands/morph-design.md → skills/workflows/phase-design.md} +16 -86
- package/content/.claude/{commands/morph-setup.md → skills/workflows/phase-setup.md} +9 -17
- package/content/.claude/skills/workflows/phase-tasks.md +164 -0
- package/content/.claude/{commands/morph-uiux.md → skills/workflows/phase-uiux.md} +15 -88
- package/content/.morph/.morphversion +5 -5
- package/content/.morph/archive/.gitkeep +25 -25
- package/content/.morph/config/agents.json +378 -242
- package/content/.morph/config/config.template.json +89 -108
- package/content/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +392 -392
- package/content/.morph/docs/workflows/design-impl.md +37 -0
- package/content/.morph/docs/workflows/fast-track.md +29 -0
- package/content/.morph/docs/workflows/full-morph.md +76 -0
- package/content/.morph/docs/workflows/standard.md +44 -0
- package/content/.morph/docs/workflows/ui-refresh.md +39 -0
- package/content/.morph/examples/api-nextjs/README.md +241 -241
- package/content/.morph/examples/api-nextjs/contracts.ts +307 -307
- package/content/.morph/examples/api-nextjs/spec.md +399 -399
- package/content/.morph/examples/api-nextjs/tasks.md +168 -168
- package/content/.morph/examples/micro-saas/README.md +125 -125
- package/content/.morph/examples/micro-saas/contracts.cs +358 -358
- package/content/.morph/examples/micro-saas/decisions.md +246 -246
- package/content/.morph/examples/micro-saas/spec.md +236 -236
- package/content/.morph/examples/micro-saas/tasks.md +150 -150
- package/content/.morph/examples/multi-agent/README.md +309 -309
- package/content/.morph/examples/multi-agent/contracts.cs +433 -433
- package/content/.morph/examples/multi-agent/spec.md +479 -479
- package/content/.morph/examples/multi-agent/tasks.md +185 -185
- package/content/.morph/examples/scheduled-reports/decisions.md +158 -0
- package/content/.morph/examples/scheduled-reports/proposal.md +95 -0
- package/content/.morph/examples/scheduled-reports/spec.md +267 -0
- package/content/.morph/examples/state-v3.json +188 -0
- package/content/.morph/features/.gitkeep +25 -25
- package/content/.morph/hooks/README.md +190 -239
- package/content/.morph/hooks/pre-commit-agents.sh +24 -24
- package/content/.morph/hooks/pre-commit-all.sh +48 -48
- package/content/.morph/hooks/pre-commit-specs.sh +49 -49
- package/content/.morph/hooks/pre-commit-tests.sh +60 -60
- package/content/.morph/project.md +160 -160
- package/content/.morph/schemas/agent.schema.json +296 -296
- package/content/.morph/schemas/tasks.schema.json +220 -0
- package/content/.morph/specs/.gitkeep +20 -20
- package/content/.morph/standards/agent-framework-blazor-ui.md +359 -0
- package/content/.morph/standards/agent-framework-production.md +410 -0
- package/content/.morph/standards/agent-framework-setup.md +413 -453
- package/content/.morph/standards/agent-framework-workflows.md +349 -0
- package/content/.morph/standards/architecture.md +325 -325
- package/content/.morph/standards/azure.md +605 -379
- package/content/.morph/standards/coding.md +377 -377
- package/content/.morph/standards/dotnet10-migration.md +520 -494
- package/content/.morph/standards/fluent-ui-setup.md +590 -590
- package/content/.morph/standards/migration-guide.md +514 -514
- package/content/.morph/standards/passkeys-auth.md +423 -423
- package/content/.morph/standards/vector-search-rag.md +536 -536
- package/content/.morph/state.json +17 -17
- package/content/.morph/templates/FluentDesignTheme.cs +149 -149
- package/content/.morph/templates/MudTheme.cs +281 -281
- package/content/.morph/templates/agent.cs +163 -172
- package/content/.morph/templates/clarify-questions.md +159 -0
- package/content/.morph/templates/component.razor +239 -239
- package/content/.morph/templates/contracts/Commands.cs +74 -0
- package/content/.morph/templates/contracts/Entities.cs +25 -0
- package/content/.morph/templates/contracts/Queries.cs +74 -0
- package/content/.morph/templates/contracts/README.md +74 -0
- package/content/.morph/templates/contracts.cs +217 -217
- package/content/.morph/templates/decisions.md +123 -106
- package/content/.morph/templates/design-system.css +226 -226
- package/content/.morph/templates/infra/.dockerignore.example +89 -89
- package/content/.morph/templates/infra/Dockerfile.example +82 -82
- package/content/.morph/templates/infra/README.md +286 -286
- package/content/.morph/templates/infra/app-insights.bicep +63 -63
- package/content/.morph/templates/infra/app-service.bicep +164 -164
- package/content/.morph/templates/infra/container-app-env.bicep +49 -49
- package/content/.morph/templates/infra/container-app.bicep +156 -156
- package/content/.morph/templates/infra/deploy-checklist.md +426 -0
- package/content/.morph/templates/infra/deploy.ps1 +229 -229
- package/content/.morph/templates/infra/deploy.sh +208 -208
- package/content/.morph/templates/infra/key-vault.bicep +91 -91
- package/content/.morph/templates/infra/main.bicep +189 -189
- package/content/.morph/templates/infra/parameters.dev.json +29 -29
- package/content/.morph/templates/infra/parameters.prod.json +29 -29
- package/content/.morph/templates/infra/parameters.staging.json +29 -29
- package/content/.morph/templates/infra/sql-database.bicep +103 -103
- package/content/.morph/templates/infra/storage.bicep +106 -106
- package/content/.morph/templates/integrations/asaas-client.cs +387 -387
- package/content/.morph/templates/integrations/asaas-webhook.cs +351 -351
- package/content/.morph/templates/integrations/azure-identity-config.cs +288 -288
- package/content/.morph/templates/integrations/clerk-config.cs +258 -258
- package/content/.morph/templates/job.cs +171 -171
- package/content/.morph/templates/migration.cs +83 -83
- package/content/.morph/templates/proposal.md +141 -155
- package/content/.morph/templates/recap.md +94 -105
- package/content/.morph/templates/repository.cs +141 -141
- package/content/.morph/templates/saas/subscription.cs +347 -347
- package/content/.morph/templates/saas/tenant.cs +338 -338
- package/content/.morph/templates/service.cs +139 -139
- package/content/.morph/templates/simulation.md +353 -0
- package/content/.morph/templates/spec.md +149 -148
- package/content/.morph/templates/sprint-status.yaml +68 -68
- package/content/.morph/templates/state.template.json +222 -222
- package/content/.morph/templates/story.md +143 -143
- package/content/.morph/templates/tasks.md +257 -235
- package/content/.morph/templates/test.cs +239 -239
- package/content/.morph/templates/ui-components.md +362 -276
- package/content/.morph/templates/ui-design-system.md +286 -286
- package/content/.morph/templates/ui-flows.md +336 -336
- package/content/.morph/templates/ui-mockups.md +133 -133
- package/content/.morph/test-infra/example.bicep +59 -59
- package/content/CLAUDE.md +150 -442
- package/content/README.md +79 -79
- package/detectors/config-detector.js +223 -223
- package/detectors/conversation-analyzer.js +163 -163
- package/detectors/index.js +84 -84
- package/detectors/standards-generator.js +275 -275
- package/detectors/structure-detector.js +245 -250
- package/docs/README.md +144 -149
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +977 -977
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1048 -1048
- package/docs/api/scripts/collapse.js +38 -38
- package/docs/api/scripts/commonNav.js +28 -28
- package/docs/api/scripts/linenumber.js +25 -25
- package/docs/api/scripts/nav.js +12 -12
- package/docs/api/scripts/polyfill.js +3 -3
- package/docs/api/scripts/prettify/Apache-License-2.0.txt +202 -202
- package/docs/api/scripts/prettify/lang-css.js +2 -2
- package/docs/api/scripts/prettify/prettify.js +28 -28
- package/docs/api/scripts/search.js +98 -98
- package/docs/api/styles/jsdoc.css +776 -776
- package/docs/api/styles/prettify.css +80 -80
- package/docs/examples.md +328 -328
- package/docs/getting-started.md +301 -302
- package/docs/installation.md +361 -361
- package/docs/templates.md +418 -418
- package/docs/validation-checklist.md +265 -266
- package/package.json +80 -80
- package/scripts/postinstall.js +132 -132
- package/src/commands/advance-phase.js +183 -0
- package/src/commands/analyze-blazor-concurrency.js +193 -0
- package/src/commands/create-story.js +351 -351
- package/src/commands/detect-agents.js +139 -0
- package/src/commands/detect.js +104 -104
- package/src/commands/doctor.js +356 -280
- package/src/commands/generate.js +149 -149
- package/src/commands/init.js +258 -245
- package/src/commands/lint-fluent.js +352 -0
- package/src/commands/rollback-phase.js +185 -0
- package/src/commands/session-summary.js +291 -0
- package/src/commands/shard-spec.js +224 -224
- package/src/commands/sprint-status.js +250 -250
- package/src/commands/state.js +333 -333
- package/src/commands/sync.js +167 -167
- package/src/commands/task.js +78 -0
- package/src/commands/troubleshoot.js +222 -0
- package/src/commands/update.js +192 -159
- package/src/commands/validate-blazor-state.js +210 -0
- package/src/commands/validate-blazor.js +156 -0
- package/src/commands/validate-css.js +84 -0
- package/src/commands/validate-phase.js +221 -0
- package/src/lib/blazor-concurrency-analyzer.js +288 -0
- package/src/lib/blazor-state-validator.js +291 -0
- package/src/lib/blazor-validator.js +374 -0
- package/src/lib/complexity-analyzer.js +441 -292
- package/src/lib/continuous-validator.js +421 -0
- package/src/lib/css-validator.js +352 -0
- package/src/lib/decision-constraint-loader.js +109 -0
- package/src/lib/design-system-generator.js +298 -298
- package/src/lib/learning-system.js +520 -0
- package/src/lib/mockup-generator.js +366 -0
- package/src/lib/recap-generator.js +205 -0
- package/src/lib/state-manager.js +397 -340
- package/src/lib/troubleshoot-grep.js +194 -0
- package/src/lib/troubleshoot-index.js +144 -0
- package/src/lib/ui-detector.js +350 -0
- package/src/lib/validation-runner.js +231 -0
- package/src/lib/validators/architecture-validator.js +387 -0
- package/src/lib/validators/contract-compliance-validator.js +273 -0
- package/src/lib/validators/package-validator.js +360 -0
- package/src/lib/validators/ui-contrast-validator.js +422 -0
- package/src/utils/file-copier.js +179 -139
- package/src/utils/logger.js +32 -32
- package/src/utils/version-checker.js +175 -175
- package/content/.claude/commands/morph-costs.md +0 -206
- package/content/.claude/commands/morph-tasks.md +0 -319
- package/content/.claude/skills/specialists/cost-guardian.md +0 -110
- package/content/.claude/skills/stacks/shopify.md +0 -445
- package/content/.morph/config/azure-pricing.json +0 -70
- package/content/.morph/config/azure-pricing.schema.json +0 -50
- package/content/.morph/hooks/pre-commit-costs.sh +0 -91
- package/docs/api/cost-calculator.js.html +0 -513
- package/docs/api/design-system-generator.js.html +0 -382
- package/docs/api/global.html +0 -5263
- package/docs/api/index.html +0 -96
- package/docs/api/state-manager.js.html +0 -423
- package/src/commands/cost.js +0 -181
- package/src/commands/update-pricing.js +0 -206
- package/src/lib/cost-calculator.js +0 -429
|
@@ -1,387 +1,387 @@
|
|
|
1
|
-
// ==============================================================================
|
|
2
|
-
// MORPH-SPEC - Asaas Client Template
|
|
3
|
-
// HTTP Client para integração com Asaas API
|
|
4
|
-
// ==============================================================================
|
|
5
|
-
|
|
6
|
-
using System.Net.Http.Json;
|
|
7
|
-
using System.Text.Json.Serialization;
|
|
8
|
-
using Microsoft.Extensions.Logging;
|
|
9
|
-
using Microsoft.Extensions.Options;
|
|
10
|
-
|
|
11
|
-
namespace {{Namespace}}.Infrastructure.Services;
|
|
12
|
-
|
|
13
|
-
// ==============================================================================
|
|
14
|
-
// OPTIONS
|
|
15
|
-
// ==============================================================================
|
|
16
|
-
|
|
17
|
-
public class AsaasOptions
|
|
18
|
-
{
|
|
19
|
-
public const string SectionName = "Asaas";
|
|
20
|
-
|
|
21
|
-
/// <summary>
|
|
22
|
-
/// Base URL da API (sandbox ou produção)
|
|
23
|
-
/// Sandbox: https://sandbox.asaas.com/api/v3
|
|
24
|
-
/// Produção: https://www.asaas.com/api/v3
|
|
25
|
-
/// </summary>
|
|
26
|
-
public string BaseUrl { get; set; } = "https://sandbox.asaas.com/api/v3";
|
|
27
|
-
|
|
28
|
-
/// <summary>
|
|
29
|
-
/// API Key do Asaas
|
|
30
|
-
/// </summary>
|
|
31
|
-
public string ApiKey { get; set; } = string.Empty;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// ==============================================================================
|
|
35
|
-
// INTERFACE
|
|
36
|
-
// ==============================================================================
|
|
37
|
-
|
|
38
|
-
public interface IAsaasClient
|
|
39
|
-
{
|
|
40
|
-
// Customers
|
|
41
|
-
Task<AsaasCustomer> CreateCustomerAsync(CreateCustomerRequest request, CancellationToken ct = default);
|
|
42
|
-
Task<AsaasCustomer?> GetCustomerByIdAsync(string customerId, CancellationToken ct = default);
|
|
43
|
-
Task<AsaasCustomer?> GetCustomerByCpfCnpjAsync(string cpfCnpj, CancellationToken ct = default);
|
|
44
|
-
|
|
45
|
-
// Payments
|
|
46
|
-
Task<AsaasPayment> CreatePaymentAsync(CreatePaymentRequest request, CancellationToken ct = default);
|
|
47
|
-
Task<AsaasPayment?> GetPaymentAsync(string paymentId, CancellationToken ct = default);
|
|
48
|
-
Task<AsaasPixQrCode?> GetPixQrCodeAsync(string paymentId, CancellationToken ct = default);
|
|
49
|
-
|
|
50
|
-
// Subscriptions
|
|
51
|
-
Task<AsaasSubscription> CreateSubscriptionAsync(CreateSubscriptionRequest request, CancellationToken ct = default);
|
|
52
|
-
Task<AsaasSubscription?> GetSubscriptionAsync(string subscriptionId, CancellationToken ct = default);
|
|
53
|
-
Task CancelSubscriptionAsync(string subscriptionId, CancellationToken ct = default);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// ==============================================================================
|
|
57
|
-
// IMPLEMENTATION
|
|
58
|
-
// ==============================================================================
|
|
59
|
-
|
|
60
|
-
public class AsaasClient : IAsaasClient
|
|
61
|
-
{
|
|
62
|
-
private readonly HttpClient _httpClient;
|
|
63
|
-
private readonly ILogger<AsaasClient> _logger;
|
|
64
|
-
|
|
65
|
-
public AsaasClient(HttpClient httpClient, ILogger<AsaasClient> logger)
|
|
66
|
-
{
|
|
67
|
-
_httpClient = httpClient;
|
|
68
|
-
_logger = logger;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// =========================================================================
|
|
72
|
-
// CUSTOMERS
|
|
73
|
-
// =========================================================================
|
|
74
|
-
|
|
75
|
-
public async Task<AsaasCustomer> CreateCustomerAsync(CreateCustomerRequest request, CancellationToken ct = default)
|
|
76
|
-
{
|
|
77
|
-
_logger.LogInformation("Creating Asaas customer: {Name}", request.Name);
|
|
78
|
-
|
|
79
|
-
var response = await _httpClient.PostAsJsonAsync("customers", request, ct);
|
|
80
|
-
await EnsureSuccessAsync(response, "create customer");
|
|
81
|
-
|
|
82
|
-
return await response.Content.ReadFromJsonAsync<AsaasCustomer>(ct)
|
|
83
|
-
?? throw new AsaasException("Failed to deserialize customer response");
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
public async Task<AsaasCustomer?> GetCustomerByIdAsync(string customerId, CancellationToken ct = default)
|
|
87
|
-
{
|
|
88
|
-
var response = await _httpClient.GetAsync($"customers/{customerId}", ct);
|
|
89
|
-
|
|
90
|
-
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
91
|
-
return null;
|
|
92
|
-
|
|
93
|
-
await EnsureSuccessAsync(response, "get customer");
|
|
94
|
-
return await response.Content.ReadFromJsonAsync<AsaasCustomer>(ct);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
public async Task<AsaasCustomer?> GetCustomerByCpfCnpjAsync(string cpfCnpj, CancellationToken ct = default)
|
|
98
|
-
{
|
|
99
|
-
var response = await _httpClient.GetAsync($"customers?cpfCnpj={cpfCnpj}", ct);
|
|
100
|
-
await EnsureSuccessAsync(response, "search customer");
|
|
101
|
-
|
|
102
|
-
var result = await response.Content.ReadFromJsonAsync<AsaasListResponse<AsaasCustomer>>(ct);
|
|
103
|
-
return result?.Data?.FirstOrDefault();
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// =========================================================================
|
|
107
|
-
// PAYMENTS
|
|
108
|
-
// =========================================================================
|
|
109
|
-
|
|
110
|
-
public async Task<AsaasPayment> CreatePaymentAsync(CreatePaymentRequest request, CancellationToken ct = default)
|
|
111
|
-
{
|
|
112
|
-
_logger.LogInformation("Creating Asaas payment for customer {CustomerId}, type {BillingType}, value {Value}",
|
|
113
|
-
request.Customer, request.BillingType, request.Value);
|
|
114
|
-
|
|
115
|
-
var response = await _httpClient.PostAsJsonAsync("payments", request, ct);
|
|
116
|
-
await EnsureSuccessAsync(response, "create payment");
|
|
117
|
-
|
|
118
|
-
return await response.Content.ReadFromJsonAsync<AsaasPayment>(ct)
|
|
119
|
-
?? throw new AsaasException("Failed to deserialize payment response");
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
public async Task<AsaasPayment?> GetPaymentAsync(string paymentId, CancellationToken ct = default)
|
|
123
|
-
{
|
|
124
|
-
var response = await _httpClient.GetAsync($"payments/{paymentId}", ct);
|
|
125
|
-
|
|
126
|
-
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
127
|
-
return null;
|
|
128
|
-
|
|
129
|
-
await EnsureSuccessAsync(response, "get payment");
|
|
130
|
-
return await response.Content.ReadFromJsonAsync<AsaasPayment>(ct);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
public async Task<AsaasPixQrCode?> GetPixQrCodeAsync(string paymentId, CancellationToken ct = default)
|
|
134
|
-
{
|
|
135
|
-
var response = await _httpClient.GetAsync($"payments/{paymentId}/pixQrCode", ct);
|
|
136
|
-
|
|
137
|
-
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
138
|
-
return null;
|
|
139
|
-
|
|
140
|
-
await EnsureSuccessAsync(response, "get pix qrcode");
|
|
141
|
-
return await response.Content.ReadFromJsonAsync<AsaasPixQrCode>(ct);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// =========================================================================
|
|
145
|
-
// SUBSCRIPTIONS
|
|
146
|
-
// =========================================================================
|
|
147
|
-
|
|
148
|
-
public async Task<AsaasSubscription> CreateSubscriptionAsync(CreateSubscriptionRequest request, CancellationToken ct = default)
|
|
149
|
-
{
|
|
150
|
-
_logger.LogInformation("Creating Asaas subscription for customer {CustomerId}", request.Customer);
|
|
151
|
-
|
|
152
|
-
var response = await _httpClient.PostAsJsonAsync("subscriptions", request, ct);
|
|
153
|
-
await EnsureSuccessAsync(response, "create subscription");
|
|
154
|
-
|
|
155
|
-
return await response.Content.ReadFromJsonAsync<AsaasSubscription>(ct)
|
|
156
|
-
?? throw new AsaasException("Failed to deserialize subscription response");
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
public async Task<AsaasSubscription?> GetSubscriptionAsync(string subscriptionId, CancellationToken ct = default)
|
|
160
|
-
{
|
|
161
|
-
var response = await _httpClient.GetAsync($"subscriptions/{subscriptionId}", ct);
|
|
162
|
-
|
|
163
|
-
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
164
|
-
return null;
|
|
165
|
-
|
|
166
|
-
await EnsureSuccessAsync(response, "get subscription");
|
|
167
|
-
return await response.Content.ReadFromJsonAsync<AsaasSubscription>(ct);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
public async Task CancelSubscriptionAsync(string subscriptionId, CancellationToken ct = default)
|
|
171
|
-
{
|
|
172
|
-
_logger.LogInformation("Canceling Asaas subscription {SubscriptionId}", subscriptionId);
|
|
173
|
-
|
|
174
|
-
var response = await _httpClient.DeleteAsync($"subscriptions/{subscriptionId}", ct);
|
|
175
|
-
await EnsureSuccessAsync(response, "cancel subscription");
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// =========================================================================
|
|
179
|
-
// HELPERS
|
|
180
|
-
// =========================================================================
|
|
181
|
-
|
|
182
|
-
private async Task EnsureSuccessAsync(HttpResponseMessage response, string operation)
|
|
183
|
-
{
|
|
184
|
-
if (!response.IsSuccessStatusCode)
|
|
185
|
-
{
|
|
186
|
-
var error = await response.Content.ReadAsStringAsync();
|
|
187
|
-
_logger.LogError("Asaas API error during {Operation}: {StatusCode} - {Error}",
|
|
188
|
-
operation, response.StatusCode, error);
|
|
189
|
-
throw new AsaasException($"Failed to {operation}: {response.StatusCode} - {error}");
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// ==============================================================================
|
|
195
|
-
// DTOS
|
|
196
|
-
// ==============================================================================
|
|
197
|
-
|
|
198
|
-
public record CreateCustomerRequest
|
|
199
|
-
{
|
|
200
|
-
[JsonPropertyName("name")]
|
|
201
|
-
public required string Name { get; init; }
|
|
202
|
-
|
|
203
|
-
[JsonPropertyName("cpfCnpj")]
|
|
204
|
-
public required string CpfCnpj { get; init; }
|
|
205
|
-
|
|
206
|
-
[JsonPropertyName("email")]
|
|
207
|
-
public string? Email { get; init; }
|
|
208
|
-
|
|
209
|
-
[JsonPropertyName("phone")]
|
|
210
|
-
public string? Phone { get; init; }
|
|
211
|
-
|
|
212
|
-
[JsonPropertyName("mobilePhone")]
|
|
213
|
-
public string? MobilePhone { get; init; }
|
|
214
|
-
|
|
215
|
-
[JsonPropertyName("externalReference")]
|
|
216
|
-
public string? ExternalReference { get; init; }
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
public record CreatePaymentRequest
|
|
220
|
-
{
|
|
221
|
-
[JsonPropertyName("customer")]
|
|
222
|
-
public required string Customer { get; init; }
|
|
223
|
-
|
|
224
|
-
[JsonPropertyName("billingType")]
|
|
225
|
-
public required string BillingType { get; init; } // BOLETO, PIX, CREDIT_CARD
|
|
226
|
-
|
|
227
|
-
[JsonPropertyName("value")]
|
|
228
|
-
public required decimal Value { get; init; }
|
|
229
|
-
|
|
230
|
-
[JsonPropertyName("dueDate")]
|
|
231
|
-
public required string DueDate { get; init; } // yyyy-MM-dd
|
|
232
|
-
|
|
233
|
-
[JsonPropertyName("description")]
|
|
234
|
-
public string? Description { get; init; }
|
|
235
|
-
|
|
236
|
-
[JsonPropertyName("externalReference")]
|
|
237
|
-
public string? ExternalReference { get; init; }
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
public record CreateSubscriptionRequest
|
|
241
|
-
{
|
|
242
|
-
[JsonPropertyName("customer")]
|
|
243
|
-
public required string Customer { get; init; }
|
|
244
|
-
|
|
245
|
-
[JsonPropertyName("billingType")]
|
|
246
|
-
public required string BillingType { get; init; }
|
|
247
|
-
|
|
248
|
-
[JsonPropertyName("value")]
|
|
249
|
-
public required decimal Value { get; init; }
|
|
250
|
-
|
|
251
|
-
[JsonPropertyName("nextDueDate")]
|
|
252
|
-
public required string NextDueDate { get; init; }
|
|
253
|
-
|
|
254
|
-
[JsonPropertyName("cycle")]
|
|
255
|
-
public required string Cycle { get; init; } // MONTHLY, WEEKLY, BIWEEKLY, YEARLY
|
|
256
|
-
|
|
257
|
-
[JsonPropertyName("description")]
|
|
258
|
-
public string? Description { get; init; }
|
|
259
|
-
|
|
260
|
-
[JsonPropertyName("externalReference")]
|
|
261
|
-
public string? ExternalReference { get; init; }
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
public record AsaasCustomer
|
|
265
|
-
{
|
|
266
|
-
[JsonPropertyName("id")]
|
|
267
|
-
public string Id { get; init; } = string.Empty;
|
|
268
|
-
|
|
269
|
-
[JsonPropertyName("name")]
|
|
270
|
-
public string Name { get; init; } = string.Empty;
|
|
271
|
-
|
|
272
|
-
[JsonPropertyName("cpfCnpj")]
|
|
273
|
-
public string CpfCnpj { get; init; } = string.Empty;
|
|
274
|
-
|
|
275
|
-
[JsonPropertyName("email")]
|
|
276
|
-
public string? Email { get; init; }
|
|
277
|
-
|
|
278
|
-
[JsonPropertyName("externalReference")]
|
|
279
|
-
public string? ExternalReference { get; init; }
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
public record AsaasPayment
|
|
283
|
-
{
|
|
284
|
-
[JsonPropertyName("id")]
|
|
285
|
-
public string Id { get; init; } = string.Empty;
|
|
286
|
-
|
|
287
|
-
[JsonPropertyName("customer")]
|
|
288
|
-
public string Customer { get; init; } = string.Empty;
|
|
289
|
-
|
|
290
|
-
[JsonPropertyName("value")]
|
|
291
|
-
public decimal Value { get; init; }
|
|
292
|
-
|
|
293
|
-
[JsonPropertyName("status")]
|
|
294
|
-
public string Status { get; init; } = string.Empty;
|
|
295
|
-
|
|
296
|
-
[JsonPropertyName("billingType")]
|
|
297
|
-
public string BillingType { get; init; } = string.Empty;
|
|
298
|
-
|
|
299
|
-
[JsonPropertyName("dueDate")]
|
|
300
|
-
public string DueDate { get; init; } = string.Empty;
|
|
301
|
-
|
|
302
|
-
[JsonPropertyName("invoiceUrl")]
|
|
303
|
-
public string? InvoiceUrl { get; init; }
|
|
304
|
-
|
|
305
|
-
[JsonPropertyName("bankSlipUrl")]
|
|
306
|
-
public string? BankSlipUrl { get; init; }
|
|
307
|
-
|
|
308
|
-
[JsonPropertyName("externalReference")]
|
|
309
|
-
public string? ExternalReference { get; init; }
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
public record AsaasPixQrCode
|
|
313
|
-
{
|
|
314
|
-
[JsonPropertyName("encodedImage")]
|
|
315
|
-
public string? EncodedImage { get; init; }
|
|
316
|
-
|
|
317
|
-
[JsonPropertyName("payload")]
|
|
318
|
-
public string? Payload { get; init; }
|
|
319
|
-
|
|
320
|
-
[JsonPropertyName("expirationDate")]
|
|
321
|
-
public string? ExpirationDate { get; init; }
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
public record AsaasSubscription
|
|
325
|
-
{
|
|
326
|
-
[JsonPropertyName("id")]
|
|
327
|
-
public string Id { get; init; } = string.Empty;
|
|
328
|
-
|
|
329
|
-
[JsonPropertyName("customer")]
|
|
330
|
-
public string Customer { get; init; } = string.Empty;
|
|
331
|
-
|
|
332
|
-
[JsonPropertyName("value")]
|
|
333
|
-
public decimal Value { get; init; }
|
|
334
|
-
|
|
335
|
-
[JsonPropertyName("status")]
|
|
336
|
-
public string Status { get; init; } = string.Empty;
|
|
337
|
-
|
|
338
|
-
[JsonPropertyName("cycle")]
|
|
339
|
-
public string Cycle { get; init; } = string.Empty;
|
|
340
|
-
|
|
341
|
-
[JsonPropertyName("nextDueDate")]
|
|
342
|
-
public string NextDueDate { get; init; } = string.Empty;
|
|
343
|
-
|
|
344
|
-
[JsonPropertyName("externalReference")]
|
|
345
|
-
public string? ExternalReference { get; init; }
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
public record AsaasListResponse<T>
|
|
349
|
-
{
|
|
350
|
-
[JsonPropertyName("data")]
|
|
351
|
-
public List<T>? Data { get; init; }
|
|
352
|
-
|
|
353
|
-
[JsonPropertyName("totalCount")]
|
|
354
|
-
public int TotalCount { get; init; }
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// ==============================================================================
|
|
358
|
-
// EXCEPTION
|
|
359
|
-
// ==============================================================================
|
|
360
|
-
|
|
361
|
-
public class AsaasException : Exception
|
|
362
|
-
{
|
|
363
|
-
public AsaasException(string message) : base(message) { }
|
|
364
|
-
public AsaasException(string message, Exception innerException) : base(message, innerException) { }
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// ==============================================================================
|
|
368
|
-
// DEPENDENCY INJECTION
|
|
369
|
-
// ==============================================================================
|
|
370
|
-
|
|
371
|
-
public static class AsaasServiceExtensions
|
|
372
|
-
{
|
|
373
|
-
public static IServiceCollection AddAsaasClient(this IServiceCollection services, IConfiguration configuration)
|
|
374
|
-
{
|
|
375
|
-
services.Configure<AsaasOptions>(configuration.GetSection(AsaasOptions.SectionName));
|
|
376
|
-
|
|
377
|
-
services.AddHttpClient<IAsaasClient, AsaasClient>((sp, client) =>
|
|
378
|
-
{
|
|
379
|
-
var options = sp.GetRequiredService<IOptions<AsaasOptions>>().Value;
|
|
380
|
-
client.BaseAddress = new Uri(options.BaseUrl.TrimEnd('/') + "/");
|
|
381
|
-
client.DefaultRequestHeaders.Add("access_token", options.ApiKey);
|
|
382
|
-
client.DefaultRequestHeaders.Add("User-Agent", "MORPH-SPEC/1.0");
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
return services;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
1
|
+
// ==============================================================================
|
|
2
|
+
// MORPH-SPEC - Asaas Client Template
|
|
3
|
+
// HTTP Client para integração com Asaas API
|
|
4
|
+
// ==============================================================================
|
|
5
|
+
|
|
6
|
+
using System.Net.Http.Json;
|
|
7
|
+
using System.Text.Json.Serialization;
|
|
8
|
+
using Microsoft.Extensions.Logging;
|
|
9
|
+
using Microsoft.Extensions.Options;
|
|
10
|
+
|
|
11
|
+
namespace {{Namespace}}.Infrastructure.Services;
|
|
12
|
+
|
|
13
|
+
// ==============================================================================
|
|
14
|
+
// OPTIONS
|
|
15
|
+
// ==============================================================================
|
|
16
|
+
|
|
17
|
+
public class AsaasOptions
|
|
18
|
+
{
|
|
19
|
+
public const string SectionName = "Asaas";
|
|
20
|
+
|
|
21
|
+
/// <summary>
|
|
22
|
+
/// Base URL da API (sandbox ou produção)
|
|
23
|
+
/// Sandbox: https://sandbox.asaas.com/api/v3
|
|
24
|
+
/// Produção: https://www.asaas.com/api/v3
|
|
25
|
+
/// </summary>
|
|
26
|
+
public string BaseUrl { get; set; } = "https://sandbox.asaas.com/api/v3";
|
|
27
|
+
|
|
28
|
+
/// <summary>
|
|
29
|
+
/// API Key do Asaas
|
|
30
|
+
/// </summary>
|
|
31
|
+
public string ApiKey { get; set; } = string.Empty;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ==============================================================================
|
|
35
|
+
// INTERFACE
|
|
36
|
+
// ==============================================================================
|
|
37
|
+
|
|
38
|
+
public interface IAsaasClient
|
|
39
|
+
{
|
|
40
|
+
// Customers
|
|
41
|
+
Task<AsaasCustomer> CreateCustomerAsync(CreateCustomerRequest request, CancellationToken ct = default);
|
|
42
|
+
Task<AsaasCustomer?> GetCustomerByIdAsync(string customerId, CancellationToken ct = default);
|
|
43
|
+
Task<AsaasCustomer?> GetCustomerByCpfCnpjAsync(string cpfCnpj, CancellationToken ct = default);
|
|
44
|
+
|
|
45
|
+
// Payments
|
|
46
|
+
Task<AsaasPayment> CreatePaymentAsync(CreatePaymentRequest request, CancellationToken ct = default);
|
|
47
|
+
Task<AsaasPayment?> GetPaymentAsync(string paymentId, CancellationToken ct = default);
|
|
48
|
+
Task<AsaasPixQrCode?> GetPixQrCodeAsync(string paymentId, CancellationToken ct = default);
|
|
49
|
+
|
|
50
|
+
// Subscriptions
|
|
51
|
+
Task<AsaasSubscription> CreateSubscriptionAsync(CreateSubscriptionRequest request, CancellationToken ct = default);
|
|
52
|
+
Task<AsaasSubscription?> GetSubscriptionAsync(string subscriptionId, CancellationToken ct = default);
|
|
53
|
+
Task CancelSubscriptionAsync(string subscriptionId, CancellationToken ct = default);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ==============================================================================
|
|
57
|
+
// IMPLEMENTATION
|
|
58
|
+
// ==============================================================================
|
|
59
|
+
|
|
60
|
+
public class AsaasClient : IAsaasClient
|
|
61
|
+
{
|
|
62
|
+
private readonly HttpClient _httpClient;
|
|
63
|
+
private readonly ILogger<AsaasClient> _logger;
|
|
64
|
+
|
|
65
|
+
public AsaasClient(HttpClient httpClient, ILogger<AsaasClient> logger)
|
|
66
|
+
{
|
|
67
|
+
_httpClient = httpClient;
|
|
68
|
+
_logger = logger;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// =========================================================================
|
|
72
|
+
// CUSTOMERS
|
|
73
|
+
// =========================================================================
|
|
74
|
+
|
|
75
|
+
public async Task<AsaasCustomer> CreateCustomerAsync(CreateCustomerRequest request, CancellationToken ct = default)
|
|
76
|
+
{
|
|
77
|
+
_logger.LogInformation("Creating Asaas customer: {Name}", request.Name);
|
|
78
|
+
|
|
79
|
+
var response = await _httpClient.PostAsJsonAsync("customers", request, ct);
|
|
80
|
+
await EnsureSuccessAsync(response, "create customer");
|
|
81
|
+
|
|
82
|
+
return await response.Content.ReadFromJsonAsync<AsaasCustomer>(ct)
|
|
83
|
+
?? throw new AsaasException("Failed to deserialize customer response");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public async Task<AsaasCustomer?> GetCustomerByIdAsync(string customerId, CancellationToken ct = default)
|
|
87
|
+
{
|
|
88
|
+
var response = await _httpClient.GetAsync($"customers/{customerId}", ct);
|
|
89
|
+
|
|
90
|
+
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
91
|
+
return null;
|
|
92
|
+
|
|
93
|
+
await EnsureSuccessAsync(response, "get customer");
|
|
94
|
+
return await response.Content.ReadFromJsonAsync<AsaasCustomer>(ct);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public async Task<AsaasCustomer?> GetCustomerByCpfCnpjAsync(string cpfCnpj, CancellationToken ct = default)
|
|
98
|
+
{
|
|
99
|
+
var response = await _httpClient.GetAsync($"customers?cpfCnpj={cpfCnpj}", ct);
|
|
100
|
+
await EnsureSuccessAsync(response, "search customer");
|
|
101
|
+
|
|
102
|
+
var result = await response.Content.ReadFromJsonAsync<AsaasListResponse<AsaasCustomer>>(ct);
|
|
103
|
+
return result?.Data?.FirstOrDefault();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// =========================================================================
|
|
107
|
+
// PAYMENTS
|
|
108
|
+
// =========================================================================
|
|
109
|
+
|
|
110
|
+
public async Task<AsaasPayment> CreatePaymentAsync(CreatePaymentRequest request, CancellationToken ct = default)
|
|
111
|
+
{
|
|
112
|
+
_logger.LogInformation("Creating Asaas payment for customer {CustomerId}, type {BillingType}, value {Value}",
|
|
113
|
+
request.Customer, request.BillingType, request.Value);
|
|
114
|
+
|
|
115
|
+
var response = await _httpClient.PostAsJsonAsync("payments", request, ct);
|
|
116
|
+
await EnsureSuccessAsync(response, "create payment");
|
|
117
|
+
|
|
118
|
+
return await response.Content.ReadFromJsonAsync<AsaasPayment>(ct)
|
|
119
|
+
?? throw new AsaasException("Failed to deserialize payment response");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public async Task<AsaasPayment?> GetPaymentAsync(string paymentId, CancellationToken ct = default)
|
|
123
|
+
{
|
|
124
|
+
var response = await _httpClient.GetAsync($"payments/{paymentId}", ct);
|
|
125
|
+
|
|
126
|
+
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
127
|
+
return null;
|
|
128
|
+
|
|
129
|
+
await EnsureSuccessAsync(response, "get payment");
|
|
130
|
+
return await response.Content.ReadFromJsonAsync<AsaasPayment>(ct);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public async Task<AsaasPixQrCode?> GetPixQrCodeAsync(string paymentId, CancellationToken ct = default)
|
|
134
|
+
{
|
|
135
|
+
var response = await _httpClient.GetAsync($"payments/{paymentId}/pixQrCode", ct);
|
|
136
|
+
|
|
137
|
+
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
138
|
+
return null;
|
|
139
|
+
|
|
140
|
+
await EnsureSuccessAsync(response, "get pix qrcode");
|
|
141
|
+
return await response.Content.ReadFromJsonAsync<AsaasPixQrCode>(ct);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// =========================================================================
|
|
145
|
+
// SUBSCRIPTIONS
|
|
146
|
+
// =========================================================================
|
|
147
|
+
|
|
148
|
+
public async Task<AsaasSubscription> CreateSubscriptionAsync(CreateSubscriptionRequest request, CancellationToken ct = default)
|
|
149
|
+
{
|
|
150
|
+
_logger.LogInformation("Creating Asaas subscription for customer {CustomerId}", request.Customer);
|
|
151
|
+
|
|
152
|
+
var response = await _httpClient.PostAsJsonAsync("subscriptions", request, ct);
|
|
153
|
+
await EnsureSuccessAsync(response, "create subscription");
|
|
154
|
+
|
|
155
|
+
return await response.Content.ReadFromJsonAsync<AsaasSubscription>(ct)
|
|
156
|
+
?? throw new AsaasException("Failed to deserialize subscription response");
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public async Task<AsaasSubscription?> GetSubscriptionAsync(string subscriptionId, CancellationToken ct = default)
|
|
160
|
+
{
|
|
161
|
+
var response = await _httpClient.GetAsync($"subscriptions/{subscriptionId}", ct);
|
|
162
|
+
|
|
163
|
+
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
|
164
|
+
return null;
|
|
165
|
+
|
|
166
|
+
await EnsureSuccessAsync(response, "get subscription");
|
|
167
|
+
return await response.Content.ReadFromJsonAsync<AsaasSubscription>(ct);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
public async Task CancelSubscriptionAsync(string subscriptionId, CancellationToken ct = default)
|
|
171
|
+
{
|
|
172
|
+
_logger.LogInformation("Canceling Asaas subscription {SubscriptionId}", subscriptionId);
|
|
173
|
+
|
|
174
|
+
var response = await _httpClient.DeleteAsync($"subscriptions/{subscriptionId}", ct);
|
|
175
|
+
await EnsureSuccessAsync(response, "cancel subscription");
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// =========================================================================
|
|
179
|
+
// HELPERS
|
|
180
|
+
// =========================================================================
|
|
181
|
+
|
|
182
|
+
private async Task EnsureSuccessAsync(HttpResponseMessage response, string operation)
|
|
183
|
+
{
|
|
184
|
+
if (!response.IsSuccessStatusCode)
|
|
185
|
+
{
|
|
186
|
+
var error = await response.Content.ReadAsStringAsync();
|
|
187
|
+
_logger.LogError("Asaas API error during {Operation}: {StatusCode} - {Error}",
|
|
188
|
+
operation, response.StatusCode, error);
|
|
189
|
+
throw new AsaasException($"Failed to {operation}: {response.StatusCode} - {error}");
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ==============================================================================
|
|
195
|
+
// DTOS
|
|
196
|
+
// ==============================================================================
|
|
197
|
+
|
|
198
|
+
public record CreateCustomerRequest
|
|
199
|
+
{
|
|
200
|
+
[JsonPropertyName("name")]
|
|
201
|
+
public required string Name { get; init; }
|
|
202
|
+
|
|
203
|
+
[JsonPropertyName("cpfCnpj")]
|
|
204
|
+
public required string CpfCnpj { get; init; }
|
|
205
|
+
|
|
206
|
+
[JsonPropertyName("email")]
|
|
207
|
+
public string? Email { get; init; }
|
|
208
|
+
|
|
209
|
+
[JsonPropertyName("phone")]
|
|
210
|
+
public string? Phone { get; init; }
|
|
211
|
+
|
|
212
|
+
[JsonPropertyName("mobilePhone")]
|
|
213
|
+
public string? MobilePhone { get; init; }
|
|
214
|
+
|
|
215
|
+
[JsonPropertyName("externalReference")]
|
|
216
|
+
public string? ExternalReference { get; init; }
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public record CreatePaymentRequest
|
|
220
|
+
{
|
|
221
|
+
[JsonPropertyName("customer")]
|
|
222
|
+
public required string Customer { get; init; }
|
|
223
|
+
|
|
224
|
+
[JsonPropertyName("billingType")]
|
|
225
|
+
public required string BillingType { get; init; } // BOLETO, PIX, CREDIT_CARD
|
|
226
|
+
|
|
227
|
+
[JsonPropertyName("value")]
|
|
228
|
+
public required decimal Value { get; init; }
|
|
229
|
+
|
|
230
|
+
[JsonPropertyName("dueDate")]
|
|
231
|
+
public required string DueDate { get; init; } // yyyy-MM-dd
|
|
232
|
+
|
|
233
|
+
[JsonPropertyName("description")]
|
|
234
|
+
public string? Description { get; init; }
|
|
235
|
+
|
|
236
|
+
[JsonPropertyName("externalReference")]
|
|
237
|
+
public string? ExternalReference { get; init; }
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
public record CreateSubscriptionRequest
|
|
241
|
+
{
|
|
242
|
+
[JsonPropertyName("customer")]
|
|
243
|
+
public required string Customer { get; init; }
|
|
244
|
+
|
|
245
|
+
[JsonPropertyName("billingType")]
|
|
246
|
+
public required string BillingType { get; init; }
|
|
247
|
+
|
|
248
|
+
[JsonPropertyName("value")]
|
|
249
|
+
public required decimal Value { get; init; }
|
|
250
|
+
|
|
251
|
+
[JsonPropertyName("nextDueDate")]
|
|
252
|
+
public required string NextDueDate { get; init; }
|
|
253
|
+
|
|
254
|
+
[JsonPropertyName("cycle")]
|
|
255
|
+
public required string Cycle { get; init; } // MONTHLY, WEEKLY, BIWEEKLY, YEARLY
|
|
256
|
+
|
|
257
|
+
[JsonPropertyName("description")]
|
|
258
|
+
public string? Description { get; init; }
|
|
259
|
+
|
|
260
|
+
[JsonPropertyName("externalReference")]
|
|
261
|
+
public string? ExternalReference { get; init; }
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
public record AsaasCustomer
|
|
265
|
+
{
|
|
266
|
+
[JsonPropertyName("id")]
|
|
267
|
+
public string Id { get; init; } = string.Empty;
|
|
268
|
+
|
|
269
|
+
[JsonPropertyName("name")]
|
|
270
|
+
public string Name { get; init; } = string.Empty;
|
|
271
|
+
|
|
272
|
+
[JsonPropertyName("cpfCnpj")]
|
|
273
|
+
public string CpfCnpj { get; init; } = string.Empty;
|
|
274
|
+
|
|
275
|
+
[JsonPropertyName("email")]
|
|
276
|
+
public string? Email { get; init; }
|
|
277
|
+
|
|
278
|
+
[JsonPropertyName("externalReference")]
|
|
279
|
+
public string? ExternalReference { get; init; }
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
public record AsaasPayment
|
|
283
|
+
{
|
|
284
|
+
[JsonPropertyName("id")]
|
|
285
|
+
public string Id { get; init; } = string.Empty;
|
|
286
|
+
|
|
287
|
+
[JsonPropertyName("customer")]
|
|
288
|
+
public string Customer { get; init; } = string.Empty;
|
|
289
|
+
|
|
290
|
+
[JsonPropertyName("value")]
|
|
291
|
+
public decimal Value { get; init; }
|
|
292
|
+
|
|
293
|
+
[JsonPropertyName("status")]
|
|
294
|
+
public string Status { get; init; } = string.Empty;
|
|
295
|
+
|
|
296
|
+
[JsonPropertyName("billingType")]
|
|
297
|
+
public string BillingType { get; init; } = string.Empty;
|
|
298
|
+
|
|
299
|
+
[JsonPropertyName("dueDate")]
|
|
300
|
+
public string DueDate { get; init; } = string.Empty;
|
|
301
|
+
|
|
302
|
+
[JsonPropertyName("invoiceUrl")]
|
|
303
|
+
public string? InvoiceUrl { get; init; }
|
|
304
|
+
|
|
305
|
+
[JsonPropertyName("bankSlipUrl")]
|
|
306
|
+
public string? BankSlipUrl { get; init; }
|
|
307
|
+
|
|
308
|
+
[JsonPropertyName("externalReference")]
|
|
309
|
+
public string? ExternalReference { get; init; }
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
public record AsaasPixQrCode
|
|
313
|
+
{
|
|
314
|
+
[JsonPropertyName("encodedImage")]
|
|
315
|
+
public string? EncodedImage { get; init; }
|
|
316
|
+
|
|
317
|
+
[JsonPropertyName("payload")]
|
|
318
|
+
public string? Payload { get; init; }
|
|
319
|
+
|
|
320
|
+
[JsonPropertyName("expirationDate")]
|
|
321
|
+
public string? ExpirationDate { get; init; }
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
public record AsaasSubscription
|
|
325
|
+
{
|
|
326
|
+
[JsonPropertyName("id")]
|
|
327
|
+
public string Id { get; init; } = string.Empty;
|
|
328
|
+
|
|
329
|
+
[JsonPropertyName("customer")]
|
|
330
|
+
public string Customer { get; init; } = string.Empty;
|
|
331
|
+
|
|
332
|
+
[JsonPropertyName("value")]
|
|
333
|
+
public decimal Value { get; init; }
|
|
334
|
+
|
|
335
|
+
[JsonPropertyName("status")]
|
|
336
|
+
public string Status { get; init; } = string.Empty;
|
|
337
|
+
|
|
338
|
+
[JsonPropertyName("cycle")]
|
|
339
|
+
public string Cycle { get; init; } = string.Empty;
|
|
340
|
+
|
|
341
|
+
[JsonPropertyName("nextDueDate")]
|
|
342
|
+
public string NextDueDate { get; init; } = string.Empty;
|
|
343
|
+
|
|
344
|
+
[JsonPropertyName("externalReference")]
|
|
345
|
+
public string? ExternalReference { get; init; }
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
public record AsaasListResponse<T>
|
|
349
|
+
{
|
|
350
|
+
[JsonPropertyName("data")]
|
|
351
|
+
public List<T>? Data { get; init; }
|
|
352
|
+
|
|
353
|
+
[JsonPropertyName("totalCount")]
|
|
354
|
+
public int TotalCount { get; init; }
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ==============================================================================
|
|
358
|
+
// EXCEPTION
|
|
359
|
+
// ==============================================================================
|
|
360
|
+
|
|
361
|
+
public class AsaasException : Exception
|
|
362
|
+
{
|
|
363
|
+
public AsaasException(string message) : base(message) { }
|
|
364
|
+
public AsaasException(string message, Exception innerException) : base(message, innerException) { }
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// ==============================================================================
|
|
368
|
+
// DEPENDENCY INJECTION
|
|
369
|
+
// ==============================================================================
|
|
370
|
+
|
|
371
|
+
public static class AsaasServiceExtensions
|
|
372
|
+
{
|
|
373
|
+
public static IServiceCollection AddAsaasClient(this IServiceCollection services, IConfiguration configuration)
|
|
374
|
+
{
|
|
375
|
+
services.Configure<AsaasOptions>(configuration.GetSection(AsaasOptions.SectionName));
|
|
376
|
+
|
|
377
|
+
services.AddHttpClient<IAsaasClient, AsaasClient>((sp, client) =>
|
|
378
|
+
{
|
|
379
|
+
var options = sp.GetRequiredService<IOptions<AsaasOptions>>().Value;
|
|
380
|
+
client.BaseAddress = new Uri(options.BaseUrl.TrimEnd('/') + "/");
|
|
381
|
+
client.DefaultRequestHeaders.Add("access_token", options.ApiKey);
|
|
382
|
+
client.DefaultRequestHeaders.Add("User-Agent", "MORPH-SPEC/1.0");
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
return services;
|
|
386
|
+
}
|
|
387
|
+
}
|