@orechio/platform-angular 0.6.0 → 0.7.1

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.
Files changed (37) hide show
  1. package/README.md +134 -64
  2. package/fesm2022/orechio-platform-angular-account-account-client-mPl0tzMg.mjs.map +1 -1
  3. package/fesm2022/{orechio-platform-angular-account-forgot-password.page-5_8R5B4m.mjs → orechio-platform-angular-account-forgot-password.page-L-Z-s49p.mjs} +85 -85
  4. package/fesm2022/orechio-platform-angular-account-forgot-password.page-L-Z-s49p.mjs.map +1 -0
  5. package/fesm2022/{orechio-platform-angular-account-initial-branch.page-Cmy07JGF.mjs → orechio-platform-angular-account-initial-branch.page-C8a1eU3L.mjs} +61 -61
  6. package/fesm2022/orechio-platform-angular-account-initial-branch.page-C8a1eU3L.mjs.map +1 -0
  7. package/fesm2022/{orechio-platform-angular-account-resend-verification.page-qckKAlPk.mjs → orechio-platform-angular-account-resend-verification.page-C3lk1vNj.mjs} +69 -69
  8. package/fesm2022/orechio-platform-angular-account-resend-verification.page-C3lk1vNj.mjs.map +1 -0
  9. package/fesm2022/{orechio-platform-angular-account-token-password.page-AHqb8mFk.mjs → orechio-platform-angular-account-token-password.page-1vn5XGVu.mjs} +73 -73
  10. package/fesm2022/orechio-platform-angular-account-token-password.page-1vn5XGVu.mjs.map +1 -0
  11. package/fesm2022/{orechio-platform-angular-account-verify-email.page-CHs0EwDf.mjs → orechio-platform-angular-account-verify-email.page-xulVDiOn.mjs} +35 -35
  12. package/fesm2022/orechio-platform-angular-account-verify-email.page-xulVDiOn.mjs.map +1 -0
  13. package/fesm2022/orechio-platform-angular-account.mjs +6 -6
  14. package/fesm2022/orechio-platform-angular-account.mjs.map +1 -1
  15. package/fesm2022/orechio-platform-angular-billing-billing-format-0nlddK-x.mjs +194 -0
  16. package/fesm2022/orechio-platform-angular-billing-billing-format-0nlddK-x.mjs.map +1 -0
  17. package/fesm2022/orechio-platform-angular-billing-checkout.page-CHU_Drpu.mjs +186 -0
  18. package/fesm2022/orechio-platform-angular-billing-checkout.page-CHU_Drpu.mjs.map +1 -0
  19. package/fesm2022/orechio-platform-angular-billing-invoice.page-BVyWur3o.mjs +136 -0
  20. package/fesm2022/orechio-platform-angular-billing-invoice.page-BVyWur3o.mjs.map +1 -0
  21. package/fesm2022/orechio-platform-angular-billing-invoices.page-BiEm3hRf.mjs +105 -0
  22. package/fesm2022/orechio-platform-angular-billing-invoices.page-BiEm3hRf.mjs.map +1 -0
  23. package/fesm2022/orechio-platform-angular-billing-pix-panel.component-B608dQmc.mjs +81 -0
  24. package/fesm2022/orechio-platform-angular-billing-pix-panel.component-B608dQmc.mjs.map +1 -0
  25. package/fesm2022/orechio-platform-angular-billing-profile.page-Baa6uoM6.mjs +282 -0
  26. package/fesm2022/orechio-platform-angular-billing-profile.page-Baa6uoM6.mjs.map +1 -0
  27. package/fesm2022/orechio-platform-angular-billing-subscription.page-9NF8bWhu.mjs +160 -0
  28. package/fesm2022/orechio-platform-angular-billing-subscription.page-9NF8bWhu.mjs.map +1 -0
  29. package/fesm2022/orechio-platform-angular-billing.mjs +69 -0
  30. package/fesm2022/orechio-platform-angular-billing.mjs.map +1 -0
  31. package/package.json +5 -1
  32. package/types/orechio-platform-angular-billing.d.ts +32 -0
  33. package/fesm2022/orechio-platform-angular-account-forgot-password.page-5_8R5B4m.mjs.map +0 -1
  34. package/fesm2022/orechio-platform-angular-account-initial-branch.page-Cmy07JGF.mjs.map +0 -1
  35. package/fesm2022/orechio-platform-angular-account-resend-verification.page-qckKAlPk.mjs.map +0 -1
  36. package/fesm2022/orechio-platform-angular-account-token-password.page-AHqb8mFk.mjs.map +0 -1
  37. package/fesm2022/orechio-platform-angular-account-verify-email.page-CHs0EwDf.mjs.map +0 -1
