@baruk/core 0.5.0 → 0.6.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/.baruk-provenance.json +4 -4
- package/dist/cjs/clients/ibge.js +14 -0
- package/dist/cjs/clients/ibge.js.map +1 -1
- package/dist/cjs/clients/registry/http.js +157 -0
- package/dist/cjs/clients/registry/http.js.map +1 -0
- package/dist/cjs/clients/registry/ibge-municipios.js +28 -0
- package/dist/cjs/clients/registry/ibge-municipios.js.map +1 -0
- package/dist/cjs/clients/registry/ibge.js +63 -0
- package/dist/cjs/clients/registry/ibge.js.map +1 -0
- package/dist/cjs/clients/registry/lookup.js +191 -0
- package/dist/cjs/clients/registry/lookup.js.map +1 -0
- package/dist/cjs/clients/registry/provider.js +34 -0
- package/dist/cjs/clients/registry/provider.js.map +1 -0
- package/dist/cjs/clients/registry/resolve.js +47 -0
- package/dist/cjs/clients/registry/resolve.js.map +1 -0
- package/dist/cjs/clients/registry/serpro.js +149 -0
- package/dist/cjs/clients/registry/serpro.js.map +1 -0
- package/dist/cjs/clients/registry/service.js +230 -0
- package/dist/cjs/clients/registry/service.js.map +1 -0
- package/dist/cjs/clients/registry/synthetic.js +165 -0
- package/dist/cjs/clients/registry/synthetic.js.map +1 -0
- package/dist/cjs/clients/repository.js +6 -2
- package/dist/cjs/clients/repository.js.map +1 -1
- package/dist/cjs/db/provision-e2e-identity.js +8 -3
- package/dist/cjs/db/provision-e2e-identity.js.map +1 -1
- package/dist/cjs/fiscal/collection/authorization.js +186 -0
- package/dist/cjs/fiscal/collection/authorization.js.map +1 -0
- package/dist/cjs/fiscal/collection/competence.js +97 -0
- package/dist/cjs/fiscal/collection/competence.js.map +1 -0
- package/dist/cjs/fiscal/collection/first-contact.js +204 -0
- package/dist/cjs/fiscal/collection/first-contact.js.map +1 -0
- package/dist/cjs/fiscal/collection/plan.js +122 -0
- package/dist/cjs/fiscal/collection/plan.js.map +1 -0
- package/dist/cjs/fiscal/coverage/model.js +11 -1
- package/dist/cjs/fiscal/coverage/model.js.map +1 -1
- package/dist/cjs/fiscal/credentials/inspect.js +182 -0
- package/dist/cjs/fiscal/credentials/inspect.js.map +1 -0
- package/dist/cjs/fiscal/credentials/material.js +1 -1
- package/dist/cjs/fiscal/credentials/material.js.map +1 -1
- package/dist/cjs/fiscal/credentials/onboarding.js +266 -0
- package/dist/cjs/fiscal/credentials/onboarding.js.map +1 -0
- package/dist/cjs/fiscal/credentials/readiness.js +29 -2
- package/dist/cjs/fiscal/credentials/readiness.js.map +1 -1
- package/dist/cjs/fiscal/enrollment.js +134 -0
- package/dist/cjs/fiscal/enrollment.js.map +1 -0
- package/dist/cjs/fiscal/transport/synthetic-tls.js +52 -0
- package/dist/cjs/fiscal/transport/synthetic-tls.js.map +1 -1
- package/dist/cjs/index.js +196 -113
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/legal/documents.js +64 -4
- package/dist/cjs/legal/documents.js.map +1 -1
- package/dist/cjs/legal/types.js.map +1 -1
- package/dist/cjs/platform/capabilities.js +29 -0
- package/dist/cjs/platform/capabilities.js.map +1 -1
- package/dist/cjs/rbac/catalog.js +78 -2
- package/dist/cjs/rbac/catalog.js.map +1 -1
- package/dist/cjs/subscription-billing/index.js +8 -1
- package/dist/cjs/subscription-billing/index.js.map +1 -1
- package/dist/cjs/subscription-billing/platform-exemption.js +121 -0
- package/dist/cjs/subscription-billing/platform-exemption.js.map +1 -0
- package/dist/cjs/subscription-billing/service.js +93 -1
- package/dist/cjs/subscription-billing/service.js.map +1 -1
- package/dist/cjs/vault/repository.js +92 -5
- package/dist/cjs/vault/repository.js.map +1 -1
- package/dist/clients/ibge.d.ts.map +1 -1
- package/dist/clients/ibge.js +14 -0
- package/dist/clients/ibge.js.map +1 -1
- package/dist/clients/registry/http.d.ts +61 -0
- package/dist/clients/registry/http.d.ts.map +1 -0
- package/dist/clients/registry/http.js +151 -0
- package/dist/clients/registry/http.js.map +1 -0
- package/dist/clients/registry/ibge-municipios.d.ts +25 -0
- package/dist/clients/registry/ibge-municipios.d.ts.map +1 -0
- package/dist/clients/registry/ibge-municipios.js +25 -0
- package/dist/clients/registry/ibge-municipios.js.map +1 -0
- package/dist/clients/registry/ibge.d.ts +62 -0
- package/dist/clients/registry/ibge.d.ts.map +1 -0
- package/dist/clients/registry/ibge.js +57 -0
- package/dist/clients/registry/ibge.js.map +1 -0
- package/dist/clients/registry/lookup.d.ts +94 -0
- package/dist/clients/registry/lookup.d.ts.map +1 -0
- package/dist/clients/registry/lookup.js +184 -0
- package/dist/clients/registry/lookup.js.map +1 -0
- package/dist/clients/registry/provider.d.ts +124 -0
- package/dist/clients/registry/provider.d.ts.map +1 -0
- package/dist/clients/registry/provider.js +39 -0
- package/dist/clients/registry/provider.js.map +1 -0
- package/dist/clients/registry/resolve.d.ts +36 -0
- package/dist/clients/registry/resolve.d.ts.map +1 -0
- package/dist/clients/registry/resolve.js +44 -0
- package/dist/clients/registry/resolve.js.map +1 -0
- package/dist/clients/registry/serpro.d.ts +57 -0
- package/dist/clients/registry/serpro.d.ts.map +1 -0
- package/dist/clients/registry/serpro.js +143 -0
- package/dist/clients/registry/serpro.js.map +1 -0
- package/dist/clients/registry/service.d.ts +59 -0
- package/dist/clients/registry/service.d.ts.map +1 -0
- package/dist/clients/registry/service.js +225 -0
- package/dist/clients/registry/service.js.map +1 -0
- package/dist/clients/registry/synthetic.d.ts +30 -0
- package/dist/clients/registry/synthetic.d.ts.map +1 -0
- package/dist/clients/registry/synthetic.js +161 -0
- package/dist/clients/registry/synthetic.js.map +1 -0
- package/dist/clients/repository.d.ts +4 -0
- package/dist/clients/repository.d.ts.map +1 -1
- package/dist/clients/repository.js +6 -2
- package/dist/clients/repository.js.map +1 -1
- package/dist/db/provision-e2e-identity.js +8 -3
- package/dist/db/provision-e2e-identity.js.map +1 -1
- package/dist/fiscal/collection/authorization.d.ts +152 -0
- package/dist/fiscal/collection/authorization.d.ts.map +1 -0
- package/dist/fiscal/collection/authorization.js +178 -0
- package/dist/fiscal/collection/authorization.js.map +1 -0
- package/dist/fiscal/collection/competence.d.ts +66 -0
- package/dist/fiscal/collection/competence.d.ts.map +1 -0
- package/dist/fiscal/collection/competence.js +90 -0
- package/dist/fiscal/collection/competence.js.map +1 -0
- package/dist/fiscal/collection/first-contact.d.ts +103 -0
- package/dist/fiscal/collection/first-contact.d.ts.map +1 -0
- package/dist/fiscal/collection/first-contact.js +201 -0
- package/dist/fiscal/collection/first-contact.js.map +1 -0
- package/dist/fiscal/collection/plan.d.ts +74 -0
- package/dist/fiscal/collection/plan.d.ts.map +1 -0
- package/dist/fiscal/collection/plan.js +119 -0
- package/dist/fiscal/collection/plan.js.map +1 -0
- package/dist/fiscal/coverage/model.d.ts +28 -0
- package/dist/fiscal/coverage/model.d.ts.map +1 -1
- package/dist/fiscal/coverage/model.js +11 -1
- package/dist/fiscal/coverage/model.js.map +1 -1
- package/dist/fiscal/credentials/inspect.d.ts +114 -0
- package/dist/fiscal/credentials/inspect.d.ts.map +1 -0
- package/dist/fiscal/credentials/inspect.js +178 -0
- package/dist/fiscal/credentials/inspect.js.map +1 -0
- package/dist/fiscal/credentials/material.js +2 -2
- package/dist/fiscal/credentials/material.js.map +1 -1
- package/dist/fiscal/credentials/onboarding.d.ts +119 -0
- package/dist/fiscal/credentials/onboarding.d.ts.map +1 -0
- package/dist/fiscal/credentials/onboarding.js +259 -0
- package/dist/fiscal/credentials/onboarding.js.map +1 -0
- package/dist/fiscal/credentials/readiness.d.ts +30 -3
- package/dist/fiscal/credentials/readiness.d.ts.map +1 -1
- package/dist/fiscal/credentials/readiness.js +29 -2
- package/dist/fiscal/credentials/readiness.js.map +1 -1
- package/dist/fiscal/enrollment.d.ts +91 -0
- package/dist/fiscal/enrollment.d.ts.map +1 -0
- package/dist/fiscal/enrollment.js +126 -0
- package/dist/fiscal/enrollment.js.map +1 -0
- package/dist/fiscal/transport/synthetic-tls.d.ts +19 -0
- package/dist/fiscal/transport/synthetic-tls.d.ts.map +1 -1
- package/dist/fiscal/transport/synthetic-tls.js +51 -0
- package/dist/fiscal/transport/synthetic-tls.js.map +1 -1
- package/dist/index.d.ts +32 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -2
- package/dist/index.js.map +1 -1
- package/dist/legal/documents.d.ts.map +1 -1
- package/dist/legal/documents.js +64 -4
- package/dist/legal/documents.js.map +1 -1
- package/dist/legal/index.d.ts +1 -1
- package/dist/legal/index.d.ts.map +1 -1
- package/dist/legal/types.d.ts +77 -0
- package/dist/legal/types.d.ts.map +1 -1
- package/dist/legal/types.js.map +1 -1
- package/dist/platform/capabilities.d.ts.map +1 -1
- package/dist/platform/capabilities.js +29 -0
- package/dist/platform/capabilities.js.map +1 -1
- package/dist/rbac/catalog.d.ts.map +1 -1
- package/dist/rbac/catalog.js +78 -2
- package/dist/rbac/catalog.js.map +1 -1
- package/dist/subscription-billing/index.d.ts +3 -1
- package/dist/subscription-billing/index.d.ts.map +1 -1
- package/dist/subscription-billing/index.js +2 -1
- package/dist/subscription-billing/index.js.map +1 -1
- package/dist/subscription-billing/platform-exemption.d.ts +89 -0
- package/dist/subscription-billing/platform-exemption.d.ts.map +1 -0
- package/dist/subscription-billing/platform-exemption.js +113 -0
- package/dist/subscription-billing/platform-exemption.js.map +1 -0
- package/dist/subscription-billing/service.d.ts +53 -0
- package/dist/subscription-billing/service.d.ts.map +1 -1
- package/dist/subscription-billing/service.js +92 -1
- package/dist/subscription-billing/service.js.map +1 -1
- package/dist/vault/repository.d.ts +69 -1
- package/dist/vault/repository.d.ts.map +1 -1
- package/dist/vault/repository.js +88 -5
- package/dist/vault/repository.js.map +1 -1
- package/package.json +3 -2
- package/src/db/migrations/0060_fiscal_credential_vault_and_run_authorization.sql +321 -0
- package/src/db/migrations/0061_client_official_registry_provenance.sql +193 -0
- package/src/db/migrations/0062_first_contact_and_capability_truth.sql +119 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuthorizationConflictError = void 0;
|
|
4
|
+
exports.grantRunAuthorization = grantRunAuthorization;
|
|
5
|
+
exports.consumeRunAuthorization = consumeRunAuthorization;
|
|
6
|
+
exports.revokeRunAuthorization = revokeRunAuthorization;
|
|
7
|
+
exports.listRunAuthorizations = listRunAuthorizations;
|
|
8
|
+
const shared_1 = require("@baruk/shared");
|
|
9
|
+
const competence_js_1 = require("./competence.js");
|
|
10
|
+
class AuthorizationConflictError extends Error {
|
|
11
|
+
detail;
|
|
12
|
+
constructor(detail) {
|
|
13
|
+
super(`autorização recusada: ${detail}`);
|
|
14
|
+
this.detail = detail;
|
|
15
|
+
this.name = 'AuthorizationConflictError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.AuthorizationConflictError = AuthorizationConflictError;
|
|
19
|
+
const DEFAULT_VALIDITY_HOURS = 48;
|
|
20
|
+
const MAX_VALIDITY_HOURS = 168; // sete dias
|
|
21
|
+
/**
|
|
22
|
+
* Emite a autorização.
|
|
23
|
+
*
|
|
24
|
+
* Recusa por CONFLITO quando já existe uma viva para o mesmo par
|
|
25
|
+
* (cliente, fonte, ambiente, competência) — não por capricho de unicidade, mas
|
|
26
|
+
* porque duas autorizações vivas somam duas execuções, e o produto teria
|
|
27
|
+
* prometido uma.
|
|
28
|
+
*
|
|
29
|
+
* A unicidade é do índice parcial da 0060; o `SELECT` prévio existe só para
|
|
30
|
+
* devolver um erro legível em vez de uma violação de constraint.
|
|
31
|
+
*/
|
|
32
|
+
async function grantRunAuthorization(tx, input) {
|
|
33
|
+
const competence = (0, competence_js_1.competenceOf)(input.competenceYear, input.competenceMonth);
|
|
34
|
+
const periodStart = input.periodStart ?? competence.periodStart;
|
|
35
|
+
const periodEnd = input.periodEnd ?? competence.periodEnd;
|
|
36
|
+
(0, competence_js_1.validateWindow)(competence, periodStart, periodEnd);
|
|
37
|
+
const hours = input.validForHours ?? DEFAULT_VALIDITY_HOURS;
|
|
38
|
+
if (!Number.isInteger(hours) || hours < 1 || hours > MAX_VALIDITY_HOURS) {
|
|
39
|
+
throw new AuthorizationConflictError(`validade deve estar entre 1 e ${MAX_VALIDITY_HOURS} horas`);
|
|
40
|
+
}
|
|
41
|
+
const live = await tx `
|
|
42
|
+
SELECT id FROM fiscal_run_authorization
|
|
43
|
+
WHERE client_id = ${input.clientId}
|
|
44
|
+
AND source = ${input.source}
|
|
45
|
+
AND environment = ${input.environment}
|
|
46
|
+
AND competence_year = ${competence.year}
|
|
47
|
+
AND competence_month = ${competence.month}
|
|
48
|
+
AND consumed_at IS NULL AND revoked_at IS NULL
|
|
49
|
+
LIMIT 1
|
|
50
|
+
`;
|
|
51
|
+
if (live[0]) {
|
|
52
|
+
throw new AuthorizationConflictError('já existe uma autorização viva para este cliente, fonte, ambiente e competência');
|
|
53
|
+
}
|
|
54
|
+
const rows = await tx `
|
|
55
|
+
INSERT INTO fiscal_run_authorization (
|
|
56
|
+
id, tenant_id, client_id, document_type, environment, source, credential_kind,
|
|
57
|
+
operation, competence_year, competence_month, period_start, period_end,
|
|
58
|
+
max_runs, runs_consumed, authorized_by, responsible_name, expires_at,
|
|
59
|
+
first_contact, trigger_kind, credential_fingerprint
|
|
60
|
+
) VALUES (
|
|
61
|
+
${(0, shared_1.uuidv7)()}, current_setting('app.current_tenant')::uuid, ${input.clientId},
|
|
62
|
+
${input.documentType}, ${input.environment}, ${input.source},
|
|
63
|
+
${input.credentialKind ?? 'certificate_a1'},
|
|
64
|
+
'READ_ONLY', ${competence.year}, ${competence.month}, ${periodStart}, ${periodEnd},
|
|
65
|
+
1, 0, ${input.authorizedBy}, ${input.responsibleName ?? null},
|
|
66
|
+
now() + (${hours}::int * interval '1 hour'),
|
|
67
|
+
${input.firstContact ?? false}, ${input.triggerKind ?? 'manual'},
|
|
68
|
+
${input.credentialFingerprint ?? null}
|
|
69
|
+
)
|
|
70
|
+
RETURNING ${tx.unsafe(AUTHORIZATION_COLUMNS)}
|
|
71
|
+
`;
|
|
72
|
+
return mapAuthorization(rows[0]);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Consome a autorização — e é AQUI que a unicidade da execução acontece.
|
|
76
|
+
*
|
|
77
|
+
* Um `SELECT` seguido de `UPDATE` deixaria a janela em que dois processos leem
|
|
78
|
+
* "viva" e ambos executam. O `WHERE consumed_at IS NULL` dentro do próprio
|
|
79
|
+
* `UPDATE` fecha essa janela no banco: o segundo afeta zero linhas e recebe
|
|
80
|
+
* `null`, que é o sinal de "não execute".
|
|
81
|
+
*
|
|
82
|
+
* Devolve `null` — e não lança — para todo desfecho de recusa. Quem chama é o
|
|
83
|
+
* orquestrador no meio de uma carteira, e uma exceção aqui derrubaria o lote por
|
|
84
|
+
* causa de um portão fechado, que é estado normal.
|
|
85
|
+
*/
|
|
86
|
+
async function consumeRunAuthorization(tx, input) {
|
|
87
|
+
const rows = await tx `
|
|
88
|
+
UPDATE fiscal_run_authorization SET
|
|
89
|
+
runs_consumed = runs_consumed + 1,
|
|
90
|
+
consumed_at = now(),
|
|
91
|
+
consumed_by_run_id = ${input.runId},
|
|
92
|
+
updated_at = now()
|
|
93
|
+
WHERE id = ${input.authorizationId}
|
|
94
|
+
AND consumed_at IS NULL
|
|
95
|
+
AND revoked_at IS NULL
|
|
96
|
+
AND expires_at > now()
|
|
97
|
+
AND runs_consumed < max_runs
|
|
98
|
+
RETURNING ${tx.unsafe(AUTHORIZATION_COLUMNS)}
|
|
99
|
+
`;
|
|
100
|
+
return rows[0] ? mapAuthorization(rows[0]) : null;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Cancela antes da execução.
|
|
104
|
+
*
|
|
105
|
+
* O mecanismo de abortar (C1.34) não precisa de tabela nova: revogar a
|
|
106
|
+
* autorização é o cancelamento, porque sem ela não há execução real. Revogar uma
|
|
107
|
+
* já consumida é permitido e não desfaz nada — só registra a decisão, para o
|
|
108
|
+
* caso em que alguém descobre depois que não deveria ter autorizado.
|
|
109
|
+
*/
|
|
110
|
+
async function revokeRunAuthorization(tx, input) {
|
|
111
|
+
const rows = await tx `
|
|
112
|
+
UPDATE fiscal_run_authorization SET
|
|
113
|
+
revoked_at = now(), revoked_by = ${input.revokedBy},
|
|
114
|
+
revoke_reason = ${input.reason}, updated_at = now()
|
|
115
|
+
WHERE id = ${input.authorizationId} AND revoked_at IS NULL
|
|
116
|
+
RETURNING id
|
|
117
|
+
`;
|
|
118
|
+
return rows.count > 0;
|
|
119
|
+
}
|
|
120
|
+
/** As autorizações de um cliente, mais recentes primeiro. Sem segredo por construção. */
|
|
121
|
+
async function listRunAuthorizations(tx, clientId) {
|
|
122
|
+
const rows = await tx `
|
|
123
|
+
SELECT ${tx.unsafe(AUTHORIZATION_COLUMNS)}
|
|
124
|
+
FROM fiscal_run_authorization
|
|
125
|
+
WHERE client_id = ${clientId}
|
|
126
|
+
ORDER BY authorized_at DESC
|
|
127
|
+
LIMIT 50
|
|
128
|
+
`;
|
|
129
|
+
return rows.map(mapAuthorization);
|
|
130
|
+
}
|
|
131
|
+
const AUTHORIZATION_COLUMNS = `
|
|
132
|
+
id, client_id, document_type, environment, source, credential_kind, operation,
|
|
133
|
+
competence_year, competence_month, period_start, period_end, max_runs, runs_consumed,
|
|
134
|
+
authorized_by, authorized_at, responsible_name, expires_at, consumed_at,
|
|
135
|
+
revoked_at, revoke_reason, first_contact, trigger_kind, credential_fingerprint
|
|
136
|
+
`;
|
|
137
|
+
function mapAuthorization(r) {
|
|
138
|
+
return {
|
|
139
|
+
id: r.id,
|
|
140
|
+
clientId: r.client_id,
|
|
141
|
+
documentType: r.document_type,
|
|
142
|
+
environment: r.environment,
|
|
143
|
+
source: r.source,
|
|
144
|
+
credentialKind: r.credential_kind,
|
|
145
|
+
operation: 'READ_ONLY',
|
|
146
|
+
competence: {
|
|
147
|
+
year: r.competence_year,
|
|
148
|
+
month: r.competence_month,
|
|
149
|
+
label: `${r.competence_year}-${String(r.competence_month).padStart(2, '0')}`,
|
|
150
|
+
periodStart: isoDate(r.period_start),
|
|
151
|
+
periodEnd: isoDate(r.period_end),
|
|
152
|
+
},
|
|
153
|
+
maxRuns: r.max_runs,
|
|
154
|
+
runsConsumed: r.runs_consumed,
|
|
155
|
+
authorizedBy: r.authorized_by,
|
|
156
|
+
authorizedAt: r.authorized_at.toISOString(),
|
|
157
|
+
responsibleName: r.responsible_name,
|
|
158
|
+
firstContact: r.first_contact ?? false,
|
|
159
|
+
triggerKind: r.trigger_kind ?? 'manual',
|
|
160
|
+
credentialFingerprint: r.credential_fingerprint ?? null,
|
|
161
|
+
expiresAt: r.expires_at.toISOString(),
|
|
162
|
+
consumedAt: r.consumed_at?.toISOString() ?? null,
|
|
163
|
+
revokedAt: r.revoked_at?.toISOString() ?? null,
|
|
164
|
+
revokeReason: r.revoke_reason,
|
|
165
|
+
state: stateOf(r),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* A ordem das perguntas importa: revogada vence consumida, que vence vencida.
|
|
170
|
+
*
|
|
171
|
+
* Uma autorização consumida e depois revogada deve aparecer como revogada — é a
|
|
172
|
+
* decisão mais recente, e é a que alguém precisa ver ao investigar.
|
|
173
|
+
*/
|
|
174
|
+
function stateOf(r) {
|
|
175
|
+
if (r.revoked_at)
|
|
176
|
+
return 'revoked';
|
|
177
|
+
if (r.consumed_at)
|
|
178
|
+
return 'consumed';
|
|
179
|
+
if (r.expires_at.getTime() <= Date.now())
|
|
180
|
+
return 'expired';
|
|
181
|
+
return 'live';
|
|
182
|
+
}
|
|
183
|
+
function isoDate(d) {
|
|
184
|
+
return d.toISOString().slice(0, 10);
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=authorization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorization.js","sourceRoot":"","sources":["../../../../src/fiscal/collection/authorization.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* A janela da coleta — dita por extenso, nunca deduzida.
|
|
4
|
+
*
|
|
5
|
+
* ## O relato que originou este módulo
|
|
6
|
+
*
|
|
7
|
+
* A equipe do escritório chama de "dar baixa nas notas" o trabalho de, na virada
|
|
8
|
+
* do mês, entrar nos portais e recolher os documentos do período. Ao descrever
|
|
9
|
+
* esse trabalho, o relato humano trouxe exemplos de datas que não fechavam entre
|
|
10
|
+
* si — o que é absolutamente normal em conversa, e absolutamente perigoso como
|
|
11
|
+
* fonte de regra.
|
|
12
|
+
*
|
|
13
|
+
* A tentação é transformar "mês anterior" em constante. O erro que isso produz é
|
|
14
|
+
* silencioso: uma coleta rodada em 01/11 sobre uma janela que ninguém confirmou
|
|
15
|
+
* traz documentos de um período que não é o que a pessoa tinha em mente, e a
|
|
16
|
+
* ausência do que faltava só aparece no fechamento.
|
|
17
|
+
*
|
|
18
|
+
* Aqui a competência é um par ano/mês, e o período é um par de DATAS derivado
|
|
19
|
+
* dele. A sugestão padrão existe — mês calendário anterior —, mas ela é uma
|
|
20
|
+
* SUGESTÃO exibida, não um valor implícito: a tela mostra "serão consultados
|
|
21
|
+
* documentos de DD/MM/AAAA a DD/MM/AAAA" antes de qualquer execução, e as duas
|
|
22
|
+
* datas são gravadas na autorização.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.DEFAULT_COMPETENCE_POLICY = exports.InvalidCompetenceError = void 0;
|
|
26
|
+
exports.competenceOf = competenceOf;
|
|
27
|
+
exports.suggestCompetenceFor = suggestCompetenceFor;
|
|
28
|
+
exports.validateWindow = validateWindow;
|
|
29
|
+
class InvalidCompetenceError extends Error {
|
|
30
|
+
detail;
|
|
31
|
+
constructor(detail) {
|
|
32
|
+
super(`competência inválida: ${detail}`);
|
|
33
|
+
this.detail = detail;
|
|
34
|
+
this.name = 'InvalidCompetenceError';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.InvalidCompetenceError = InvalidCompetenceError;
|
|
38
|
+
/** A política padrão desta fase, nomeada para poder ser citada e mudada. */
|
|
39
|
+
exports.DEFAULT_COMPETENCE_POLICY = 'PREVIOUS_CALENDAR_MONTH';
|
|
40
|
+
/**
|
|
41
|
+
* A competência de um par ano/mês.
|
|
42
|
+
*
|
|
43
|
+
* O último dia sai do calendário: `Date.UTC(ano, mês, 0)` — com o mês em base 1
|
|
44
|
+
* — devolve o último dia daquele mês. Fevereiro bissexto sai de graça, que é o
|
|
45
|
+
* ponto de não escrever `30`.
|
|
46
|
+
*/
|
|
47
|
+
function competenceOf(year, month) {
|
|
48
|
+
if (!Number.isInteger(year) || year < 2000 || year > 2100) {
|
|
49
|
+
throw new InvalidCompetenceError('ano fora de 2000–2100');
|
|
50
|
+
}
|
|
51
|
+
if (!Number.isInteger(month) || month < 1 || month > 12) {
|
|
52
|
+
throw new InvalidCompetenceError('mês fora de 1–12');
|
|
53
|
+
}
|
|
54
|
+
const mm = String(month).padStart(2, '0');
|
|
55
|
+
const lastDay = new Date(Date.UTC(year, month, 0)).getUTCDate();
|
|
56
|
+
return {
|
|
57
|
+
year,
|
|
58
|
+
month,
|
|
59
|
+
label: `${year}-${mm}`,
|
|
60
|
+
periodStart: `${year}-${mm}-01`,
|
|
61
|
+
periodEnd: `${year}-${mm}-${String(lastDay).padStart(2, '0')}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* A SUGESTÃO padrão para uma execução feita em `reference`: o mês calendário
|
|
66
|
+
* anterior.
|
|
67
|
+
*
|
|
68
|
+
* Chama-se `suggest` e não `default` de propósito. Uma função chamada
|
|
69
|
+
* `defaultCompetence()` acaba sendo usada como valor efetivo por quem não leu;
|
|
70
|
+
* `suggestCompetenceFor()` obriga quem chama a decidir o que fazer com a
|
|
71
|
+
* sugestão — que é exibi-la ao lado das duas datas.
|
|
72
|
+
*/
|
|
73
|
+
function suggestCompetenceFor(reference) {
|
|
74
|
+
const year = reference.getUTCFullYear();
|
|
75
|
+
const month = reference.getUTCMonth() + 1; // base 1
|
|
76
|
+
return month === 1 ? competenceOf(year - 1, 12) : competenceOf(year, month - 1);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Confere uma janela informada à mão contra a competência declarada.
|
|
80
|
+
*
|
|
81
|
+
* Permitir janela manual e conferi-la não são opostos: o operador pode querer um
|
|
82
|
+
* recorte menor dentro do mês — o que é legítimo —, mas uma janela que atravessa
|
|
83
|
+
* a competência declarada significa que um dos dois campos está errado, e gravar
|
|
84
|
+
* os dois deixaria a autorização dizendo duas coisas.
|
|
85
|
+
*/
|
|
86
|
+
function validateWindow(competence, periodStart, periodEnd) {
|
|
87
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(periodStart) || !/^\d{4}-\d{2}-\d{2}$/.test(periodEnd)) {
|
|
88
|
+
throw new InvalidCompetenceError('datas devem estar em YYYY-MM-DD');
|
|
89
|
+
}
|
|
90
|
+
if (periodEnd < periodStart) {
|
|
91
|
+
throw new InvalidCompetenceError('data final anterior à inicial');
|
|
92
|
+
}
|
|
93
|
+
if (periodStart < competence.periodStart || periodEnd > competence.periodEnd) {
|
|
94
|
+
throw new InvalidCompetenceError(`janela ${periodStart}..${periodEnd} sai da competência ${competence.label}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=competence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"competence.js","sourceRoot":"","sources":["../../../../src/fiscal/collection/competence.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;;;AA8BH,oCAgBC;AAWD,oDAIC;AAUD,wCAgBC;AA1ED,MAAa,sBAAuB,SAAQ,KAAK;IAC1B;IAArB,YAAqB,MAAc;QACjC,KAAK,CAAC,yBAAyB,MAAM,EAAE,CAAC,CAAC;QADtB,WAAM,GAAN,MAAM,CAAQ;QAEjC,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AALD,wDAKC;AAED,4EAA4E;AAC/D,QAAA,yBAAyB,GAAG,yBAAkC,CAAC;AAE5E;;;;;;GAMG;AACH,SAAgB,YAAY,CAAC,IAAY,EAAE,KAAa;IACtD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC;QAC1D,MAAM,IAAI,sBAAsB,CAAC,uBAAuB,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE,EAAE,CAAC;QACxD,MAAM,IAAI,sBAAsB,CAAC,kBAAkB,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;IAChE,OAAO;QACL,IAAI;QACJ,KAAK;QACL,KAAK,EAAE,GAAG,IAAI,IAAI,EAAE,EAAE;QACtB,WAAW,EAAE,GAAG,IAAI,IAAI,EAAE,KAAK;QAC/B,SAAS,EAAE,GAAG,IAAI,IAAI,EAAE,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;KAC/D,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,oBAAoB,CAAC,SAAe;IAClD,MAAM,IAAI,GAAG,SAAS,CAAC,cAAc,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS;IACpD,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;AAClF,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,cAAc,CAC5B,UAA4B,EAC5B,WAAmB,EACnB,SAAiB;IAEjB,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACvF,MAAM,IAAI,sBAAsB,CAAC,iCAAiC,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,SAAS,GAAG,WAAW,EAAE,CAAC;QAC5B,MAAM,IAAI,sBAAsB,CAAC,+BAA+B,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,WAAW,GAAG,UAAU,CAAC,WAAW,IAAI,SAAS,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC;QAC7E,MAAM,IAAI,sBAAsB,CAC9B,UAAU,WAAW,KAAK,SAAS,uBAAuB,UAAU,CAAC,KAAK,EAAE,CAC7E,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runFirstContact = runFirstContact;
|
|
4
|
+
const shared_1 = require("@baruk/shared");
|
|
5
|
+
const audit_js_1 = require("../../audit/audit.js");
|
|
6
|
+
const model_js_1 = require("../coverage/model.js");
|
|
7
|
+
const readiness_js_1 = require("../credentials/readiness.js");
|
|
8
|
+
const eligibility_js_1 = require("../eligibility.js");
|
|
9
|
+
const authorization_js_1 = require("./authorization.js");
|
|
10
|
+
const recusa = (reason, detail) => ({
|
|
11
|
+
status: 'refused',
|
|
12
|
+
reason,
|
|
13
|
+
detail,
|
|
14
|
+
});
|
|
15
|
+
/**
|
|
16
|
+
* Executa o primeiro contato — ou recusa, dizendo exatamente por quê.
|
|
17
|
+
*
|
|
18
|
+
* A ordem dos portões é deliberada e vai do mais barato ao mais caro, com uma
|
|
19
|
+
* regra acima de tudo: **nada que toque credencial ou rede acontece antes de
|
|
20
|
+
* todos os portões de papel terem passado**. Um portão que fechasse depois de o
|
|
21
|
+
* cofre ter sido aberto já teria custado o que se queria evitar.
|
|
22
|
+
*/
|
|
23
|
+
async function runFirstContact(tx, input) {
|
|
24
|
+
const now = input.now ?? new Date();
|
|
25
|
+
// ═══ 1 · A autorização existe, e é DESTE escopo ═════════════════════════
|
|
26
|
+
const [auth] = await tx `
|
|
27
|
+
SELECT id, tenant_id, client_id, source, environment, competence_year, competence_month,
|
|
28
|
+
operation, first_contact, trigger_kind, credential_fingerprint,
|
|
29
|
+
expires_at, consumed_at, revoked_at
|
|
30
|
+
FROM fiscal_run_authorization
|
|
31
|
+
WHERE id = ${input.authorizationId}
|
|
32
|
+
`;
|
|
33
|
+
if (!auth)
|
|
34
|
+
return recusa('authorization_not_found', 'autorização inexistente');
|
|
35
|
+
// Cada binding é conferido em separado, e a recusa NOMEIA qual falhou. Um
|
|
36
|
+
// "não autorizado" genérico faria toda investigação começar do zero.
|
|
37
|
+
if (auth.tenant_id !== input.tenantId) {
|
|
38
|
+
return recusa('tenant_mismatch', 'autorização é de outra organização');
|
|
39
|
+
}
|
|
40
|
+
if (auth.client_id !== input.clientId) {
|
|
41
|
+
return recusa('client_mismatch', 'autorização é de outro cliente');
|
|
42
|
+
}
|
|
43
|
+
if (auth.source !== input.connector) {
|
|
44
|
+
return recusa('connector_mismatch', `autorização é do conector ${auth.source}`);
|
|
45
|
+
}
|
|
46
|
+
if (auth.competence_year !== input.competenceYear ||
|
|
47
|
+
auth.competence_month !== input.competenceMonth) {
|
|
48
|
+
return recusa('competence_mismatch', 'autorização é de outra competência');
|
|
49
|
+
}
|
|
50
|
+
if (!auth.first_contact) {
|
|
51
|
+
return recusa('authorization_not_first_contact', 'esta autorização não declara primeiro contato');
|
|
52
|
+
}
|
|
53
|
+
if (auth.trigger_kind !== 'manual') {
|
|
54
|
+
return recusa('authorization_scheduled_trigger', 'primeiro contato não aceita agendamento');
|
|
55
|
+
}
|
|
56
|
+
if (auth.revoked_at)
|
|
57
|
+
return recusa('authorization_revoked', 'autorização revogada');
|
|
58
|
+
if (auth.consumed_at)
|
|
59
|
+
return recusa('authorization_already_consumed', 'autorização já consumida');
|
|
60
|
+
if (auth.expires_at <= now)
|
|
61
|
+
return recusa('authorization_expired', 'autorização expirada');
|
|
62
|
+
// ═══ 2 · O escritório e o cliente disseram sim ══════════════════════════
|
|
63
|
+
//
|
|
64
|
+
// A elegibilidade é default-deny e cobre habilitação do tenant e matrícula do
|
|
65
|
+
// cliente. Ela é consultada AQUI, e não confiada à tela: a tela é uma
|
|
66
|
+
// conveniência, o portão é isto.
|
|
67
|
+
const eligibility = await (0, eligibility_js_1.evaluateFiscalEligibility)(tx, {
|
|
68
|
+
clientId: input.clientId,
|
|
69
|
+
documentType: documentTypeOf(input.connector),
|
|
70
|
+
environment: input.environment,
|
|
71
|
+
});
|
|
72
|
+
if (!eligibility.eligible) {
|
|
73
|
+
const razoes = new Set(eligibility.reasons);
|
|
74
|
+
if (razoes.has('client_not_enrolled')) {
|
|
75
|
+
return recusa('client_not_enrolled', 'cliente sem matrícula fiscal para este documento');
|
|
76
|
+
}
|
|
77
|
+
if (razoes.has('tenant_automation_disabled') || razoes.has('environment_mismatch')) {
|
|
78
|
+
return recusa('tenant_automation_disabled', 'organização sem automação fiscal habilitada');
|
|
79
|
+
}
|
|
80
|
+
// `credential_not_ready` é ESPERADO aqui — o primeiro contato existe
|
|
81
|
+
// justamente para o caso em que a credencial ainda não foi aceita. Só ele
|
|
82
|
+
// é tolerado; qualquer outro motivo continua fechando.
|
|
83
|
+
const outros = [...razoes].filter((r) => r !== 'credential_not_ready' && r !== 'real_operation_not_declared');
|
|
84
|
+
if (outros.length > 0) {
|
|
85
|
+
return recusa('client_not_enrolled', `inelegível: ${outros.join(', ')}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// ═══ 3 · O conector existe DE VERDADE ══════════════════════════════════
|
|
89
|
+
//
|
|
90
|
+
// Aqui mora a correção da leitura que a C2 encontrou: cobertura oficial é
|
|
91
|
+
// fato do mundo; adaptador implementado é fato do repositório. Autorizar
|
|
92
|
+
// contra um conector inexistente falharia adiante com um erro de sistema, e a
|
|
93
|
+
// tela culparia o certificado.
|
|
94
|
+
const coverage = await (0, model_js_1.coverageForClient)(tx, {
|
|
95
|
+
clientId: input.clientId,
|
|
96
|
+
documentType: documentTypeOf(input.connector),
|
|
97
|
+
});
|
|
98
|
+
if (!coverage.connectorImplemented) {
|
|
99
|
+
return recusa('connector_not_implemented', 'este conector ainda não existe no produto');
|
|
100
|
+
}
|
|
101
|
+
if (!coverage.protocolVerified) {
|
|
102
|
+
return recusa('protocol_not_verified', 'o contrato do provedor não foi conferido');
|
|
103
|
+
}
|
|
104
|
+
if (!input.realTransportEnabled) {
|
|
105
|
+
return recusa('real_transport_disabled', 'transporte real desabilitado para este conector');
|
|
106
|
+
}
|
|
107
|
+
// ═══ 4 · A credencial: local válida, e ainda não aceita ═════════════════
|
|
108
|
+
const credential = await (0, readiness_js_1.readFiscalCredentialReadiness)(tx, {
|
|
109
|
+
clientId: input.clientId,
|
|
110
|
+
environment: input.environment,
|
|
111
|
+
source: input.connector,
|
|
112
|
+
});
|
|
113
|
+
if (credential.state === 'READY') {
|
|
114
|
+
// Já aceita: não há primeiro contato a fazer, e insistir gastaria uma
|
|
115
|
+
// requisição autenticada para descobrir o que já se sabe.
|
|
116
|
+
return recusa('credential_already_verified', 'esta credencial já foi aceita pelo ambiente');
|
|
117
|
+
}
|
|
118
|
+
if (!credential.eligibleForFirstContact) {
|
|
119
|
+
return recusa('credential_not_local_valid', `credencial em estado ${credential.state}`);
|
|
120
|
+
}
|
|
121
|
+
// O material aprovado é o material que vai. Trocar o certificado depois de
|
|
122
|
+
// autorizar invalida a autorização — quem assinou aprovou UM arquivo.
|
|
123
|
+
if (auth.credential_fingerprint && auth.credential_fingerprint !== credential.fingerprint) {
|
|
124
|
+
return recusa('credential_fingerprint_mismatch', 'o certificado mudou depois desta autorização');
|
|
125
|
+
}
|
|
126
|
+
// ═══ 5 · A reivindicação — e o banco decide quem ganha ══════════════════
|
|
127
|
+
//
|
|
128
|
+
// O `UPDATE ... WHERE consumed_at IS NULL` de `consumeRunAuthorization` é o
|
|
129
|
+
// que torna a execução única sob concorrência. Dois processos chegando juntos
|
|
130
|
+
// aqui: um recebe a linha, o outro recebe `null`. Nenhum `if` em TypeScript
|
|
131
|
+
// consegue essa garantia.
|
|
132
|
+
const runId = (0, shared_1.uuidv7)();
|
|
133
|
+
const claimed = await (0, authorization_js_1.consumeRunAuthorization)(tx, {
|
|
134
|
+
authorizationId: input.authorizationId,
|
|
135
|
+
runId,
|
|
136
|
+
});
|
|
137
|
+
if (!claimed) {
|
|
138
|
+
return recusa('claim_lost', 'outra execução reivindicou esta autorização primeiro');
|
|
139
|
+
}
|
|
140
|
+
// ═══ 6 · Só agora se fala com o provedor ═══════════════════════════════
|
|
141
|
+
let probe;
|
|
142
|
+
try {
|
|
143
|
+
probe = await input.probe();
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// Exceção do transporte não atravessa: a mensagem de um cliente HTTP cita a
|
|
147
|
+
// URL, e URL de provedor carrega credencial.
|
|
148
|
+
probe = { accepted: false, failureCode: 'transport' };
|
|
149
|
+
}
|
|
150
|
+
// O registro do desfecho.
|
|
151
|
+
//
|
|
152
|
+
// `CASE` em vez de montar SQL condicional: um fragmento interpolado no meio
|
|
153
|
+
// de um `SET` é o tipo de construção que funciona no teste e produz sintaxe
|
|
154
|
+
// inválida no primeiro campo a mais.
|
|
155
|
+
//
|
|
156
|
+
// E a tentativa é registrada nos DOIS desfechos — "tentou e o ambiente
|
|
157
|
+
// recusou" e "nunca tentou" pedem coisas opostas de quem opera, e sem esta
|
|
158
|
+
// coluna eram indistinguíveis.
|
|
159
|
+
const falha = probe.accepted ? null : (probe.failureCode ?? 'unknown');
|
|
160
|
+
await tx `
|
|
161
|
+
UPDATE digital_certificate
|
|
162
|
+
SET remote_verification_last_attempt_at = ${now},
|
|
163
|
+
last_verification_error = ${falha},
|
|
164
|
+
verified_at = CASE WHEN ${probe.accepted} THEN ${now} ELSE verified_at END,
|
|
165
|
+
verified_by = CASE WHEN ${probe.accepted} THEN ${input.actorId}::uuid ELSE verified_by END,
|
|
166
|
+
remote_verification_provider =
|
|
167
|
+
CASE WHEN ${probe.accepted} THEN ${input.connector} ELSE remote_verification_provider END,
|
|
168
|
+
updated_at = now()
|
|
169
|
+
WHERE client_id = ${input.clientId}
|
|
170
|
+
AND deleted_at IS NULL
|
|
171
|
+
AND local_validated_at IS NOT NULL
|
|
172
|
+
-- O certificado EXATO que foi aprovado. Sem isto, um cliente com dois
|
|
173
|
+
-- certificados teria os dois marcados por uma execução que usou um só.
|
|
174
|
+
AND (${credential.fingerprint}::text IS NULL OR fingerprint_sha256 = ${credential.fingerprint})
|
|
175
|
+
`;
|
|
176
|
+
await (0, audit_js_1.appendAudit)(tx, {
|
|
177
|
+
actorId: input.actorId,
|
|
178
|
+
action: probe.accepted ? 'fiscal_first_contact_accepted' : 'fiscal_first_contact_refused',
|
|
179
|
+
resourceType: 'fiscal_run_authorization',
|
|
180
|
+
resourceId: input.authorizationId,
|
|
181
|
+
metadata: {
|
|
182
|
+
runId,
|
|
183
|
+
connector: input.connector,
|
|
184
|
+
environment: input.environment,
|
|
185
|
+
competence: `${input.competenceYear}-${String(input.competenceMonth).padStart(2, '0')}`,
|
|
186
|
+
documentCount: probe.documentCount ?? 0,
|
|
187
|
+
// Classe, nunca mensagem. E nenhum conteúdo fiscal.
|
|
188
|
+
failureCode: probe.accepted ? null : (probe.failureCode ?? 'unknown'),
|
|
189
|
+
cursor: probe.cursor ?? null,
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
return {
|
|
193
|
+
status: 'executed',
|
|
194
|
+
runId,
|
|
195
|
+
authorization: claimed,
|
|
196
|
+
remoteVerified: probe.accepted,
|
|
197
|
+
documentCount: probe.documentCount ?? 0,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/** O tipo de documento que um conector atende. */
|
|
201
|
+
function documentTypeOf(connector) {
|
|
202
|
+
return connector === 'nfse_adn' ? 'nfse' : 'nfe';
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=first-contact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"first-contact.js","sourceRoot":"","sources":["../../../../src/fiscal/collection/first-contact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildCollectionPlan = buildCollectionPlan;
|
|
4
|
+
const model_js_1 = require("../coverage/model.js");
|
|
5
|
+
const readiness_js_1 = require("../credentials/readiness.js");
|
|
6
|
+
const eligibility_js_1 = require("../eligibility.js");
|
|
7
|
+
const competence_js_1 = require("./competence.js");
|
|
8
|
+
const authorization_js_1 = require("./authorization.js");
|
|
9
|
+
/**
|
|
10
|
+
* O conector de cada tipo de documento.
|
|
11
|
+
*
|
|
12
|
+
* Municipal e estadual são conectores SEPARADOS — foi o que o discovery desta
|
|
13
|
+
* fase confirmou, e é o que impede o erro de tratar "dar baixa nas notas" como
|
|
14
|
+
* uma coisa só. A NFS-e do município vem pelo ADN nacional (que é quem recebe o
|
|
15
|
+
* compartilhamento das prefeituras); a NF-e de entrada vem pela distribuição da
|
|
16
|
+
* SEFAZ. Mesmo certificado, protocolos distintos, cursores distintos.
|
|
17
|
+
*/
|
|
18
|
+
const CONNECTOR_BY_TYPE = {
|
|
19
|
+
nfse: 'nfse_adn',
|
|
20
|
+
nfe: 'sefaz_dfe',
|
|
21
|
+
cte: 'sefaz_dfe',
|
|
22
|
+
nfce: 'sefaz_dfe',
|
|
23
|
+
};
|
|
24
|
+
async function buildCollectionPlan(tx, input) {
|
|
25
|
+
const now = input.now ?? new Date();
|
|
26
|
+
const suggested = (0, competence_js_1.suggestCompetenceFor)(now);
|
|
27
|
+
const competence = input.competenceYear !== undefined && input.competenceMonth !== undefined
|
|
28
|
+
? (0, competence_js_1.competenceOf)(input.competenceYear, input.competenceMonth)
|
|
29
|
+
: suggested;
|
|
30
|
+
const types = input.documentTypes ?? ['nfse', 'nfe'];
|
|
31
|
+
const authorizations = await (0, authorization_js_1.listRunAuthorizations)(tx, input.clientId);
|
|
32
|
+
const entries = [];
|
|
33
|
+
for (const documentType of types) {
|
|
34
|
+
const connector = CONNECTOR_BY_TYPE[documentType];
|
|
35
|
+
const coverage = await (0, model_js_1.coverageForClient)(tx, { clientId: input.clientId, documentType });
|
|
36
|
+
const credential = await (0, readiness_js_1.readFiscalCredentialReadiness)(tx, {
|
|
37
|
+
clientId: input.clientId,
|
|
38
|
+
environment: input.environment,
|
|
39
|
+
source: connector,
|
|
40
|
+
});
|
|
41
|
+
const eligibility = await (0, eligibility_js_1.evaluateFiscalEligibility)(tx, {
|
|
42
|
+
clientId: input.clientId,
|
|
43
|
+
documentType,
|
|
44
|
+
environment: input.environment,
|
|
45
|
+
});
|
|
46
|
+
const blockers = [];
|
|
47
|
+
if (!coverage.jurisdictionKnown)
|
|
48
|
+
blockers.push('jurisdiction_unknown');
|
|
49
|
+
if (coverage.coverageStatus === 'UNKNOWN')
|
|
50
|
+
blockers.push('coverage_unknown');
|
|
51
|
+
if (coverage.coverageStatus === 'UNSUPPORTED')
|
|
52
|
+
blockers.push('coverage_unsupported');
|
|
53
|
+
// A cobertura diz que o CAMINHO existe. Que ele já tenha respondido a este
|
|
54
|
+
// produto é outra afirmação, e ela mora em `verified_at` — vazio aqui
|
|
55
|
+
// significa que o conector nunca foi exercido, e o plano tem de dizer isso
|
|
56
|
+
// em vez de mostrar "conectado" por causa de um certificado salvo.
|
|
57
|
+
if (coverage.officialApiAvailable !== 'yes')
|
|
58
|
+
blockers.push('connector_not_verified');
|
|
59
|
+
// Cada camada com o seu nome. Fundir as três num "não está pronto" foi o que
|
|
60
|
+
// mandou o operador procurar no certificado um defeito de implementação.
|
|
61
|
+
if (!coverage.connectorImplemented)
|
|
62
|
+
blockers.push('connector_not_implemented');
|
|
63
|
+
else if (!coverage.protocolVerified)
|
|
64
|
+
blockers.push('protocol_not_verified');
|
|
65
|
+
// A credencial válida SÓ localmente não é mais um bloqueio absoluto: ela é
|
|
66
|
+
// exatamente o estado que o primeiro contato existe para atravessar. O que
|
|
67
|
+
// continua bloqueando é o cron — e este plano descreve a prova controlada,
|
|
68
|
+
// que é manual por definição.
|
|
69
|
+
if (!credential.usableByWorker && !credential.eligibleForFirstContact) {
|
|
70
|
+
blockers.push('credential_not_ready');
|
|
71
|
+
}
|
|
72
|
+
const motivos = new Set(eligibility.reasons);
|
|
73
|
+
if (motivos.has('client_not_enrolled'))
|
|
74
|
+
blockers.push('client_not_enrolled');
|
|
75
|
+
if (motivos.has('tenant_automation_disabled') || motivos.has('environment_mismatch')) {
|
|
76
|
+
blockers.push('tenant_automation_disabled');
|
|
77
|
+
}
|
|
78
|
+
// `credential_not_ready` da elegibilidade é esperado enquanto o aceite
|
|
79
|
+
// remoto não existir, e já está representado acima com a distinção certa.
|
|
80
|
+
const outros = [...motivos].filter((r) => r !== 'client_not_enrolled' &&
|
|
81
|
+
r !== 'tenant_automation_disabled' &&
|
|
82
|
+
r !== 'environment_mismatch' &&
|
|
83
|
+
r !== 'credential_not_ready' &&
|
|
84
|
+
r !== 'real_operation_not_declared');
|
|
85
|
+
if (outros.length > 0)
|
|
86
|
+
blockers.push('not_eligible');
|
|
87
|
+
const live = authorizations.find((a) => a.state === 'live' &&
|
|
88
|
+
a.source === connector &&
|
|
89
|
+
a.environment === input.environment &&
|
|
90
|
+
a.competence.year === competence.year &&
|
|
91
|
+
a.competence.month === competence.month);
|
|
92
|
+
entries.push({
|
|
93
|
+
documentType,
|
|
94
|
+
connector,
|
|
95
|
+
jurisdictionScope: coverage.jurisdictionScope,
|
|
96
|
+
jurisdictionCode: coverage.jurisdictionCode,
|
|
97
|
+
coverage,
|
|
98
|
+
credentialState: credential.state,
|
|
99
|
+
credentialKind: credential.kind,
|
|
100
|
+
/** O material abre aqui? Independente de algum ambiente já tê-lo aceito. */
|
|
101
|
+
credentialLocalValid: credential.localValid,
|
|
102
|
+
/** Esta prova, se autorizada, seria o primeiro contato com o ambiente. */
|
|
103
|
+
firstContact: credential.eligibleForFirstContact,
|
|
104
|
+
connectorImplemented: coverage.connectorImplemented,
|
|
105
|
+
protocolVerified: coverage.protocolVerified,
|
|
106
|
+
operation: 'READ_ONLY',
|
|
107
|
+
executionMode: 'manual',
|
|
108
|
+
blockers,
|
|
109
|
+
readyForControlledTest: blockers.length === 0,
|
|
110
|
+
authorization: live ?? null,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
clientId: input.clientId,
|
|
115
|
+
competence,
|
|
116
|
+
suggestedCompetence: suggested,
|
|
117
|
+
environment: input.environment,
|
|
118
|
+
entries,
|
|
119
|
+
readyForControlledTest: entries.length > 0 && entries.every((e) => e.readyForControlledTest),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../../src/fiscal/collection/plan.ts"],"names":[],"mappings":";;AAuGA,kDAkHC;AAxND,mDAA8E;AAC9E,8DAA4E;AAC5E,sDAA8D;AAE9D,mDAA4F;AAC5F,yDAAwF;AAiFxF;;;;;;;;GAQG;AACH,MAAM,iBAAiB,GAAuC;IAC5D,IAAI,EAAE,UAAU;IAChB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,WAAW;CAClB,CAAC;AAEK,KAAK,UAAU,mBAAmB,CACvC,EAAM,EACN,KAOC;IAED,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;IACpC,MAAM,SAAS,GAAG,IAAA,oCAAoB,EAAC,GAAG,CAAC,CAAC;IAC5C,MAAM,UAAU,GACd,KAAK,CAAC,cAAc,KAAK,SAAS,IAAI,KAAK,CAAC,eAAe,KAAK,SAAS;QACvE,CAAC,CAAC,IAAA,4BAAY,EAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,eAAe,CAAC;QAC3D,CAAC,CAAC,SAAS,CAAC;IAEhB,MAAM,KAAK,GAAG,KAAK,CAAC,aAAa,IAAK,CAAC,MAAM,EAAE,KAAK,CAAW,CAAC;IAChE,MAAM,cAAc,GAAG,MAAM,IAAA,wCAAqB,EAAC,EAAE,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAEvE,MAAM,OAAO,GAA0B,EAAE,CAAC;IAC1C,KAAK,MAAM,YAAY,IAAI,KAAK,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAG,MAAM,IAAA,4BAAiB,EAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,YAAY,EAAE,CAAC,CAAC;QACzF,MAAM,UAAU,GAAG,MAAM,IAAA,4CAA6B,EAAC,EAAE,EAAE;YACzD,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,MAAM,EAAE,SAAS;SAClB,CAAC,CAAC;QACH,MAAM,WAAW,GAAG,MAAM,IAAA,0CAAyB,EAAC,EAAE,EAAE;YACtD,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,YAAY;YACZ,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAwB,EAAE,CAAC;QACzC,IAAI,CAAC,QAAQ,CAAC,iBAAiB;YAAE,QAAQ,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACvE,IAAI,QAAQ,CAAC,cAAc,KAAK,SAAS;YAAE,QAAQ,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC7E,IAAI,QAAQ,CAAC,cAAc,KAAK,aAAa;YAAE,QAAQ,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACrF,2EAA2E;QAC3E,sEAAsE;QACtE,2EAA2E;QAC3E,mEAAmE;QACnE,IAAI,QAAQ,CAAC,oBAAoB,KAAK,KAAK;YAAE,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QACrF,6EAA6E;QAC7E,yEAAyE;QACzE,IAAI,CAAC,QAAQ,CAAC,oBAAoB;YAAE,QAAQ,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;aAC1E,IAAI,CAAC,QAAQ,CAAC,gBAAgB;YAAE,QAAQ,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QAE5E,2EAA2E;QAC3E,2EAA2E;QAC3E,2EAA2E;QAC3E,8BAA8B;QAC9B,IAAI,CAAC,UAAU,CAAC,cAAc,IAAI,CAAC,UAAU,CAAC,uBAAuB,EAAE,CAAC;YACtE,QAAQ,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACxC,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAC7C,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAC7E,IAAI,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,EAAE,CAAC;YACrF,QAAQ,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC9C,CAAC;QACD,uEAAuE;QACvE,0EAA0E;QAC1E,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,CAChC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,KAAK,qBAAqB;YAC3B,CAAC,KAAK,4BAA4B;YAClC,CAAC,KAAK,sBAAsB;YAC5B,CAAC,KAAK,sBAAsB;YAC5B,CAAC,KAAK,6BAA6B,CACtC,CAAC;QACF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAErD,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAC9B,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,KAAK,KAAK,MAAM;YAClB,CAAC,CAAC,MAAM,KAAK,SAAS;YACtB,CAAC,CAAC,WAAW,KAAK,KAAK,CAAC,WAAW;YACnC,CAAC,CAAC,UAAU,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI;YACrC,CAAC,CAAC,UAAU,CAAC,KAAK,KAAK,UAAU,CAAC,KAAK,CAC1C,CAAC;QAEF,OAAO,CAAC,IAAI,CAAC;YACX,YAAY;YACZ,SAAS;YACT,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB;YAC7C,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;YAC3C,QAAQ;YACR,eAAe,EAAE,UAAU,CAAC,KAAK;YACjC,cAAc,EAAE,UAAU,CAAC,IAAI;YAC/B,4EAA4E;YAC5E,oBAAoB,EAAE,UAAU,CAAC,UAAU;YAC3C,0EAA0E;YAC1E,YAAY,EAAE,UAAU,CAAC,uBAAuB;YAChD,oBAAoB,EAAE,QAAQ,CAAC,oBAAoB;YACnD,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;YAC3C,SAAS,EAAE,WAAW;YACtB,aAAa,EAAE,QAAQ;YACvB,QAAQ;YACR,sBAAsB,EAAE,QAAQ,CAAC,MAAM,KAAK,CAAC;YAC7C,aAAa,EAAE,IAAI,IAAI,IAAI;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,UAAU;QACV,mBAAmB,EAAE,SAAS;QAC9B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,OAAO;QACP,sBAAsB,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC;KAC7F,CAAC;AACJ,CAAC"}
|