@@ -0,0 +1,194 @@
1
+ import { HttpClient, HttpParams } from '@angular/common/http';
2
+ import * as i0 from '@angular/core';
3
+ import { inject, Injectable, input, computed, ChangeDetectionStrategy, Component } from '@angular/core';
4
+ import { catchError, throwError } from 'rxjs';
5
+ import { normalizeProblemDetails } from '@orechio/platform-angular';
6
+ import { ORECHIO_BILLING_CONFIG } from './orechio-platform-angular-billing.mjs';
7
+
8
+ /**
9
+ * O cliente do BFF de cobrança (`Orechio.Platform.Bff.Account` 0.2.0,
10
+ * `MapOrechioBillingEndpoints`). Same-origin, só com o BFF do host — mesmo desenho do
11
+ * `AccountClient`, e o erro sai pelo mesmo `normalizeProblemDetails`.
12
+ */
13
+ class BillingClient {
14
+ http = inject(HttpClient);
15
+ config = inject(ORECHIO_BILLING_CONFIG);
16
+ getSubscription() {
17
+ return this.falha(this.http.get(this.url('/subscription')));
18
+ }
19
+ getProfile() {
20
+ return this.falha(this.http.get(this.url('/profile')));
21
+ }
22
+ createProfile(request) {
23
+ return this.falha(this.http.post(this.url('/profile'), request));
24
+ }
25
+ updateProfileContact(request) {
26
+ return this.falha(this.http.patch(this.url('/profile/contact'), request));
27
+ }
28
+ updateProfileAddress(request) {
29
+ return this.falha(this.http.patch(this.url('/profile/address'), request));
30
+ }
31
+ listPlans() {
32
+ return this.falha(this.http.get(this.url('/plans')));
33
+ }
34
+ previewPricing(planId, branchCount, cycle) {
35
+ const params = new HttpParams({ fromObject: { planId, branchCount, cycle } });
36
+ return this.falha(this.http.get(this.url('/pricing/preview'), { params }));
37
+ }
38
+ /**
39
+ * Checkout PIX. O corpo é o `CheckoutRequest` da Platform (`cycle`, `method`), sem
40
+ * `applicationId`: com o token de produto, a Platform usa o app do token.
41
+ */
42
+ checkout(cycle) {
43
+ return this.falha(this.http.post(this.url('/checkout'), { cycle, method: 'pix' }));
44
+ }
45
+ listInvoices(page = 1, pageSize = 20) {
46
+ const params = new HttpParams({ fromObject: { page, pageSize } });
47
+ return this.falha(this.http.get(this.url('/invoices'), { params }));
48
+ }
49
+ getInvoice(id) {
50
+ return this.falha(this.http.get(this.url(`/invoices/${encodeURIComponent(id)}`)));
51
+ }
52
+ refreshInvoicePix(id) {
53
+ return this.falha(this.http.post(this.url(`/invoices/${encodeURIComponent(id)}/refresh`), null));
54
+ }
55
+ url(path) {
56
+ return `${this.config.basePath}${path}`;
57
+ }
58
+ falha(chamada) {
59
+ return chamada.pipe(catchError((error) => throwError(() => normalizeProblemDetails(error))));
60
+ }
61
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: BillingClient, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
62
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: BillingClient, providedIn: 'root' });
63
+ }
64
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: BillingClient, decorators: [{
65
+ type: Injectable,
66
+ args: [{ providedIn: 'root' }]
67
+ }] });
68
+
69
+ const ENDERECO_INCOMPLETO = 'Preencha o endereço completo.';
70
+ const DOCUMENTO_INVALIDO = 'CPF ou CNPJ inválido.';
71
+ const DOCUMENTO_TRAVADO = 'O documento e o nome já foram usados em uma cobrança e não podem mais ser alterados.';
72
+ const PLANO_INDISPONIVEL = 'O plano da assinatura não está disponível. Fale com o suporte.';
73
+ const SO_O_TITULAR = 'Só o titular da conta pode ver e pagar a cobrança.';
74
+ /**
75
+ * Os codes que as rotas de cobrança da Platform e do BFF emitem de fato
76
+ * (`Commerce*Endpoints`, handlers de `Billing/`, value objects de perfil,
77
+ * `PermissionAuthorization`, `Bff.Account`).
78
+ */
79
+ const MENSAGENS = {
80
+ 'session.missing': 'Sua sessão expirou. Entre novamente para continuar.',
81
+ 'platform.unavailable': 'O serviço de cobrança está indisponível no momento. Tente novamente em instantes.',
82
+ 'http.0': 'Sem conexão com o servidor. Verifique sua internet e tente novamente.',
83
+ rate_limit_exceeded: 'Muitas tentativas. Aguarde alguns minutos e tente novamente.',
84
+ 'access.platform_only': SO_O_TITULAR,
85
+ 'permission.denied': SO_O_TITULAR,
86
+ 'subscription.not_found': 'Nenhuma assinatura encontrada para esta conta.',
87
+ 'billing_profile.not_found': 'Cadastre os dados de cobrança antes de pagar.',
88
+ 'billing_profile.already_exists': 'Os dados de cobrança já estão cadastrados.',
89
+ 'billing_profile.legal_name_required': 'Informe o nome completo ou a razão social.',
90
+ 'billing_profile.billing_email_required': 'Informe o e-mail de cobrança.',
91
+ 'billing_profile.billing_email_invalid': 'Informe um e-mail de cobrança válido.',
92
+ 'billing_profile.mobile_phone_too_long': 'O celular informado é longo demais.',
93
+ 'billing_profile.document_type_locked': DOCUMENTO_TRAVADO,
94
+ 'billing_profile.document_number_locked': DOCUMENTO_TRAVADO,
95
+ 'billing_profile.legal_name_locked': DOCUMENTO_TRAVADO,
96
+ 'tax_document.value_required': 'Informe o CPF ou o CNPJ.',
97
+ 'tax_document.length_invalid': DOCUMENTO_INVALIDO,
98
+ 'tax_document.checksum_invalid': DOCUMENTO_INVALIDO,
99
+ 'address.postal_code_invalid': 'CEP inválido.',
100
+ 'address.state_invalid': 'UF inválida. Use a sigla do estado, como SP.',
101
+ 'address.street_required': ENDERECO_INCOMPLETO,
102
+ 'address.number_required': ENDERECO_INCOMPLETO,
103
+ 'address.neighborhood_required': ENDERECO_INCOMPLETO,
104
+ 'address.city_required': ENDERECO_INCOMPLETO,
105
+ 'checkout.subscription_not_eligible': 'Não há pagamento de assinatura a fazer agora. Veja as faturas em aberto.',
106
+ 'checkout.open_invoice_exists': 'Já existe uma fatura em aberto. Pague a fatura em aberto em vez de gerar uma nova cobrança.',
107
+ 'checkout.pending_other_method': 'Já existe uma cobrança em aberto por outro meio de pagamento. Veja as faturas.',
108
+ 'checkout.credit_card_not_supported': 'Pagamento por cartão ainda não está disponível.',
109
+ 'checkout.invoice_in_inconsistent_state': 'A cobrança anterior ficou incompleta. Tente novamente em alguns minutos.',
110
+ 'billing.cycle_invalid': 'Escolha um ciclo de cobrança válido.',
111
+ 'pricing_preview.cycle_invalid': 'Escolha um ciclo de cobrança válido.',
112
+ 'plan.not_found': PLANO_INDISPONIVEL,
113
+ 'plan.not_available': PLANO_INDISPONIVEL,
114
+ 'subscription.plan_inactive': PLANO_INDISPONIVEL,
115
+ 'invoice.not_found': 'Fatura não encontrada.',
116
+ 'invoice.payment_unavailable': 'Esta cobrança não está mais disponível para pagamento. Fale com o suporte.',
117
+ 'invoice.refresh_not_allowed': 'Esta fatura não está mais em aberto.',
118
+ 'invoice.refresh_pix_only': 'Só é possível gerar QR para faturas PIX.',
119
+ 'invoice.no_external_payment': 'Esta fatura ainda não tem cobrança gerada. Tente novamente em alguns minutos.',
120
+ };
121
+ const GENERICA = 'Não foi possível concluir a operação. Tente novamente; se continuar, informe o código de atendimento ao suporte.';
122
+ /**
123
+ * O texto de tela para um erro do BFF, escolhido por `code`. O corpo do erro (`message`) nunca
124
+ * vira texto: ele é escrito para log, não para o cliente.
125
+ */
126
+ function mensagemDeErro(problema) {
127
+ const conhecida = MENSAGENS[problema.code];
128
+ if (conhecida)
129
+ return { texto: conhecida };
130
+ return problema.correlationId
131
+ ? { texto: GENERICA, correlationId: problema.correlationId }
132
+ : { texto: GENERICA };
133
+ }
134
+
135
+ class BillingErrorComponent {
136
+ problema = input.required(/* @ts-ignore */
137
+ ...(ngDevMode ? [{ debugName: "problema" }] : /* istanbul ignore next */ []));
138
+ mensagem = computed(() => mensagemDeErro(this.problema()), /* @ts-ignore */
139
+ ...(ngDevMode ? [{ debugName: "mensagem" }] : /* istanbul ignore next */ []));
140
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: BillingErrorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
141
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: BillingErrorComponent, isStandalone: true, selector: "orechio-billing-error", inputs: { problema: { classPropertyName: "problema", publicName: "problema", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
142
+ <div class="orechio-billing__error" role="alert">
143
+ <p>{{ mensagem().texto }}</p>
144
+ @if (mensagem().correlationId; as id) {
145
+ <p>Código de atendimento: <code>{{ id }}</code></p>
146
+ }
147
+ </div>
148
+ `, isInline: true, styles: [".orechio-billing__error{color:var(--orechio-color-danger, #b00020)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
149
+ }
150
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: BillingErrorComponent, decorators: [{
151
+ type: Component,
152
+ args: [{ selector: 'orechio-billing-error', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
153
+ <div class="orechio-billing__error" role="alert">
154
+ <p>{{ mensagem().texto }}</p>
155
+ @if (mensagem().correlationId; as id) {
156
+ <p>Código de atendimento: <code>{{ id }}</code></p>
157
+ }
158
+ </div>
159
+ `, styles: [".orechio-billing__error{color:var(--orechio-color-danger, #b00020)}\n"] }]
160
+ }], propDecorators: { problema: [{ type: i0.Input, args: [{ isSignal: true, alias: "problema", required: true }] }] } });
161
+
162
+ const MOEDA = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' });
163
+ function moeda(valor) {
164
+ return MOEDA.format(valor);
165
+ }
166
+ function data(iso) {
167
+ return iso ? new Date(iso).toLocaleDateString('pt-BR') : '';
168
+ }
169
+ const STATUS_DA_FATURA = {
170
+ Created: 'Em emissão',
171
+ Pending: 'Em aberto',
172
+ Paid: 'Paga',
173
+ Overdue: 'Vencida',
174
+ Refunded: 'Estornada',
175
+ Cancelled: 'Cancelada',
176
+ };
177
+ const ESTILO_BASE = `
178
+ .orechio-billing {
179
+ display: flex;
180
+ flex-direction: column;
181
+ gap: var(--orechio-space-3, 0.75rem);
182
+ max-width: 40rem;
183
+ margin: 0 auto;
184
+ padding: var(--orechio-space-6, 1.5rem);
185
+ color: var(--orechio-color-text, inherit);
186
+ font-family: var(--orechio-font-body, inherit);
187
+ }
188
+ .orechio-billing form { display: flex; flex-direction: column; gap: var(--orechio-space-2, 0.5rem); }
189
+ .orechio-billing__muted { color: var(--orechio-color-text-muted, #666); }
190
+ .orechio-billing__error { color: var(--orechio-color-danger, #b00020); }
191
+ `;
192
+
193
+ export { BillingClient as B, STATUS_DA_FATURA as S, BillingErrorComponent as a, data as d, moeda as m };
194
+ //# sourceMappingURL=orechio-platform-angular-billing-billing-format-0nlddK-x.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orechio-platform-angular-billing-billing-format-0nlddK-x.mjs","sources":["../../../projects/platform-angular/billing/src/billing-client.ts","../../../projects/platform-angular/billing/src/billing-errors.ts","../../../projects/platform-angular/billing/src/billing-error.component.ts","../../../projects/platform-angular/billing/src/billing-format.ts"],"sourcesContent":["import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http';\r\nimport { Injectable, inject } from '@angular/core';\r\nimport { Observable, catchError, throwError } from 'rxjs';\r\nimport { ProblemDetails, normalizeProblemDetails } from '@orechio/platform-angular';\r\nimport { ORECHIO_BILLING_CONFIG } from './billing-config';\r\nimport {\r\n BillingAddressRequest,\r\n BillingContactRequest,\r\n BillingCycle,\r\n BillingProfile,\r\n CheckoutResult,\r\n CreateBillingProfileRequest,\r\n InvoiceDetail,\r\n InvoicesPage,\r\n Plan,\r\n PricingPreview,\r\n RefreshedPayment,\r\n Subscription,\r\n} from './billing-models';\r\n\r\n/**\r\n * O cliente do BFF de cobrança (`Orechio.Platform.Bff.Account` 0.2.0,\r\n * `MapOrechioBillingEndpoints`). Same-origin, só com o BFF do host — mesmo desenho do\r\n * `AccountClient`, e o erro sai pelo mesmo `normalizeProblemDetails`.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class BillingClient {\r\n private readonly http = inject(HttpClient);\r\n private readonly config = inject(ORECHIO_BILLING_CONFIG);\r\n\r\n getSubscription(): Observable<Subscription> {\r\n return this.falha(this.http.get<Subscription>(this.url('/subscription')));\r\n }\r\n\r\n getProfile(): Observable<BillingProfile> {\r\n return this.falha(this.http.get<BillingProfile>(this.url('/profile')));\r\n }\r\n\r\n createProfile(request: CreateBillingProfileRequest): Observable<{ id: string }> {\r\n return this.falha(this.http.post<{ id: string }>(this.url('/profile'), request));\r\n }\r\n\r\n updateProfileContact(request: BillingContactRequest): Observable<void> {\r\n return this.falha(this.http.patch<void>(this.url('/profile/contact'), request));\r\n }\r\n\r\n updateProfileAddress(request: BillingAddressRequest): Observable<void> {\r\n return this.falha(this.http.patch<void>(this.url('/profile/address'), request));\r\n }\r\n\r\n listPlans(): Observable<Plan[]> {\r\n return this.falha(this.http.get<Plan[]>(this.url('/plans')));\r\n }\r\n\r\n previewPricing(planId: string, branchCount: number, cycle: BillingCycle): Observable<PricingPreview> {\r\n const params = new HttpParams({ fromObject: { planId, branchCount, cycle } });\r\n return this.falha(this.http.get<PricingPreview>(this.url('/pricing/preview'), { params }));\r\n }\r\n\r\n /**\r\n * Checkout PIX. O corpo é o `CheckoutRequest` da Platform (`cycle`, `method`), sem\r\n * `applicationId`: com o token de produto, a Platform usa o app do token.\r\n */\r\n checkout(cycle: BillingCycle): Observable<CheckoutResult> {\r\n return this.falha(this.http.post<CheckoutResult>(this.url('/checkout'), { cycle, method: 'pix' }));\r\n }\r\n\r\n listInvoices(page = 1, pageSize = 20): Observable<InvoicesPage> {\r\n const params = new HttpParams({ fromObject: { page, pageSize } });\r\n return this.falha(this.http.get<InvoicesPage>(this.url('/invoices'), { params }));\r\n }\r\n\r\n getInvoice(id: string): Observable<InvoiceDetail> {\r\n return this.falha(this.http.get<InvoiceDetail>(this.url(`/invoices/${encodeURIComponent(id)}`)));\r\n }\r\n\r\n refreshInvoicePix(id: string): Observable<RefreshedPayment> {\r\n return this.falha(this.http.post<RefreshedPayment>(this.url(`/invoices/${encodeURIComponent(id)}/refresh`), null));\r\n }\r\n\r\n private url(path: string): string {\r\n return `${this.config.basePath}${path}`;\r\n }\r\n\r\n private falha<T>(chamada: Observable<T>): Observable<T> {\r\n return chamada.pipe(\r\n catchError((error: HttpErrorResponse) =>\r\n throwError((): ProblemDetails => normalizeProblemDetails(error)),\r\n ),\r\n );\r\n }\r\n}\r\n","import { ProblemDetails } from '@orechio/platform-angular';\r\n\r\nexport interface MensagemDeErro {\r\n texto: string;\r\n /** Só para code desconhecido: é o que o suporte cruza com o log dos dois lados. */\r\n correlationId?: string;\r\n}\r\n\r\nconst ENDERECO_INCOMPLETO = 'Preencha o endereço completo.';\r\nconst DOCUMENTO_INVALIDO = 'CPF ou CNPJ inválido.';\r\nconst DOCUMENTO_TRAVADO =\r\n 'O documento e o nome já foram usados em uma cobrança e não podem mais ser alterados.';\r\nconst PLANO_INDISPONIVEL = 'O plano da assinatura não está disponível. Fale com o suporte.';\r\nconst SO_O_TITULAR = 'Só o titular da conta pode ver e pagar a cobrança.';\r\n\r\n/**\r\n * Os codes que as rotas de cobrança da Platform e do BFF emitem de fato\r\n * (`Commerce*Endpoints`, handlers de `Billing/`, value objects de perfil,\r\n * `PermissionAuthorization`, `Bff.Account`).\r\n */\r\nconst MENSAGENS: Record<string, string> = {\r\n 'session.missing': 'Sua sessão expirou. Entre novamente para continuar.',\r\n 'platform.unavailable':\r\n 'O serviço de cobrança está indisponível no momento. Tente novamente em instantes.',\r\n 'http.0': 'Sem conexão com o servidor. Verifique sua internet e tente novamente.',\r\n rate_limit_exceeded: 'Muitas tentativas. Aguarde alguns minutos e tente novamente.',\r\n\r\n 'access.platform_only': SO_O_TITULAR,\r\n 'permission.denied': SO_O_TITULAR,\r\n\r\n 'subscription.not_found': 'Nenhuma assinatura encontrada para esta conta.',\r\n\r\n 'billing_profile.not_found': 'Cadastre os dados de cobrança antes de pagar.',\r\n 'billing_profile.already_exists': 'Os dados de cobrança já estão cadastrados.',\r\n 'billing_profile.legal_name_required': 'Informe o nome completo ou a razão social.',\r\n 'billing_profile.billing_email_required': 'Informe o e-mail de cobrança.',\r\n 'billing_profile.billing_email_invalid': 'Informe um e-mail de cobrança válido.',\r\n 'billing_profile.mobile_phone_too_long': 'O celular informado é longo demais.',\r\n 'billing_profile.document_type_locked': DOCUMENTO_TRAVADO,\r\n 'billing_profile.document_number_locked': DOCUMENTO_TRAVADO,\r\n 'billing_profile.legal_name_locked': DOCUMENTO_TRAVADO,\r\n 'tax_document.value_required': 'Informe o CPF ou o CNPJ.',\r\n 'tax_document.length_invalid': DOCUMENTO_INVALIDO,\r\n 'tax_document.checksum_invalid': DOCUMENTO_INVALIDO,\r\n 'address.postal_code_invalid': 'CEP inválido.',\r\n 'address.state_invalid': 'UF inválida. Use a sigla do estado, como SP.',\r\n 'address.street_required': ENDERECO_INCOMPLETO,\r\n 'address.number_required': ENDERECO_INCOMPLETO,\r\n 'address.neighborhood_required': ENDERECO_INCOMPLETO,\r\n 'address.city_required': ENDERECO_INCOMPLETO,\r\n\r\n 'checkout.subscription_not_eligible':\r\n 'Não há pagamento de assinatura a fazer agora. Veja as faturas em aberto.',\r\n 'checkout.open_invoice_exists':\r\n 'Já existe uma fatura em aberto. Pague a fatura em aberto em vez de gerar uma nova cobrança.',\r\n 'checkout.pending_other_method':\r\n 'Já existe uma cobrança em aberto por outro meio de pagamento. Veja as faturas.',\r\n 'checkout.credit_card_not_supported': 'Pagamento por cartão ainda não está disponível.',\r\n 'checkout.invoice_in_inconsistent_state':\r\n 'A cobrança anterior ficou incompleta. Tente novamente em alguns minutos.',\r\n 'billing.cycle_invalid': 'Escolha um ciclo de cobrança válido.',\r\n 'pricing_preview.cycle_invalid': 'Escolha um ciclo de cobrança válido.',\r\n 'plan.not_found': PLANO_INDISPONIVEL,\r\n 'plan.not_available': PLANO_INDISPONIVEL,\r\n 'subscription.plan_inactive': PLANO_INDISPONIVEL,\r\n\r\n 'invoice.not_found': 'Fatura não encontrada.',\r\n 'invoice.payment_unavailable':\r\n 'Esta cobrança não está mais disponível para pagamento. Fale com o suporte.',\r\n 'invoice.refresh_not_allowed': 'Esta fatura não está mais em aberto.',\r\n 'invoice.refresh_pix_only': 'Só é possível gerar QR para faturas PIX.',\r\n 'invoice.no_external_payment':\r\n 'Esta fatura ainda não tem cobrança gerada. Tente novamente em alguns minutos.',\r\n};\r\n\r\nconst GENERICA =\r\n 'Não foi possível concluir a operação. Tente novamente; se continuar, informe o código de atendimento ao suporte.';\r\n\r\n/**\r\n * O texto de tela para um erro do BFF, escolhido por `code`. O corpo do erro (`message`) nunca\r\n * vira texto: ele é escrito para log, não para o cliente.\r\n */\r\nexport function mensagemDeErro(problema: ProblemDetails): MensagemDeErro {\r\n const conhecida = MENSAGENS[problema.code];\r\n if (conhecida) return { texto: conhecida };\r\n\r\n return problema.correlationId\r\n ? { texto: GENERICA, correlationId: problema.correlationId }\r\n : { texto: GENERICA };\r\n}\r\n","import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\r\nimport { ProblemDetails } from '@orechio/platform-angular';\r\nimport { mensagemDeErro } from './billing-errors';\r\n\r\n@Component({\r\n selector: 'orechio-billing-error',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"orechio-billing__error\" role=\"alert\">\r\n <p>{{ mensagem().texto }}</p>\r\n @if (mensagem().correlationId; as id) {\r\n <p>Código de atendimento: <code>{{ id }}</code></p>\r\n }\r\n </div>\r\n `,\r\n styles: `.orechio-billing__error { color: var(--orechio-color-danger, #b00020); }`,\r\n})\r\nexport class BillingErrorComponent {\r\n readonly problema = input.required<ProblemDetails>();\r\n protected readonly mensagem = computed(() => mensagemDeErro(this.problema()));\r\n}\r\n","import { InvoiceStatus } from './billing-models';\r\n\r\nconst MOEDA = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' });\r\n\r\nexport function moeda(valor: number): string {\r\n return MOEDA.format(valor);\r\n}\r\n\r\nexport function data(iso: string | null | undefined): string {\r\n return iso ? new Date(iso).toLocaleDateString('pt-BR') : '';\r\n}\r\n\r\nexport const STATUS_DA_FATURA: Record<InvoiceStatus, string> = {\r\n Created: 'Em emissão',\r\n Pending: 'Em aberto',\r\n Paid: 'Paga',\r\n Overdue: 'Vencida',\r\n Refunded: 'Estornada',\r\n Cancelled: 'Cancelada',\r\n};\r\n\r\nexport const ESTILO_BASE = `\r\n .orechio-billing {\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--orechio-space-3, 0.75rem);\r\n max-width: 40rem;\r\n margin: 0 auto;\r\n padding: var(--orechio-space-6, 1.5rem);\r\n color: var(--orechio-color-text, inherit);\r\n font-family: var(--orechio-font-body, inherit);\r\n }\r\n .orechio-billing form { display: flex; flex-direction: column; gap: var(--orechio-space-2, 0.5rem); }\r\n .orechio-billing__muted { color: var(--orechio-color-text-muted, #666); }\r\n .orechio-billing__error { color: var(--orechio-color-danger, #b00020); }\r\n`;\r\n"],"names":[],"mappings":";;;;;;;AAoBA;;;;AAIG;MAEU,aAAa,CAAA;AACP,IAAA,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC;AACzB,IAAA,MAAM,GAAG,MAAM,CAAC,sBAAsB,CAAC;IAExD,eAAe,GAAA;AACb,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAe,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC;IAC3E;IAEA,UAAU,GAAA;AACR,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAiB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;IACxE;AAEA,IAAA,aAAa,CAAC,OAAoC,EAAA;QAChD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAiB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,CAAC;IAClF;AAEA,IAAA,oBAAoB,CAAC,OAA8B,EAAA;QACjD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAO,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC,CAAC;IACjF;AAEA,IAAA,oBAAoB,CAAC,OAA8B,EAAA;QACjD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAO,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC,CAAC;IACjF;IAEA,SAAS,GAAA;AACP,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAS,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC9D;AAEA,IAAA,cAAc,CAAC,MAAc,EAAE,WAAmB,EAAE,KAAmB,EAAA;AACrE,QAAA,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,CAAC;QAC7E,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAiB,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5F;AAEA;;;AAGG;AACH,IAAA,QAAQ,CAAC,KAAmB,EAAA;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAiB,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACpG;AAEA,IAAA,YAAY,CAAC,IAAI,GAAG,CAAC,EAAE,QAAQ,GAAG,EAAE,EAAA;AAClC,QAAA,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC;QACjE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAe,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACnF;AAEA,IAAA,UAAU,CAAC,EAAU,EAAA;QACnB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAgB,IAAI,CAAC,GAAG,CAAC,CAAA,UAAA,EAAa,kBAAkB,CAAC,EAAE,CAAC,CAAA,CAAE,CAAC,CAAC,CAAC;IAClG;AAEA,IAAA,iBAAiB,CAAC,EAAU,EAAA;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAmB,IAAI,CAAC,GAAG,CAAC,CAAA,UAAA,EAAa,kBAAkB,CAAC,EAAE,CAAC,CAAA,QAAA,CAAU,CAAC,EAAE,IAAI,CAAC,CAAC;IACpH;AAEQ,IAAA,GAAG,CAAC,IAAY,EAAA;QACtB,OAAO,CAAA,EAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAA,EAAG,IAAI,CAAA,CAAE;IACzC;AAEQ,IAAA,KAAK,CAAI,OAAsB,EAAA;QACrC,OAAO,OAAO,CAAC,IAAI,CACjB,UAAU,CAAC,CAAC,KAAwB,KAClC,UAAU,CAAC,MAAsB,uBAAuB,CAAC,KAAK,CAAC,CAAC,CACjE,CACF;IACH;uGAhEW,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAb,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,aAAa,cADA,MAAM,EAAA,CAAA;;2FACnB,aAAa,EAAA,UAAA,EAAA,CAAA;kBADzB,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACjBlC,MAAM,mBAAmB,GAAG,+BAA+B;AAC3D,MAAM,kBAAkB,GAAG,uBAAuB;AAClD,MAAM,iBAAiB,GACrB,sFAAsF;AACxF,MAAM,kBAAkB,GAAG,gEAAgE;AAC3F,MAAM,YAAY,GAAG,oDAAoD;AAEzE;;;;AAIG;AACH,MAAM,SAAS,GAA2B;AACxC,IAAA,iBAAiB,EAAE,qDAAqD;AACxE,IAAA,sBAAsB,EACpB,mFAAmF;AACrF,IAAA,QAAQ,EAAE,uEAAuE;AACjF,IAAA,mBAAmB,EAAE,8DAA8D;AAEnF,IAAA,sBAAsB,EAAE,YAAY;AACpC,IAAA,mBAAmB,EAAE,YAAY;AAEjC,IAAA,wBAAwB,EAAE,gDAAgD;AAE1E,IAAA,2BAA2B,EAAE,+CAA+C;AAC5E,IAAA,gCAAgC,EAAE,4CAA4C;AAC9E,IAAA,qCAAqC,EAAE,4CAA4C;AACnF,IAAA,wCAAwC,EAAE,+BAA+B;AACzE,IAAA,uCAAuC,EAAE,uCAAuC;AAChF,IAAA,uCAAuC,EAAE,qCAAqC;AAC9E,IAAA,sCAAsC,EAAE,iBAAiB;AACzD,IAAA,wCAAwC,EAAE,iBAAiB;AAC3D,IAAA,mCAAmC,EAAE,iBAAiB;AACtD,IAAA,6BAA6B,EAAE,0BAA0B;AACzD,IAAA,6BAA6B,EAAE,kBAAkB;AACjD,IAAA,+BAA+B,EAAE,kBAAkB;AACnD,IAAA,6BAA6B,EAAE,eAAe;AAC9C,IAAA,uBAAuB,EAAE,8CAA8C;AACvE,IAAA,yBAAyB,EAAE,mBAAmB;AAC9C,IAAA,yBAAyB,EAAE,mBAAmB;AAC9C,IAAA,+BAA+B,EAAE,mBAAmB;AACpD,IAAA,uBAAuB,EAAE,mBAAmB;AAE5C,IAAA,oCAAoC,EAClC,0EAA0E;AAC5E,IAAA,8BAA8B,EAC5B,6FAA6F;AAC/F,IAAA,+BAA+B,EAC7B,gFAAgF;AAClF,IAAA,oCAAoC,EAAE,iDAAiD;AACvF,IAAA,wCAAwC,EACtC,0EAA0E;AAC5E,IAAA,uBAAuB,EAAE,sCAAsC;AAC/D,IAAA,+BAA+B,EAAE,sCAAsC;AACvE,IAAA,gBAAgB,EAAE,kBAAkB;AACpC,IAAA,oBAAoB,EAAE,kBAAkB;AACxC,IAAA,4BAA4B,EAAE,kBAAkB;AAEhD,IAAA,mBAAmB,EAAE,wBAAwB;AAC7C,IAAA,6BAA6B,EAC3B,4EAA4E;AAC9E,IAAA,6BAA6B,EAAE,sCAAsC;AACrE,IAAA,0BAA0B,EAAE,0CAA0C;AACtE,IAAA,6BAA6B,EAC3B,+EAA+E;CAClF;AAED,MAAM,QAAQ,GACZ,kHAAkH;AAEpH;;;AAGG;AACG,SAAU,cAAc,CAAC,QAAwB,EAAA;IACrD,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;AAC1C,IAAA,IAAI,SAAS;AAAE,QAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE;IAE1C,OAAO,QAAQ,CAAC;UACZ,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,CAAC,aAAa;AAC1D,UAAE,EAAE,KAAK,EAAE,QAAQ,EAAE;AACzB;;MCvEa,qBAAqB,CAAA;IACvB,QAAQ,GAAG,KAAK,CAAC,QAAQ;iFAAkB;AACjC,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAM,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;iFAAC;uGAFlE,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAArB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,uBAAA,EAAA,MAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAVtB,CAAA;;;;;;;AAOT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,uEAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAGU,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBAdjC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,uBAAuB,cACrB,IAAI,EAAA,eAAA,EACC,uBAAuB,CAAC,MAAM,EAAA,QAAA,EACrC,CAAA;;;;;;;AAOT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,uEAAA,CAAA,EAAA;;;ACbH,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AAE9E,SAAU,KAAK,CAAC,KAAa,EAAA;AACjC,IAAA,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;AAC5B;AAEM,SAAU,IAAI,CAAC,GAA8B,EAAA;AACjD,IAAA,OAAO,GAAG,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,GAAG,EAAE;AAC7D;AAEO,MAAM,gBAAgB,GAAkC;AAC7D,IAAA,OAAO,EAAE,YAAY;AACrB,IAAA,OAAO,EAAE,WAAW;AACpB,IAAA,IAAI,EAAE,MAAM;AACZ,IAAA,OAAO,EAAE,SAAS;AAClB,IAAA,QAAQ,EAAE,WAAW;AACrB,IAAA,SAAS,EAAE,WAAW;;AAGjB,MAAM,WAAW,GAAG,CAAA;;;;;;;;;;;;;;CAc1B;;;;"}
@@ -0,0 +1,186 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, signal, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { Router, ActivatedRoute, RouterLink } from '@angular/router';
4
+ import { forkJoin } from 'rxjs';
5
+ import { B as BillingClient, m as moeda, a as BillingErrorComponent } from './orechio-platform-angular-billing-billing-format-0nlddK-x.mjs';
6
+ import { P as PixPanelComponent } from './orechio-platform-angular-billing-pix-panel.component-B608dQmc.mjs';
7
+
8
+ const STATUS_COM_CHECKOUT = ['Trial', 'PendingPayment', 'Grace', 'Suspended'];
9
+ const CICLOS = [
10
+ { valor: 'Monthly', rotulo: 'Mensal' },
11
+ { valor: 'Yearly', rotulo: 'Anual' },
12
+ ];
13
+ /**
14
+ * Pagar a assinatura (ADR-021 §3.5, item 3): o plano ATUAL — trocar de plano é v2 —, o preço
15
+ * de cada ciclo vindo de `pricing/preview`, e o checkout PIX.
16
+ */
17
+ class CheckoutPage {
18
+ client = inject(BillingClient);
19
+ router = inject(Router);
20
+ route = inject(ActivatedRoute);
21
+ moeda = moeda;
22
+ previas = signal([], /* @ts-ignore */
23
+ ...(ngDevMode ? [{ debugName: "previas" }] : /* istanbul ignore next */ []));
24
+ ciclo = signal('Monthly', /* @ts-ignore */
25
+ ...(ngDevMode ? [{ debugName: "ciclo" }] : /* istanbul ignore next */ []));
26
+ inelegivel = signal(false, /* @ts-ignore */
27
+ ...(ngDevMode ? [{ debugName: "inelegivel" }] : /* istanbul ignore next */ []));
28
+ enviando = signal(false, /* @ts-ignore */
29
+ ...(ngDevMode ? [{ debugName: "enviando" }] : /* istanbul ignore next */ []));
30
+ pix = signal(null, /* @ts-ignore */
31
+ ...(ngDevMode ? [{ debugName: "pix" }] : /* istanbul ignore next */ []));
32
+ invoiceUrl = signal(null, /* @ts-ignore */
33
+ ...(ngDevMode ? [{ debugName: "invoiceUrl" }] : /* istanbul ignore next */ []));
34
+ erro = signal(null, /* @ts-ignore */
35
+ ...(ngDevMode ? [{ debugName: "erro" }] : /* istanbul ignore next */ []));
36
+ rotulo(ciclo) {
37
+ return CICLOS.find((c) => c.valor === ciclo)?.rotulo ?? ciclo;
38
+ }
39
+ ngOnInit() {
40
+ forkJoin({ assinatura: this.client.getSubscription(), perfil: this.client.getProfile() }).subscribe({
41
+ next: ({ assinatura, perfil }) => {
42
+ // O checkout serve Trial, PendingPayment, Grace e Suspended (`InitiateCheckoutCommand`,
43
+ // passo 4; os dois últimos desde a BILLING-2b, e só sem fatura aberta — ver `pagar`).
44
+ // Checado antes do perfil: não se pede cadastro para um pagamento que não existe.
45
+ if (!STATUS_COM_CHECKOUT.includes(assinatura.status)) {
46
+ this.inelegivel.set(true);
47
+ return;
48
+ }
49
+ // O checkout recusa sem perfil (`billing_profile.not_found`). Mandar para o perfil
50
+ // ANTES poupa o cliente de escolher o ciclo para receber um erro.
51
+ if (!perfil.exists || !perfil.isComplete) {
52
+ void this.router.navigate(['../profile'], {
53
+ relativeTo: this.route,
54
+ queryParams: { next: 'checkout' },
55
+ });
56
+ return;
57
+ }
58
+ this.ciclo.set(assinatura.cycle);
59
+ this.carregarPrecos(assinatura);
60
+ },
61
+ error: (problema) => this.erro.set(problema),
62
+ });
63
+ }
64
+ pagar() {
65
+ if (this.enviando())
66
+ return;
67
+ this.enviando.set(true);
68
+ this.erro.set(null);
69
+ this.client.checkout(this.ciclo()).subscribe({
70
+ next: (resultado) => {
71
+ this.enviando.set(false);
72
+ this.invoiceUrl.set(resultado.invoiceUrl ?? null);
73
+ if (resultado.pix)
74
+ this.pix.set(resultado.pix);
75
+ else
76
+ this.erro.set({ code: 'checkout.pix_missing', status: 200 });
77
+ },
78
+ error: (problema) => {
79
+ this.enviando.set(false);
80
+ // Em Grace/Suspended com fatura aberta a Platform recusa: a aberta é a que se paga.
81
+ if (problema.code === 'checkout.open_invoice_exists') {
82
+ void this.router.navigate(['../invoices'], { relativeTo: this.route });
83
+ return;
84
+ }
85
+ this.erro.set(problema);
86
+ },
87
+ });
88
+ }
89
+ carregarPrecos(assinatura) {
90
+ forkJoin(CICLOS.map(({ valor }) => this.client.previewPricing(assinatura.planId, assinatura.branchCountSnapshot, valor))).subscribe({
91
+ next: (previas) => this.previas.set(previas),
92
+ error: (problema) => this.erro.set(problema),
93
+ });
94
+ }
95
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: CheckoutPage, deps: [], target: i0.ɵɵFactoryTarget.Component });
96
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: CheckoutPage, isStandalone: true, selector: "orechio-billing-checkout", ngImport: i0, template: `
97
+ <section class="orechio-billing">
98
+ <h1>Pagar assinatura</h1>
99
+
100
+ @if (pix(); as dados) {
101
+ <p>Pague o PIX abaixo. A assinatura é atualizada assim que o pagamento for confirmado.</p>
102
+ <orechio-billing-pix [pix]="dados" [invoiceUrl]="invoiceUrl()" />
103
+ <a routerLink="..">Voltar para a assinatura</a>
104
+ } @else if (inelegivel()) {
105
+ <p>Não há pagamento de assinatura a fazer agora.</p>
106
+ <a routerLink="../invoices">Ver faturas</a>
107
+ } @else if (previas().length) {
108
+ <h2>{{ previas()[0].planName }}</h2>
109
+
110
+ <fieldset>
111
+ <legend>Ciclo de cobrança</legend>
112
+ @for (previa of previas(); track previa.cycle) {
113
+ <label>
114
+ <input
115
+ type="radio"
116
+ name="ciclo"
117
+ [value]="previa.cycle"
118
+ [checked]="ciclo() === previa.cycle"
119
+ (change)="ciclo.set(previa.cycle)"
120
+ />
121
+ {{ rotulo(previa.cycle) }} — {{ moeda(previa.total) }}
122
+ </label>
123
+ }
124
+ </fieldset>
125
+
126
+ <button type="button" data-gerar-pix (click)="pagar()" [disabled]="enviando()">
127
+ {{ enviando() ? 'Gerando PIX…' : 'Gerar PIX' }}
128
+ </button>
129
+ } @else if (!erro()) {
130
+ <p class="orechio-billing__muted">Carregando…</p>
131
+ }
132
+
133
+ @if (erro(); as problema) {
134
+ <orechio-billing-error [problema]="problema" />
135
+ }
136
+ </section>
137
+ `, isInline: true, styles: [".orechio-billing{display:flex;flex-direction:column;gap:var(--orechio-space-3, .75rem);max-width:40rem;margin:0 auto;padding:var(--orechio-space-6, 1.5rem);color:var(--orechio-color-text, inherit);font-family:var(--orechio-font-body, inherit)}.orechio-billing form{display:flex;flex-direction:column;gap:var(--orechio-space-2, .5rem)}.orechio-billing__muted{color:var(--orechio-color-text-muted, #666)}.orechio-billing__error{color:var(--orechio-color-danger, #b00020)}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "component", type: BillingErrorComponent, selector: "orechio-billing-error", inputs: ["problema"] }, { kind: "component", type: PixPanelComponent, selector: "orechio-billing-pix", inputs: ["pix", "invoiceUrl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
138
+ }
139
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: CheckoutPage, decorators: [{
140
+ type: Component,
141
+ args: [{ selector: 'orechio-billing-checkout', standalone: true, imports: [RouterLink, BillingErrorComponent, PixPanelComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
142
+ <section class="orechio-billing">
143
+ <h1>Pagar assinatura</h1>
144
+
145
+ @if (pix(); as dados) {
146
+ <p>Pague o PIX abaixo. A assinatura é atualizada assim que o pagamento for confirmado.</p>
147
+ <orechio-billing-pix [pix]="dados" [invoiceUrl]="invoiceUrl()" />
148
+ <a routerLink="..">Voltar para a assinatura</a>
149
+ } @else if (inelegivel()) {
150
+ <p>Não há pagamento de assinatura a fazer agora.</p>
151
+ <a routerLink="../invoices">Ver faturas</a>
152
+ } @else if (previas().length) {
153
+ <h2>{{ previas()[0].planName }}</h2>
154
+
155
+ <fieldset>
156
+ <legend>Ciclo de cobrança</legend>
157
+ @for (previa of previas(); track previa.cycle) {
158
+ <label>
159
+ <input
160
+ type="radio"
161
+ name="ciclo"
162
+ [value]="previa.cycle"
163
+ [checked]="ciclo() === previa.cycle"
164
+ (change)="ciclo.set(previa.cycle)"
165
+ />
166
+ {{ rotulo(previa.cycle) }} — {{ moeda(previa.total) }}
167
+ </label>
168
+ }
169
+ </fieldset>
170
+
171
+ <button type="button" data-gerar-pix (click)="pagar()" [disabled]="enviando()">
172
+ {{ enviando() ? 'Gerando PIX…' : 'Gerar PIX' }}
173
+ </button>
174
+ } @else if (!erro()) {
175
+ <p class="orechio-billing__muted">Carregando…</p>
176
+ }
177
+
178
+ @if (erro(); as problema) {
179
+ <orechio-billing-error [problema]="problema" />
180
+ }
181
+ </section>
182
+ `, styles: [".orechio-billing{display:flex;flex-direction:column;gap:var(--orechio-space-3, .75rem);max-width:40rem;margin:0 auto;padding:var(--orechio-space-6, 1.5rem);color:var(--orechio-color-text, inherit);font-family:var(--orechio-font-body, inherit)}.orechio-billing form{display:flex;flex-direction:column;gap:var(--orechio-space-2, .5rem)}.orechio-billing__muted{color:var(--orechio-color-text-muted, #666)}.orechio-billing__error{color:var(--orechio-color-danger, #b00020)}\n"] }]
183
+ }] });
184
+
185
+ export { CheckoutPage };
186
+ //# sourceMappingURL=orechio-platform-angular-billing-checkout.page-CHU_Drpu.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orechio-platform-angular-billing-checkout.page-CHU_Drpu.mjs","sources":["../../../projects/platform-angular/billing/src/pages/checkout.page.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, OnInit, inject, signal } from '@angular/core';\r\nimport { ActivatedRoute, Router, RouterLink } from '@angular/router';\r\nimport { forkJoin } from 'rxjs';\r\nimport { ProblemDetails } from '@orechio/platform-angular';\r\nimport { BillingClient } from '../billing-client';\r\nimport { BillingErrorComponent } from '../billing-error.component';\r\nimport { ESTILO_BASE, moeda } from '../billing-format';\r\nimport { BillingCycle, PixData, PricingPreview, Subscription, SubscriptionStatus } from '../billing-models';\r\nimport { PixPanelComponent } from '../pix-panel.component';\r\n\r\nconst STATUS_COM_CHECKOUT: SubscriptionStatus[] = ['Trial', 'PendingPayment', 'Grace', 'Suspended'];\r\n\r\nconst CICLOS: { valor: BillingCycle; rotulo: string }[] = [\r\n { valor: 'Monthly', rotulo: 'Mensal' },\r\n { valor: 'Yearly', rotulo: 'Anual' },\r\n];\r\n\r\n/**\r\n * Pagar a assinatura (ADR-021 §3.5, item 3): o plano ATUAL — trocar de plano é v2 —, o preço\r\n * de cada ciclo vindo de `pricing/preview`, e o checkout PIX.\r\n */\r\n@Component({\r\n selector: 'orechio-billing-checkout',\r\n standalone: true,\r\n imports: [RouterLink, BillingErrorComponent, PixPanelComponent],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <section class=\"orechio-billing\">\r\n <h1>Pagar assinatura</h1>\r\n\r\n @if (pix(); as dados) {\r\n <p>Pague o PIX abaixo. A assinatura é atualizada assim que o pagamento for confirmado.</p>\r\n <orechio-billing-pix [pix]=\"dados\" [invoiceUrl]=\"invoiceUrl()\" />\r\n <a routerLink=\"..\">Voltar para a assinatura</a>\r\n } @else if (inelegivel()) {\r\n <p>Não há pagamento de assinatura a fazer agora.</p>\r\n <a routerLink=\"../invoices\">Ver faturas</a>\r\n } @else if (previas().length) {\r\n <h2>{{ previas()[0].planName }}</h2>\r\n\r\n <fieldset>\r\n <legend>Ciclo de cobrança</legend>\r\n @for (previa of previas(); track previa.cycle) {\r\n <label>\r\n <input\r\n type=\"radio\"\r\n name=\"ciclo\"\r\n [value]=\"previa.cycle\"\r\n [checked]=\"ciclo() === previa.cycle\"\r\n (change)=\"ciclo.set(previa.cycle)\"\r\n />\r\n {{ rotulo(previa.cycle) }} — {{ moeda(previa.total) }}\r\n </label>\r\n }\r\n </fieldset>\r\n\r\n <button type=\"button\" data-gerar-pix (click)=\"pagar()\" [disabled]=\"enviando()\">\r\n {{ enviando() ? 'Gerando PIX…' : 'Gerar PIX' }}\r\n </button>\r\n } @else if (!erro()) {\r\n <p class=\"orechio-billing__muted\">Carregando…</p>\r\n }\r\n\r\n @if (erro(); as problema) {\r\n <orechio-billing-error [problema]=\"problema\" />\r\n }\r\n </section>\r\n `,\r\n styles: ESTILO_BASE,\r\n})\r\nexport class CheckoutPage implements OnInit {\r\n private readonly client = inject(BillingClient);\r\n private readonly router = inject(Router);\r\n private readonly route = inject(ActivatedRoute);\r\n\r\n protected readonly moeda = moeda;\r\n protected readonly previas = signal<PricingPreview[]>([]);\r\n protected readonly ciclo = signal<BillingCycle>('Monthly');\r\n protected readonly inelegivel = signal(false);\r\n protected readonly enviando = signal(false);\r\n protected readonly pix = signal<PixData | null>(null);\r\n protected readonly invoiceUrl = signal<string | null>(null);\r\n protected readonly erro = signal<ProblemDetails | null>(null);\r\n\r\n protected rotulo(ciclo: BillingCycle): string {\r\n return CICLOS.find((c) => c.valor === ciclo)?.rotulo ?? ciclo;\r\n }\r\n\r\n ngOnInit(): void {\r\n forkJoin({ assinatura: this.client.getSubscription(), perfil: this.client.getProfile() }).subscribe({\r\n next: ({ assinatura, perfil }) => {\r\n // O checkout serve Trial, PendingPayment, Grace e Suspended (`InitiateCheckoutCommand`,\r\n // passo 4; os dois últimos desde a BILLING-2b, e só sem fatura aberta — ver `pagar`).\r\n // Checado antes do perfil: não se pede cadastro para um pagamento que não existe.\r\n if (!STATUS_COM_CHECKOUT.includes(assinatura.status)) {\r\n this.inelegivel.set(true);\r\n return;\r\n }\r\n\r\n // O checkout recusa sem perfil (`billing_profile.not_found`). Mandar para o perfil\r\n // ANTES poupa o cliente de escolher o ciclo para receber um erro.\r\n if (!perfil.exists || !perfil.isComplete) {\r\n void this.router.navigate(['../profile'], {\r\n relativeTo: this.route,\r\n queryParams: { next: 'checkout' },\r\n });\r\n return;\r\n }\r\n\r\n this.ciclo.set(assinatura.cycle);\r\n this.carregarPrecos(assinatura);\r\n },\r\n error: (problema: ProblemDetails) => this.erro.set(problema),\r\n });\r\n }\r\n\r\n protected pagar(): void {\r\n if (this.enviando()) return;\r\n this.enviando.set(true);\r\n this.erro.set(null);\r\n\r\n this.client.checkout(this.ciclo()).subscribe({\r\n next: (resultado) => {\r\n this.enviando.set(false);\r\n this.invoiceUrl.set(resultado.invoiceUrl ?? null);\r\n if (resultado.pix) this.pix.set(resultado.pix);\r\n else this.erro.set({ code: 'checkout.pix_missing', status: 200 });\r\n },\r\n error: (problema: ProblemDetails) => {\r\n this.enviando.set(false);\r\n // Em Grace/Suspended com fatura aberta a Platform recusa: a aberta é a que se paga.\r\n if (problema.code === 'checkout.open_invoice_exists') {\r\n void this.router.navigate(['../invoices'], { relativeTo: this.route });\r\n return;\r\n }\r\n this.erro.set(problema);\r\n },\r\n });\r\n }\r\n\r\n private carregarPrecos(assinatura: Subscription): void {\r\n forkJoin(\r\n CICLOS.map(({ valor }) =>\r\n this.client.previewPricing(assinatura.planId, assinatura.branchCountSnapshot, valor),\r\n ),\r\n ).subscribe({\r\n next: (previas) => this.previas.set(previas),\r\n error: (problema: ProblemDetails) => this.erro.set(problema),\r\n });\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, signal, computed, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { ActivatedRoute, RouterLink } from '@angular/router';
4
+ import { B as BillingClient, S as STATUS_DA_FATURA, m as moeda, d as data, a as BillingErrorComponent } from './orechio-platform-angular-billing-billing-format-0nlddK-x.mjs';
5
+ import { P as PixPanelComponent } from './orechio-platform-angular-billing-pix-panel.component-B608dQmc.mjs';
6
+
7
+ /**
8
+ * Detalhe de fatura. O detalhe da Platform não traz dado de pagamento (`InvoiceDetailDto`):
9
+ * o QR vem do refresh, que a Platform aceita para fatura PIX `Pending` ou `Overdue`
10
+ * (`RefreshPaymentDataCommand`, passo 2) — o que inclui a fatura de renovação.
11
+ */
12
+ class InvoicePage {
13
+ client = inject(BillingClient);
14
+ route = inject(ActivatedRoute);
15
+ status = STATUS_DA_FATURA;
16
+ moeda = moeda;
17
+ data = data;
18
+ fatura = signal(null, /* @ts-ignore */
19
+ ...(ngDevMode ? [{ debugName: "fatura" }] : /* istanbul ignore next */ []));
20
+ pix = signal(null, /* @ts-ignore */
21
+ ...(ngDevMode ? [{ debugName: "pix" }] : /* istanbul ignore next */ []));
22
+ invoiceUrl = signal(null, /* @ts-ignore */
23
+ ...(ngDevMode ? [{ debugName: "invoiceUrl" }] : /* istanbul ignore next */ []));
24
+ gerando = signal(false, /* @ts-ignore */
25
+ ...(ngDevMode ? [{ debugName: "gerando" }] : /* istanbul ignore next */ []));
26
+ erro = signal(null, /* @ts-ignore */
27
+ ...(ngDevMode ? [{ debugName: "erro" }] : /* istanbul ignore next */ []));
28
+ podeGerarQr = computed(() => {
29
+ const f = this.fatura();
30
+ return !!f && f.paymentMethod === 'Pix' && (f.status === 'Pending' || f.status === 'Overdue');
31
+ }, /* @ts-ignore */
32
+ ...(ngDevMode ? [{ debugName: "podeGerarQr" }] : /* istanbul ignore next */ []));
33
+ ngOnInit() {
34
+ const id = this.route.snapshot.paramMap.get('id') ?? '';
35
+ this.client.getInvoice(id).subscribe({
36
+ next: (fatura) => this.fatura.set(fatura),
37
+ error: (problema) => this.erro.set(problema),
38
+ });
39
+ }
40
+ gerarQr() {
41
+ const f = this.fatura();
42
+ if (!f || this.gerando())
43
+ return;
44
+ this.gerando.set(true);
45
+ this.erro.set(null);
46
+ this.client.refreshInvoicePix(f.id).subscribe({
47
+ next: (pix) => {
48
+ this.gerando.set(false);
49
+ // O refresh traz o PIX e o `invoiceUrl` juntos: o link acompanha o QR que está na tela.
50
+ this.invoiceUrl.set(pix.invoiceUrl ?? null);
51
+ this.pix.set(pix);
52
+ },
53
+ error: (problema) => {
54
+ this.gerando.set(false);
55
+ this.erro.set(problema);
56
+ },
57
+ });
58
+ }
59
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: InvoicePage, deps: [], target: i0.ɵɵFactoryTarget.Component });
60
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: InvoicePage, isStandalone: true, selector: "orechio-billing-invoice", ngImport: i0, template: `
61
+ <section class="orechio-billing">
62
+ @if (fatura(); as f) {
63
+ <h1>Fatura {{ f.number }}</h1>
64
+ <p>{{ status[f.status] }} — {{ moeda(f.amount) }} — vence em {{ data(f.dueDate) }}</p>
65
+ <p class="orechio-billing__muted">
66
+ {{ f.planNameAtTime }}, de {{ data(f.periodStartsAt) }} a {{ data(f.periodEndsAt) }}
67
+ </p>
68
+
69
+ <ul>
70
+ @for (item of f.items; track item.order) {
71
+ <li>{{ item.description }} — {{ item.quantity }} × {{ moeda(item.unitAmount) }} = {{ moeda(item.totalAmount) }}</li>
72
+ }
73
+ </ul>
74
+
75
+ @if (podeGerarQr()) {
76
+ <button type="button" data-gerar-qr (click)="gerarQr()" [disabled]="gerando()">
77
+ {{ gerando() ? 'Gerando…' : 'Gerar novo QR' }}
78
+ </button>
79
+ }
80
+
81
+ @if (pix(); as dados) {
82
+ <orechio-billing-pix [pix]="dados" [invoiceUrl]="invoiceUrl()" />
83
+ }
84
+ } @else if (!erro()) {
85
+ <p class="orechio-billing__muted">Carregando…</p>
86
+ }
87
+
88
+ @if (erro(); as problema) {
89
+ <orechio-billing-error [problema]="problema" />
90
+ }
91
+
92
+ <a routerLink="..">Voltar para as faturas</a>
93
+ </section>
94
+ `, isInline: true, styles: [".orechio-billing{display:flex;flex-direction:column;gap:var(--orechio-space-3, .75rem);max-width:40rem;margin:0 auto;padding:var(--orechio-space-6, 1.5rem);color:var(--orechio-color-text, inherit);font-family:var(--orechio-font-body, inherit)}.orechio-billing form{display:flex;flex-direction:column;gap:var(--orechio-space-2, .5rem)}.orechio-billing__muted{color:var(--orechio-color-text-muted, #666)}.orechio-billing__error{color:var(--orechio-color-danger, #b00020)}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "component", type: BillingErrorComponent, selector: "orechio-billing-error", inputs: ["problema"] }, { kind: "component", type: PixPanelComponent, selector: "orechio-billing-pix", inputs: ["pix", "invoiceUrl"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
95
+ }
96
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: InvoicePage, decorators: [{
97
+ type: Component,
98
+ args: [{ selector: 'orechio-billing-invoice', standalone: true, imports: [RouterLink, BillingErrorComponent, PixPanelComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
99
+ <section class="orechio-billing">
100
+ @if (fatura(); as f) {
101
+ <h1>Fatura {{ f.number }}</h1>
102
+ <p>{{ status[f.status] }} — {{ moeda(f.amount) }} — vence em {{ data(f.dueDate) }}</p>
103
+ <p class="orechio-billing__muted">
104
+ {{ f.planNameAtTime }}, de {{ data(f.periodStartsAt) }} a {{ data(f.periodEndsAt) }}
105
+ </p>
106
+
107
+ <ul>
108
+ @for (item of f.items; track item.order) {
109
+ <li>{{ item.description }} — {{ item.quantity }} × {{ moeda(item.unitAmount) }} = {{ moeda(item.totalAmount) }}</li>
110
+ }
111
+ </ul>
112
+
113
+ @if (podeGerarQr()) {
114
+ <button type="button" data-gerar-qr (click)="gerarQr()" [disabled]="gerando()">
115
+ {{ gerando() ? 'Gerando…' : 'Gerar novo QR' }}
116
+ </button>
117
+ }
118
+
119
+ @if (pix(); as dados) {
120
+ <orechio-billing-pix [pix]="dados" [invoiceUrl]="invoiceUrl()" />
121
+ }
122
+ } @else if (!erro()) {
123
+ <p class="orechio-billing__muted">Carregando…</p>
124
+ }
125
+
126
+ @if (erro(); as problema) {
127
+ <orechio-billing-error [problema]="problema" />
128
+ }
129
+
130
+ <a routerLink="..">Voltar para as faturas</a>
131
+ </section>
132
+ `, styles: [".orechio-billing{display:flex;flex-direction:column;gap:var(--orechio-space-3, .75rem);max-width:40rem;margin:0 auto;padding:var(--orechio-space-6, 1.5rem);color:var(--orechio-color-text, inherit);font-family:var(--orechio-font-body, inherit)}.orechio-billing form{display:flex;flex-direction:column;gap:var(--orechio-space-2, .5rem)}.orechio-billing__muted{color:var(--orechio-color-text-muted, #666)}.orechio-billing__error{color:var(--orechio-color-danger, #b00020)}\n"] }]
133
+ }] });
134
+
135
+ export { InvoicePage };
136
+ //# sourceMappingURL=orechio-platform-angular-billing-invoice.page-BVyWur3o.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orechio-platform-angular-billing-invoice.page-BVyWur3o.mjs","sources":["../../../projects/platform-angular/billing/src/pages/invoice.page.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, OnInit, computed, inject, signal } from '@angular/core';\r\nimport { ActivatedRoute, RouterLink } from '@angular/router';\r\nimport { ProblemDetails } from '@orechio/platform-angular';\r\nimport { BillingClient } from '../billing-client';\r\nimport { BillingErrorComponent } from '../billing-error.component';\r\nimport { ESTILO_BASE, STATUS_DA_FATURA, data, moeda } from '../billing-format';\r\nimport { InvoiceDetail, PixData } from '../billing-models';\r\nimport { PixPanelComponent } from '../pix-panel.component';\r\n\r\n/**\r\n * Detalhe de fatura. O detalhe da Platform não traz dado de pagamento (`InvoiceDetailDto`):\r\n * o QR vem do refresh, que a Platform aceita para fatura PIX `Pending` ou `Overdue`\r\n * (`RefreshPaymentDataCommand`, passo 2) — o que inclui a fatura de renovação.\r\n */\r\n@Component({\r\n selector: 'orechio-billing-invoice',\r\n standalone: true,\r\n imports: [RouterLink, BillingErrorComponent, PixPanelComponent],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <section class=\"orechio-billing\">\r\n @if (fatura(); as f) {\r\n <h1>Fatura {{ f.number }}</h1>\r\n <p>{{ status[f.status] }} — {{ moeda(f.amount) }} — vence em {{ data(f.dueDate) }}</p>\r\n <p class=\"orechio-billing__muted\">\r\n {{ f.planNameAtTime }}, de {{ data(f.periodStartsAt) }} a {{ data(f.periodEndsAt) }}\r\n </p>\r\n\r\n <ul>\r\n @for (item of f.items; track item.order) {\r\n <li>{{ item.description }} — {{ item.quantity }} × {{ moeda(item.unitAmount) }} = {{ moeda(item.totalAmount) }}</li>\r\n }\r\n </ul>\r\n\r\n @if (podeGerarQr()) {\r\n <button type=\"button\" data-gerar-qr (click)=\"gerarQr()\" [disabled]=\"gerando()\">\r\n {{ gerando() ? 'Gerando…' : 'Gerar novo QR' }}\r\n </button>\r\n }\r\n\r\n @if (pix(); as dados) {\r\n <orechio-billing-pix [pix]=\"dados\" [invoiceUrl]=\"invoiceUrl()\" />\r\n }\r\n } @else if (!erro()) {\r\n <p class=\"orechio-billing__muted\">Carregando…</p>\r\n }\r\n\r\n @if (erro(); as problema) {\r\n <orechio-billing-error [problema]=\"problema\" />\r\n }\r\n\r\n <a routerLink=\"..\">Voltar para as faturas</a>\r\n </section>\r\n `,\r\n styles: ESTILO_BASE,\r\n})\r\nexport class InvoicePage implements OnInit {\r\n private readonly client = inject(BillingClient);\r\n private readonly route = inject(ActivatedRoute);\r\n\r\n protected readonly status = STATUS_DA_FATURA;\r\n protected readonly moeda = moeda;\r\n protected readonly data = data;\r\n protected readonly fatura = signal<InvoiceDetail | null>(null);\r\n protected readonly pix = signal<PixData | null>(null);\r\n protected readonly invoiceUrl = signal<string | null>(null);\r\n protected readonly gerando = signal(false);\r\n protected readonly erro = signal<ProblemDetails | null>(null);\r\n protected readonly podeGerarQr = computed(() => {\r\n const f = this.fatura();\r\n return !!f && f.paymentMethod === 'Pix' && (f.status === 'Pending' || f.status === 'Overdue');\r\n });\r\n\r\n ngOnInit(): void {\r\n const id = this.route.snapshot.paramMap.get('id') ?? '';\r\n this.client.getInvoice(id).subscribe({\r\n next: (fatura) => this.fatura.set(fatura),\r\n error: (problema: ProblemDetails) => this.erro.set(problema),\r\n });\r\n }\r\n\r\n protected gerarQr(): void {\r\n const f = this.fatura();\r\n if (!f || this.gerando()) return;\r\n\r\n this.gerando.set(true);\r\n this.erro.set(null);\r\n this.client.refreshInvoicePix(f.id).subscribe({\r\n next: (pix) => {\r\n this.gerando.set(false);\r\n // O refresh traz o PIX e o `invoiceUrl` juntos: o link acompanha o QR que está na tela.\r\n this.invoiceUrl.set(pix.invoiceUrl ?? null);\r\n this.pix.set(pix);\r\n },\r\n error: (problema: ProblemDetails) => {\r\n this.gerando.set(false);\r\n this.erro.set(problema);\r\n },\r\n });\r\n }\r\n}\r\n"],"names":[],"mappings":"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"}