@baruk/core 0.4.2 → 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/CHANGELOG.md +42 -0
- package/dist/audit/repository.d.ts +33 -1
- package/dist/audit/repository.d.ts.map +1 -1
- package/dist/audit/repository.js +41 -7
- package/dist/audit/repository.js.map +1 -1
- package/dist/auth/service.d.ts +21 -0
- package/dist/auth/service.d.ts.map +1 -1
- package/dist/auth/service.js +46 -1
- package/dist/auth/service.js.map +1 -1
- package/dist/billing/ar-repository.d.ts +41 -1
- package/dist/billing/ar-repository.d.ts.map +1 -1
- package/dist/billing/ar-repository.js +82 -6
- package/dist/billing/ar-repository.js.map +1 -1
- package/dist/billing/provider-account.d.ts +38 -0
- package/dist/billing/provider-account.d.ts.map +1 -1
- package/dist/billing/provider-account.js +58 -2
- package/dist/billing/provider-account.js.map +1 -1
- package/dist/billing/repository.d.ts +44 -0
- package/dist/billing/repository.d.ts.map +1 -1
- package/dist/billing/repository.js +49 -5
- package/dist/billing/repository.js.map +1 -1
- package/dist/cjs/audit/repository.js +41 -7
- package/dist/cjs/audit/repository.js.map +1 -1
- package/dist/cjs/auth/service.js +46 -1
- package/dist/cjs/auth/service.js.map +1 -1
- package/dist/cjs/billing/ar-repository.js +82 -6
- package/dist/cjs/billing/ar-repository.js.map +1 -1
- package/dist/cjs/billing/provider-account.js +60 -1
- package/dist/cjs/billing/provider-account.js.map +1 -1
- package/dist/cjs/billing/repository.js +51 -5
- package/dist/cjs/billing/repository.js.map +1 -1
- package/dist/cjs/clients/ibge.js +117 -0
- package/dist/cjs/clients/ibge.js.map +1 -0
- 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 +190 -9
- package/dist/cjs/clients/repository.js.map +1 -1
- package/dist/cjs/collection/branding.js +190 -0
- package/dist/cjs/collection/branding.js.map +1 -1
- package/dist/cjs/collection/clearance-store.js +74 -0
- package/dist/cjs/collection/clearance-store.js.map +1 -0
- package/dist/cjs/collection/communication-runtime.js +65 -2
- package/dist/cjs/collection/communication-runtime.js.map +1 -1
- package/dist/cjs/collection/engine.js +20 -0
- package/dist/cjs/collection/engine.js.map +1 -1
- package/dist/cjs/collection/policy.js +29 -1
- package/dist/cjs/collection/policy.js.map +1 -1
- package/dist/cjs/communication/clearance.js +18 -0
- package/dist/cjs/communication/clearance.js.map +1 -0
- package/dist/cjs/communication/dry-run-scenario.js +5 -0
- package/dist/cjs/communication/dry-run-scenario.js.map +1 -1
- package/dist/cjs/communication/engine.js +12 -0
- package/dist/cjs/communication/engine.js.map +1 -1
- package/dist/cjs/communication/policy.js.map +1 -1
- package/dist/cjs/competence/business-days.js +155 -0
- package/dist/cjs/competence/business-days.js.map +1 -0
- package/dist/cjs/competence/catalog-validation.js +174 -0
- package/dist/cjs/competence/catalog-validation.js.map +1 -0
- package/dist/cjs/competence/obligation-preview.js +190 -0
- package/dist/cjs/competence/obligation-preview.js.map +1 -0
- package/dist/cjs/competence/repository.js +330 -17
- package/dist/cjs/competence/repository.js.map +1 -1
- package/dist/cjs/dashboard/pilot-panel.js +90 -0
- package/dist/cjs/dashboard/pilot-panel.js.map +1 -0
- package/dist/cjs/dashboard/repository.js +11 -1
- package/dist/cjs/dashboard/repository.js.map +1 -1
- package/dist/cjs/db/client.js +17 -11
- package/dist/cjs/db/client.js.map +1 -1
- package/dist/cjs/db/provision-e2e-identity.js +116 -0
- package/dist/cjs/db/provision-e2e-identity.js.map +1 -0
- package/dist/cjs/fiscal/applicability.js +164 -0
- package/dist/cjs/fiscal/applicability.js.map +1 -0
- 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/conditions.js +198 -0
- package/dist/cjs/fiscal/conditions.js.map +1 -0
- package/dist/cjs/fiscal/contracts/nfse-adn-contract.js +390 -0
- package/dist/cjs/fiscal/contracts/nfse-adn-contract.js.map +1 -0
- package/dist/cjs/fiscal/contracts/nfse-adn-endpoint.js +108 -0
- package/dist/cjs/fiscal/contracts/nfse-adn-endpoint.js.map +1 -0
- package/dist/cjs/fiscal/contracts/nfse-adn-envelope.js +220 -0
- package/dist/cjs/fiscal/contracts/nfse-adn-envelope.js.map +1 -0
- package/dist/cjs/fiscal/coverage/model.js +137 -0
- package/dist/cjs/fiscal/coverage/model.js.map +1 -0
- package/dist/cjs/fiscal/coverage/requests.js +99 -0
- package/dist/cjs/fiscal/coverage/requests.js.map +1 -0
- 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 +168 -0
- package/dist/cjs/fiscal/credentials/material.js.map +1 -0
- 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 +190 -0
- package/dist/cjs/fiscal/credentials/readiness.js.map +1 -0
- package/dist/cjs/fiscal/eligibility.js +199 -0
- package/dist/cjs/fiscal/eligibility.js.map +1 -0
- package/dist/cjs/fiscal/enrollment.js +134 -0
- package/dist/cjs/fiscal/enrollment.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/__fixtures__/nfse.js +128 -0
- package/dist/cjs/fiscal/ingestion/__fixtures__/nfse.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/adn-transport.js +229 -0
- package/dist/cjs/fiscal/ingestion/adn-transport.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/direction.js +36 -0
- package/dist/cjs/fiscal/ingestion/direction.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/nfse-adn.js +228 -0
- package/dist/cjs/fiscal/ingestion/nfse-adn.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/pipeline.js +704 -0
- package/dist/cjs/fiscal/ingestion/pipeline.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/provider.js +51 -0
- package/dist/cjs/fiscal/ingestion/provider.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/repository.js +132 -0
- package/dist/cjs/fiscal/ingestion/repository.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/synthetic-provider.js +103 -0
- package/dist/cjs/fiscal/ingestion/synthetic-provider.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/synthetic-transport-types.js +13 -0
- package/dist/cjs/fiscal/ingestion/synthetic-transport-types.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/synthetic-transport.js +61 -0
- package/dist/cjs/fiscal/ingestion/synthetic-transport.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/xml-reader.js +121 -0
- package/dist/cjs/fiscal/ingestion/xml-reader.js.map +1 -0
- package/dist/cjs/fiscal/repository.js +470 -0
- package/dist/cjs/fiscal/repository.js.map +1 -0
- package/dist/cjs/fiscal/sync/circuit.js +124 -0
- package/dist/cjs/fiscal/sync/circuit.js.map +1 -0
- package/dist/cjs/fiscal/sync/intervention.js +140 -0
- package/dist/cjs/fiscal/sync/intervention.js.map +1 -0
- package/dist/cjs/fiscal/sync/lease.js +146 -0
- package/dist/cjs/fiscal/sync/lease.js.map +1 -0
- package/dist/cjs/fiscal/sync/observability.js +244 -0
- package/dist/cjs/fiscal/sync/observability.js.map +1 -0
- package/dist/cjs/fiscal/sync/orchestrator.js +490 -0
- package/dist/cjs/fiscal/sync/orchestrator.js.map +1 -0
- package/dist/cjs/fiscal/sync/policy.js +143 -0
- package/dist/cjs/fiscal/sync/policy.js.map +1 -0
- package/dist/cjs/fiscal/sync/reprocess.js +241 -0
- package/dist/cjs/fiscal/sync/reprocess.js.map +1 -0
- package/dist/cjs/fiscal/sync/retry.js +183 -0
- package/dist/cjs/fiscal/sync/retry.js.map +1 -0
- package/dist/cjs/fiscal/sync/secret-boundary.js +123 -0
- package/dist/cjs/fiscal/sync/secret-boundary.js.map +1 -0
- package/dist/cjs/fiscal/transport/https.js +309 -0
- package/dist/cjs/fiscal/transport/https.js.map +1 -0
- package/dist/cjs/fiscal/transport/synthetic-tls.js +380 -0
- package/dist/cjs/fiscal/transport/synthetic-tls.js.map +1 -0
- package/dist/cjs/fiscal/transport/types.js +93 -0
- package/dist/cjs/fiscal/transport/types.js.map +1 -0
- package/dist/cjs/import/br-documents.js +85 -0
- package/dist/cjs/import/br-documents.js.map +1 -0
- package/dist/cjs/import/clients-import.js +347 -40
- package/dist/cjs/import/clients-import.js.map +1 -1
- package/dist/cjs/index.js +461 -73
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/legal/documents.js +164 -19
- package/dist/cjs/legal/documents.js.map +1 -1
- package/dist/cjs/legal/index.js +3 -1
- package/dist/cjs/legal/index.js.map +1 -1
- package/dist/cjs/legal/types.js.map +1 -1
- package/dist/cjs/onboarding/persistence.js +4 -4
- package/dist/cjs/onboarding/persistence.js.map +1 -1
- package/dist/cjs/pilot/go-live-checklist.js +212 -0
- package/dist/cjs/pilot/go-live-checklist.js.map +1 -0
- package/dist/cjs/pilot/milestone.js +79 -0
- package/dist/cjs/pilot/milestone.js.map +1 -0
- package/dist/cjs/platform/capabilities.js +173 -0
- package/dist/cjs/platform/capabilities.js.map +1 -0
- package/dist/cjs/platform/job-contract.js +411 -0
- package/dist/cjs/platform/job-contract.js.map +1 -0
- package/dist/cjs/rbac/catalog.js +110 -0
- package/dist/cjs/rbac/catalog.js.map +1 -1
- package/dist/cjs/subscription-billing/index.js +9 -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 +246 -78
- package/dist/cjs/subscription-billing/service.js.map +1 -1
- package/dist/cjs/tenancy/features.js +131 -0
- package/dist/cjs/tenancy/features.js.map +1 -0
- package/dist/cjs/tenancy/settings.js +224 -0
- package/dist/cjs/tenancy/settings.js.map +1 -0
- package/dist/cjs/users/repository.js +24 -1
- package/dist/cjs/users/repository.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 +17 -0
- package/dist/clients/ibge.d.ts.map +1 -0
- package/dist/clients/ibge.js +112 -0
- package/dist/clients/ibge.js.map +1 -0
- 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 +158 -0
- package/dist/clients/repository.d.ts.map +1 -1
- package/dist/clients/repository.js +186 -9
- package/dist/clients/repository.js.map +1 -1
- package/dist/collection/branding.d.ts +65 -0
- package/dist/collection/branding.d.ts.map +1 -1
- package/dist/collection/branding.js +186 -0
- package/dist/collection/branding.js.map +1 -1
- package/dist/collection/clearance-store.d.ts +39 -0
- package/dist/collection/clearance-store.d.ts.map +1 -0
- package/dist/collection/clearance-store.js +69 -0
- package/dist/collection/clearance-store.js.map +1 -0
- package/dist/collection/communication-runtime.d.ts +37 -0
- package/dist/collection/communication-runtime.d.ts.map +1 -1
- package/dist/collection/communication-runtime.js +63 -1
- package/dist/collection/communication-runtime.js.map +1 -1
- package/dist/collection/engine.d.ts +23 -0
- package/dist/collection/engine.d.ts.map +1 -1
- package/dist/collection/engine.js +20 -0
- package/dist/collection/engine.js.map +1 -1
- package/dist/collection/policy.d.ts +25 -0
- package/dist/collection/policy.d.ts.map +1 -1
- package/dist/collection/policy.js +27 -0
- package/dist/collection/policy.js.map +1 -1
- package/dist/communication/clearance.d.ts +53 -0
- package/dist/communication/clearance.d.ts.map +1 -0
- package/dist/communication/clearance.js +15 -0
- package/dist/communication/clearance.js.map +1 -0
- package/dist/communication/dry-run-scenario.d.ts.map +1 -1
- package/dist/communication/dry-run-scenario.js +5 -0
- package/dist/communication/dry-run-scenario.js.map +1 -1
- package/dist/communication/engine.d.ts +10 -0
- package/dist/communication/engine.d.ts.map +1 -1
- package/dist/communication/engine.js +12 -0
- package/dist/communication/engine.js.map +1 -1
- package/dist/communication/policy.d.ts +16 -0
- package/dist/communication/policy.d.ts.map +1 -1
- package/dist/communication/policy.js.map +1 -1
- package/dist/competence/business-days.d.ts +51 -0
- package/dist/competence/business-days.d.ts.map +1 -0
- package/dist/competence/business-days.js +145 -0
- package/dist/competence/business-days.js.map +1 -0
- package/dist/competence/catalog-validation.d.ts +86 -0
- package/dist/competence/catalog-validation.d.ts.map +1 -0
- package/dist/competence/catalog-validation.js +168 -0
- package/dist/competence/catalog-validation.js.map +1 -0
- package/dist/competence/obligation-preview.d.ts +103 -0
- package/dist/competence/obligation-preview.d.ts.map +1 -0
- package/dist/competence/obligation-preview.js +184 -0
- package/dist/competence/obligation-preview.js.map +1 -0
- package/dist/competence/repository.d.ts +139 -1
- package/dist/competence/repository.d.ts.map +1 -1
- package/dist/competence/repository.js +325 -17
- package/dist/competence/repository.js.map +1 -1
- package/dist/dashboard/pilot-panel.d.ts +100 -0
- package/dist/dashboard/pilot-panel.d.ts.map +1 -0
- package/dist/dashboard/pilot-panel.js +87 -0
- package/dist/dashboard/pilot-panel.js.map +1 -0
- package/dist/dashboard/repository.d.ts.map +1 -1
- package/dist/dashboard/repository.js +11 -1
- package/dist/dashboard/repository.js.map +1 -1
- package/dist/db/client.d.ts +45 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +16 -11
- package/dist/db/client.js.map +1 -1
- package/dist/db/migrate.d.ts +36 -1
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +199 -32
- package/dist/db/migrate.js.map +1 -1
- package/dist/db/provision-e2e-identity.d.ts +2 -0
- package/dist/db/provision-e2e-identity.d.ts.map +1 -0
- package/dist/db/provision-e2e-identity.js +114 -0
- package/dist/db/provision-e2e-identity.js.map +1 -0
- package/dist/fiscal/applicability.d.ts +73 -0
- package/dist/fiscal/applicability.d.ts.map +1 -0
- package/dist/fiscal/applicability.js +160 -0
- package/dist/fiscal/applicability.js.map +1 -0
- 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/conditions.d.ts +99 -0
- package/dist/fiscal/conditions.d.ts.map +1 -0
- package/dist/fiscal/conditions.js +190 -0
- package/dist/fiscal/conditions.js.map +1 -0
- package/dist/fiscal/contracts/nfse-adn-contract.d.ts +315 -0
- package/dist/fiscal/contracts/nfse-adn-contract.d.ts.map +1 -0
- package/dist/fiscal/contracts/nfse-adn-contract.js +386 -0
- package/dist/fiscal/contracts/nfse-adn-contract.js.map +1 -0
- package/dist/fiscal/contracts/nfse-adn-endpoint.d.ts +13 -0
- package/dist/fiscal/contracts/nfse-adn-endpoint.d.ts.map +1 -0
- package/dist/fiscal/contracts/nfse-adn-endpoint.js +103 -0
- package/dist/fiscal/contracts/nfse-adn-endpoint.js.map +1 -0
- package/dist/fiscal/contracts/nfse-adn-envelope.d.ts +77 -0
- package/dist/fiscal/contracts/nfse-adn-envelope.d.ts.map +1 -0
- package/dist/fiscal/contracts/nfse-adn-envelope.js +215 -0
- package/dist/fiscal/contracts/nfse-adn-envelope.js.map +1 -0
- package/dist/fiscal/coverage/model.d.ts +114 -0
- package/dist/fiscal/coverage/model.d.ts.map +1 -0
- package/dist/fiscal/coverage/model.js +130 -0
- package/dist/fiscal/coverage/model.js.map +1 -0
- package/dist/fiscal/coverage/requests.d.ts +70 -0
- package/dist/fiscal/coverage/requests.d.ts.map +1 -0
- package/dist/fiscal/coverage/requests.js +95 -0
- package/dist/fiscal/coverage/requests.js.map +1 -0
- 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.d.ts +81 -0
- package/dist/fiscal/credentials/material.d.ts.map +1 -0
- package/dist/fiscal/credentials/material.js +164 -0
- package/dist/fiscal/credentials/material.js.map +1 -0
- 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 +119 -0
- package/dist/fiscal/credentials/readiness.d.ts.map +1 -0
- package/dist/fiscal/credentials/readiness.js +186 -0
- package/dist/fiscal/credentials/readiness.js.map +1 -0
- package/dist/fiscal/eligibility.d.ts +106 -0
- package/dist/fiscal/eligibility.d.ts.map +1 -0
- package/dist/fiscal/eligibility.js +194 -0
- package/dist/fiscal/eligibility.js.map +1 -0
- 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/ingestion/__fixtures__/nfse.d.ts +57 -0
- package/dist/fiscal/ingestion/__fixtures__/nfse.d.ts.map +1 -0
- package/dist/fiscal/ingestion/__fixtures__/nfse.js +121 -0
- package/dist/fiscal/ingestion/__fixtures__/nfse.js.map +1 -0
- package/dist/fiscal/ingestion/adn-transport.d.ts +123 -0
- package/dist/fiscal/ingestion/adn-transport.d.ts.map +1 -0
- package/dist/fiscal/ingestion/adn-transport.js +220 -0
- package/dist/fiscal/ingestion/adn-transport.js.map +1 -0
- package/dist/fiscal/ingestion/direction.d.ts +60 -0
- package/dist/fiscal/ingestion/direction.d.ts.map +1 -0
- package/dist/fiscal/ingestion/direction.js +32 -0
- package/dist/fiscal/ingestion/direction.js.map +1 -0
- package/dist/fiscal/ingestion/nfse-adn.d.ts +91 -0
- package/dist/fiscal/ingestion/nfse-adn.d.ts.map +1 -0
- package/dist/fiscal/ingestion/nfse-adn.js +222 -0
- package/dist/fiscal/ingestion/nfse-adn.js.map +1 -0
- package/dist/fiscal/ingestion/pipeline.d.ts +168 -0
- package/dist/fiscal/ingestion/pipeline.d.ts.map +1 -0
- package/dist/fiscal/ingestion/pipeline.js +699 -0
- package/dist/fiscal/ingestion/pipeline.js.map +1 -0
- package/dist/fiscal/ingestion/provider.d.ts +206 -0
- package/dist/fiscal/ingestion/provider.d.ts.map +1 -0
- package/dist/fiscal/ingestion/provider.js +47 -0
- package/dist/fiscal/ingestion/provider.js.map +1 -0
- package/dist/fiscal/ingestion/repository.d.ts +82 -0
- package/dist/fiscal/ingestion/repository.d.ts.map +1 -0
- package/dist/fiscal/ingestion/repository.js +127 -0
- package/dist/fiscal/ingestion/repository.js.map +1 -0
- package/dist/fiscal/ingestion/synthetic-provider.d.ts +92 -0
- package/dist/fiscal/ingestion/synthetic-provider.d.ts.map +1 -0
- package/dist/fiscal/ingestion/synthetic-provider.js +99 -0
- package/dist/fiscal/ingestion/synthetic-provider.js.map +1 -0
- package/dist/fiscal/ingestion/synthetic-transport-types.d.ts +19 -0
- package/dist/fiscal/ingestion/synthetic-transport-types.d.ts.map +1 -0
- package/dist/fiscal/ingestion/synthetic-transport-types.js +9 -0
- package/dist/fiscal/ingestion/synthetic-transport-types.js.map +1 -0
- package/dist/fiscal/ingestion/synthetic-transport.d.ts +55 -0
- package/dist/fiscal/ingestion/synthetic-transport.d.ts.map +1 -0
- package/dist/fiscal/ingestion/synthetic-transport.js +57 -0
- package/dist/fiscal/ingestion/synthetic-transport.js.map +1 -0
- package/dist/fiscal/ingestion/xml-reader.d.ts +55 -0
- package/dist/fiscal/ingestion/xml-reader.d.ts.map +1 -0
- package/dist/fiscal/ingestion/xml-reader.js +112 -0
- package/dist/fiscal/ingestion/xml-reader.js.map +1 -0
- package/dist/fiscal/repository.d.ts +220 -0
- package/dist/fiscal/repository.d.ts.map +1 -0
- package/dist/fiscal/repository.js +449 -0
- package/dist/fiscal/repository.js.map +1 -0
- package/dist/fiscal/sync/circuit.d.ts +86 -0
- package/dist/fiscal/sync/circuit.d.ts.map +1 -0
- package/dist/fiscal/sync/circuit.js +118 -0
- package/dist/fiscal/sync/circuit.js.map +1 -0
- package/dist/fiscal/sync/intervention.d.ts +81 -0
- package/dist/fiscal/sync/intervention.d.ts.map +1 -0
- package/dist/fiscal/sync/intervention.js +135 -0
- package/dist/fiscal/sync/intervention.js.map +1 -0
- package/dist/fiscal/sync/lease.d.ts +118 -0
- package/dist/fiscal/sync/lease.d.ts.map +1 -0
- package/dist/fiscal/sync/lease.js +139 -0
- package/dist/fiscal/sync/lease.js.map +1 -0
- package/dist/fiscal/sync/observability.d.ts +148 -0
- package/dist/fiscal/sync/observability.d.ts.map +1 -0
- package/dist/fiscal/sync/observability.js +239 -0
- package/dist/fiscal/sync/observability.js.map +1 -0
- package/dist/fiscal/sync/orchestrator.d.ts +132 -0
- package/dist/fiscal/sync/orchestrator.d.ts.map +1 -0
- package/dist/fiscal/sync/orchestrator.js +487 -0
- package/dist/fiscal/sync/orchestrator.js.map +1 -0
- package/dist/fiscal/sync/policy.d.ts +87 -0
- package/dist/fiscal/sync/policy.d.ts.map +1 -0
- package/dist/fiscal/sync/policy.js +136 -0
- package/dist/fiscal/sync/policy.js.map +1 -0
- package/dist/fiscal/sync/reprocess.d.ts +76 -0
- package/dist/fiscal/sync/reprocess.d.ts.map +1 -0
- package/dist/fiscal/sync/reprocess.js +237 -0
- package/dist/fiscal/sync/reprocess.js.map +1 -0
- package/dist/fiscal/sync/retry.d.ts +82 -0
- package/dist/fiscal/sync/retry.d.ts.map +1 -0
- package/dist/fiscal/sync/retry.js +176 -0
- package/dist/fiscal/sync/retry.js.map +1 -0
- package/dist/fiscal/sync/secret-boundary.d.ts +169 -0
- package/dist/fiscal/sync/secret-boundary.d.ts.map +1 -0
- package/dist/fiscal/sync/secret-boundary.js +116 -0
- package/dist/fiscal/sync/secret-boundary.js.map +1 -0
- package/dist/fiscal/transport/https.d.ts +86 -0
- package/dist/fiscal/transport/https.d.ts.map +1 -0
- package/dist/fiscal/transport/https.js +303 -0
- package/dist/fiscal/transport/https.js.map +1 -0
- package/dist/fiscal/transport/synthetic-tls.d.ts +99 -0
- package/dist/fiscal/transport/synthetic-tls.d.ts.map +1 -0
- package/dist/fiscal/transport/synthetic-tls.js +374 -0
- package/dist/fiscal/transport/synthetic-tls.js.map +1 -0
- package/dist/fiscal/transport/types.d.ts +134 -0
- package/dist/fiscal/transport/types.d.ts.map +1 -0
- package/dist/fiscal/transport/types.js +88 -0
- package/dist/fiscal/transport/types.js.map +1 -0
- package/dist/import/br-documents.d.ts +26 -0
- package/dist/import/br-documents.d.ts.map +1 -0
- package/dist/import/br-documents.js +78 -0
- package/dist/import/br-documents.js.map +1 -0
- package/dist/import/clients-import.d.ts +122 -4
- package/dist/import/clients-import.d.ts.map +1 -1
- package/dist/import/clients-import.js +341 -41
- package/dist/import/clients-import.js.map +1 -1
- package/dist/index.d.ts +145 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +120 -7
- package/dist/index.js.map +1 -1
- package/dist/legal/documents.d.ts +12 -1
- package/dist/legal/documents.d.ts.map +1 -1
- package/dist/legal/documents.js +162 -18
- package/dist/legal/documents.js.map +1 -1
- package/dist/legal/index.d.ts +2 -2
- package/dist/legal/index.d.ts.map +1 -1
- package/dist/legal/index.js +1 -1
- package/dist/legal/index.js.map +1 -1
- package/dist/legal/types.d.ts +114 -2
- package/dist/legal/types.d.ts.map +1 -1
- package/dist/legal/types.js.map +1 -1
- package/dist/onboarding/persistence.d.ts +10 -1
- package/dist/onboarding/persistence.d.ts.map +1 -1
- package/dist/onboarding/persistence.js +4 -4
- package/dist/onboarding/persistence.js.map +1 -1
- package/dist/pilot/go-live-checklist.d.ts +41 -0
- package/dist/pilot/go-live-checklist.d.ts.map +1 -0
- package/dist/pilot/go-live-checklist.js +209 -0
- package/dist/pilot/go-live-checklist.js.map +1 -0
- package/dist/pilot/milestone.d.ts +56 -0
- package/dist/pilot/milestone.d.ts.map +1 -0
- package/dist/pilot/milestone.js +74 -0
- package/dist/pilot/milestone.js.map +1 -0
- package/dist/platform/capabilities.d.ts +88 -0
- package/dist/platform/capabilities.d.ts.map +1 -0
- package/dist/platform/capabilities.js +169 -0
- package/dist/platform/capabilities.js.map +1 -0
- package/dist/platform/job-contract.d.ts +232 -0
- package/dist/platform/job-contract.d.ts.map +1 -0
- package/dist/platform/job-contract.js +403 -0
- package/dist/platform/job-contract.js.map +1 -0
- package/dist/rbac/catalog.d.ts.map +1 -1
- package/dist/rbac/catalog.js +110 -0
- package/dist/rbac/catalog.js.map +1 -1
- package/dist/subscription-billing/index.d.ts +8 -5
- package/dist/subscription-billing/index.d.ts.map +1 -1
- package/dist/subscription-billing/index.js +4 -3
- 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 +74 -0
- package/dist/subscription-billing/service.d.ts.map +1 -1
- package/dist/subscription-billing/service.js +182 -16
- package/dist/subscription-billing/service.js.map +1 -1
- package/dist/tenancy/features.d.ts +69 -0
- package/dist/tenancy/features.d.ts.map +1 -0
- package/dist/tenancy/features.js +123 -0
- package/dist/tenancy/features.js.map +1 -0
- package/dist/tenancy/settings.d.ts +63 -0
- package/dist/tenancy/settings.d.ts.map +1 -0
- package/dist/tenancy/settings.js +218 -0
- package/dist/tenancy/settings.js.map +1 -0
- package/dist/users/repository.d.ts +16 -1
- package/dist/users/repository.d.ts.map +1 -1
- package/dist/users/repository.js +24 -1
- package/dist/users/repository.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 +10 -2
- package/src/db/migrations/0045_role_write_scope.sql +122 -0
- package/src/db/migrations/0046_pilot_activation_model.sql +184 -0
- package/src/db/migrations/0047_recipient_clearance.sql +89 -0
- package/src/db/migrations/0048_item_type_note.sql +16 -0
- package/src/db/migrations/0049_national_fiscal_engine.sql +279 -0
- package/src/db/migrations/0050_fiscal_vocabulary_readonly.sql +29 -0
- package/src/db/migrations/0051_seed_rules_from_catalog.sql +72 -0
- package/src/db/migrations/0052_fiscal_rule_delete_scope.sql +57 -0
- package/src/db/migrations/0053_rule_validity_lower_bound.sql +44 -0
- package/src/db/migrations/0054_tenant_profile_and_rule_source.sql +89 -0
- package/src/db/migrations/0055_job_capability_contract.sql +300 -0
- package/src/db/migrations/0056_fiscal_document_ingestion.sql +337 -0
- package/src/db/migrations/0057_fiscal_pending_event_inbox.sql +228 -0
- package/src/db/migrations/0058_fiscal_operational_engine.sql +516 -0
- package/src/db/migrations/0059_fiscal_contract_version.sql +59 -0
- 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,337 @@
|
|
|
1
|
+
-- 0056 — o documento fiscal como registro canônico, e o cursor que o busca.
|
|
2
|
+
--
|
|
3
|
+
-- ═══ O problema operacional, na frase de quem o tem ════════════════════════
|
|
4
|
+
--
|
|
5
|
+
-- A proprietária da SC precisa chegar mais cedo ou sair mais tarde para "fazer
|
|
6
|
+
-- baixa de nota fiscal de cliente". Essa expressão não descreve UMA rotina: ela
|
|
7
|
+
-- cobre buscar NFS-e emitidas no portal do município, buscar NF-e destinadas ao
|
|
8
|
+
-- cliente no ambiente nacional, salvar XML, conferir contra o que o cliente
|
|
9
|
+
-- mandou, e classificar por competência. Fluxos diferentes, sistemas
|
|
10
|
+
-- diferentes, e só o último é trabalho de contador.
|
|
11
|
+
--
|
|
12
|
+
-- Esta migration cria onde o resultado dessa busca cabe — e nada além disso.
|
|
13
|
+
-- Capturar documento NÃO é escriturar: apuração, obrigação e fechamento
|
|
14
|
+
-- continuam em outros domínios, e é deliberado que esta tabela não os toque.
|
|
15
|
+
--
|
|
16
|
+
-- ═══ Por que um modelo só para NF-e, NFS-e e CT-e ══════════════════════════
|
|
17
|
+
--
|
|
18
|
+
-- A pesquisa oficial desta onda mediu que os três compartilham a MESMA forma de
|
|
19
|
+
-- distribuição:
|
|
20
|
+
--
|
|
21
|
+
-- NF-e NT 2014.002 v1.02c (ago/2020) — WS `NFeDistribuicaoDFe`,
|
|
22
|
+
-- `distNSU`/`consNSU`/`consChNFe`, lote de até 50, `ultNSU`/`maxNSU`,
|
|
23
|
+
-- `docZip` gZip+base64.
|
|
24
|
+
-- CT-e NT 2015.002 — WS `CTeDistribuicaoDFe`, `distNSU`/`consNSU`,
|
|
25
|
+
-- `ultNSU`/`maxNSU`, `docZip`. Mesma semântica, outro documento.
|
|
26
|
+
-- NFS-e Manual dos Contribuintes do ADN v1.0 (12/02/2026) —
|
|
27
|
+
-- `GET /DFe/{NSU}` e `GET /NFSe/{ChaveAcesso}/Eventos`. REST em vez de
|
|
28
|
+
-- SOAP, e o MESMO conceito de NSU.
|
|
29
|
+
--
|
|
30
|
+
-- Um cursor NSU sobre um ator identificado por documento serve aos três. Modelar
|
|
31
|
+
-- só NFS-e agora criaria retrabalho garantido, e modelar cada um em tabela
|
|
32
|
+
-- própria triplicaria dedupe, cursor e trilha. Um registro canônico com
|
|
33
|
+
-- `document_type`, e o específico no payload normalizado.
|
|
34
|
+
|
|
35
|
+
-- ── 1 · O documento fiscal ─────────────────────────────────────────────────
|
|
36
|
+
--
|
|
37
|
+
-- RAW e NORMALIZED coexistem, e nenhum dos dois é derivável do outro em
|
|
38
|
+
-- produção: o XML original é o que tem valor probatório e o que a Receita
|
|
39
|
+
-- reconhece; o normalizado é o que a tela lê sem reparsear XML a cada render.
|
|
40
|
+
-- Normalizar NUNCA destrói o original — `raw_blob_id` aponta para `blob`, que
|
|
41
|
+
-- já carrega sha256, tamanho e chave de storage particionada por
|
|
42
|
+
-- {tenant}/{client}/{yyyy}/{mm}.
|
|
43
|
+
--
|
|
44
|
+
-- `normalized` é jsonb e não colunas por campo. Isso não é preguiça de
|
|
45
|
+
-- modelagem: a reforma tributária acrescenta IBS e CBS aos leiautes, e um
|
|
46
|
+
-- schema rígido demais hoje descartaria em silêncio campos que ainda não
|
|
47
|
+
-- existem. O que é consultado vira coluna; o resto sobrevive no jsonb e no XML.
|
|
48
|
+
CREATE TABLE IF NOT EXISTS fiscal_document (
|
|
49
|
+
id uuid PRIMARY KEY,
|
|
50
|
+
tenant_id uuid NOT NULL REFERENCES tenant(id),
|
|
51
|
+
client_id uuid NOT NULL,
|
|
52
|
+
|
|
53
|
+
document_type text NOT NULL CHECK (document_type IN ('nfse', 'nfe', 'cte', 'nfce')),
|
|
54
|
+
-- `received` é o caso que a NT 2014.002 privilegia: "Documentos emitidos pela
|
|
55
|
+
-- própria empresa NÃO estarão disponíveis para consulta" no DF-e da NF-e. Já
|
|
56
|
+
-- o ADN da NFS-e devolve documentos em que o contribuinte é emitente,
|
|
57
|
+
-- tomador OU intermediário. A coluna existe porque a resposta é diferente por
|
|
58
|
+
-- documento, e tratar tudo como "nota do cliente" perderia a distinção que
|
|
59
|
+
-- decide o que se faz com ela.
|
|
60
|
+
direction text NOT NULL CHECK (direction IN ('issued', 'received', 'intermediary')),
|
|
61
|
+
|
|
62
|
+
source text NOT NULL,
|
|
63
|
+
-- Sem fallback entre ambientes, nos dois sentidos (Gate B0 §4). Documento de
|
|
64
|
+
-- homologação nunca vira documento real por omissão de coluna.
|
|
65
|
+
source_environment text NOT NULL
|
|
66
|
+
CHECK (source_environment IN ('synthetic', 'homologation', 'production')),
|
|
67
|
+
-- Posição do cursor que entregou este documento. Texto e não bigint: o NSU da
|
|
68
|
+
-- NT 2014.002 tem até 15 dígitos e o do ADN não promete ser numérico.
|
|
69
|
+
source_nsu text,
|
|
70
|
+
|
|
71
|
+
access_key text,
|
|
72
|
+
document_number text,
|
|
73
|
+
series text,
|
|
74
|
+
issuer_document text,
|
|
75
|
+
issuer_name text,
|
|
76
|
+
recipient_document text,
|
|
77
|
+
recipient_name text,
|
|
78
|
+
issued_at timestamptz,
|
|
79
|
+
-- Competência CONTÁBIL, separada da emissão de propósito: nota emitida em
|
|
80
|
+
-- 02/10 pode pertencer à competência 2026-09, e assumir que as duas são a
|
|
81
|
+
-- mesma coisa é como o fechamento mensal sai errado.
|
|
82
|
+
competence_label text CHECK (competence_label IS NULL OR competence_label ~ '^\d{4}-\d{2}$'),
|
|
83
|
+
gross_amount numeric(14,2),
|
|
84
|
+
currency text NOT NULL DEFAULT 'BRL',
|
|
85
|
+
|
|
86
|
+
-- Cancelada não é apagada. A nota existiu, foi contabilizada por alguém, e
|
|
87
|
+
-- some do painel só se alguém decidir escondê-la — nunca por efeito colateral
|
|
88
|
+
-- de um evento.
|
|
89
|
+
status text NOT NULL DEFAULT 'active'
|
|
90
|
+
CHECK (status IN ('active', 'cancelled', 'replaced', 'denied')),
|
|
91
|
+
-- `summary` é o `resNFe`: o que o ambiente nacional entrega ao destinatário
|
|
92
|
+
-- ANTES da manifestação. `full` é o `procNFe`. A distinção é do leiaute, não
|
|
93
|
+
-- nossa, e o produto precisa dizer qual tem — um resumo apresentado como
|
|
94
|
+
-- documento completo é uma mentira sobre o que o escritório possui.
|
|
95
|
+
content_kind text NOT NULL DEFAULT 'summary' CHECK (content_kind IN ('summary', 'full')),
|
|
96
|
+
|
|
97
|
+
raw_blob_id uuid,
|
|
98
|
+
raw_sha256 text CHECK (raw_sha256 IS NULL OR raw_sha256 ~ '^[a-f0-9]{64}$'),
|
|
99
|
+
normalized jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
100
|
+
|
|
101
|
+
-- Identidade de deduplicação. Calculada pelo adapter conforme o tipo: chave de
|
|
102
|
+
-- acesso quando existe, senão o par (fonte, identificador do provedor), senão
|
|
103
|
+
-- o hash do conteúdo. Nunca o NSU sozinho — o mesmo documento pode reaparecer
|
|
104
|
+
-- sob outro NSU num replay, e é exatamente esse o caso que a dedupe existe
|
|
105
|
+
-- para absorver.
|
|
106
|
+
dedupe_key text NOT NULL,
|
|
107
|
+
|
|
108
|
+
ingested_at timestamptz NOT NULL DEFAULT now(),
|
|
109
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
110
|
+
|
|
111
|
+
CONSTRAINT fiscal_document_tenant_id_uq UNIQUE (tenant_id, id),
|
|
112
|
+
FOREIGN KEY (tenant_id, client_id) REFERENCES client (tenant_id, id),
|
|
113
|
+
FOREIGN KEY (tenant_id, raw_blob_id) REFERENCES blob (tenant_id, id),
|
|
114
|
+
-- Um documento marcado `full` sem original guardado é uma afirmação sem
|
|
115
|
+
-- lastro. `summary` pode não ter blob: o resumo cabe no normalizado.
|
|
116
|
+
CONSTRAINT fiscal_document_full_has_raw
|
|
117
|
+
CHECK (content_kind <> 'full' OR raw_blob_id IS NOT NULL)
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
-- A dedupe é por (tenant, cliente, chave). Cliente entra porque a MESMA nota
|
|
121
|
+
-- pode ser destinada a um cliente e emitida por outro dentro do mesmo
|
|
122
|
+
-- escritório — são dois fatos contábeis distintos sobre o mesmo XML.
|
|
123
|
+
CREATE UNIQUE INDEX IF NOT EXISTS fiscal_document_dedupe_uq
|
|
124
|
+
ON fiscal_document (tenant_id, client_id, dedupe_key);
|
|
125
|
+
|
|
126
|
+
CREATE INDEX IF NOT EXISTS fiscal_document_client_idx
|
|
127
|
+
ON fiscal_document (tenant_id, client_id, issued_at DESC);
|
|
128
|
+
CREATE INDEX IF NOT EXISTS fiscal_document_competence_idx
|
|
129
|
+
ON fiscal_document (tenant_id, competence_label, document_type);
|
|
130
|
+
|
|
131
|
+
ALTER TABLE fiscal_document ENABLE ROW LEVEL SECURITY;
|
|
132
|
+
ALTER TABLE fiscal_document FORCE ROW LEVEL SECURITY;
|
|
133
|
+
-- Duas fronteiras, não uma. O ramo aberto de `app.current_client` é o mesmo
|
|
134
|
+
-- padrão das demais tabelas client-scoped: staff vê o escritório inteiro, o
|
|
135
|
+
-- portal vê só o próprio cliente.
|
|
136
|
+
CREATE POLICY fiscal_document_tenant_isolation ON fiscal_document
|
|
137
|
+
USING (
|
|
138
|
+
tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid
|
|
139
|
+
AND (
|
|
140
|
+
NULLIF(current_setting('app.current_client', true), '') IS NULL
|
|
141
|
+
OR client_id = NULLIF(current_setting('app.current_client', true), '')::uuid
|
|
142
|
+
)
|
|
143
|
+
)
|
|
144
|
+
WITH CHECK (
|
|
145
|
+
tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid
|
|
146
|
+
AND (
|
|
147
|
+
NULLIF(current_setting('app.current_client', true), '') IS NULL
|
|
148
|
+
OR client_id = NULLIF(current_setting('app.current_client', true), '')::uuid
|
|
149
|
+
)
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
COMMENT ON COLUMN fiscal_document.competence_label IS
|
|
153
|
+
'Competência CONTÁBIL (YYYY-MM), separada de issued_at: emissão e competência divergem, e assumir que são a mesma coisa erra o fechamento.';
|
|
154
|
+
COMMENT ON COLUMN fiscal_document.content_kind IS
|
|
155
|
+
'summary = resNFe (o que o ambiente nacional entrega antes da manifestação); full = procNFe. Apresentar resumo como documento completo é mentir sobre o que o escritório possui.';
|
|
156
|
+
|
|
157
|
+
-- ── 2 · Eventos do documento ───────────────────────────────────────────────
|
|
158
|
+
--
|
|
159
|
+
-- Cancelamento, substituição e correção são EVENTOS, e o documento continua
|
|
160
|
+
-- existindo. A NT 2014.002 é explícita: o cancelamento é entregue mesmo sem
|
|
161
|
+
-- manifestação do destinatário, justamente porque ele muda o que a nota
|
|
162
|
+
-- significa sem apagá-la.
|
|
163
|
+
CREATE TABLE IF NOT EXISTS fiscal_document_event (
|
|
164
|
+
id uuid PRIMARY KEY,
|
|
165
|
+
tenant_id uuid NOT NULL REFERENCES tenant(id),
|
|
166
|
+
fiscal_document_id uuid NOT NULL,
|
|
167
|
+
event_type text NOT NULL
|
|
168
|
+
CHECK (event_type IN ('cancellation', 'replacement', 'correction',
|
|
169
|
+
'manifestation', 'other')),
|
|
170
|
+
event_code text,
|
|
171
|
+
occurred_at timestamptz,
|
|
172
|
+
source_nsu text,
|
|
173
|
+
raw_blob_id uuid,
|
|
174
|
+
payload jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
175
|
+
dedupe_key text NOT NULL,
|
|
176
|
+
ingested_at timestamptz NOT NULL DEFAULT now(),
|
|
177
|
+
CONSTRAINT fiscal_document_event_tenant_id_uq UNIQUE (tenant_id, id),
|
|
178
|
+
FOREIGN KEY (tenant_id, fiscal_document_id) REFERENCES fiscal_document (tenant_id, id),
|
|
179
|
+
FOREIGN KEY (tenant_id, raw_blob_id) REFERENCES blob (tenant_id, id)
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
CREATE UNIQUE INDEX IF NOT EXISTS fiscal_document_event_dedupe_uq
|
|
183
|
+
ON fiscal_document_event (tenant_id, fiscal_document_id, dedupe_key);
|
|
184
|
+
|
|
185
|
+
ALTER TABLE fiscal_document_event ENABLE ROW LEVEL SECURITY;
|
|
186
|
+
ALTER TABLE fiscal_document_event FORCE ROW LEVEL SECURITY;
|
|
187
|
+
CREATE POLICY fiscal_document_event_tenant_isolation ON fiscal_document_event
|
|
188
|
+
USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
|
|
189
|
+
WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
|
|
190
|
+
|
|
191
|
+
-- ── 3 · O cursor de sincronização ──────────────────────────────────────────
|
|
192
|
+
--
|
|
193
|
+
-- Por (tenant, cliente, fonte, ambiente), e não por job: o NSU do ambiente
|
|
194
|
+
-- nacional é POR CNPJ consultado. O `job_cursor` do Gate B0 é por tenant e não
|
|
195
|
+
-- tem essa granularidade — reaproveitá-lo colapsaria a posição de todos os
|
|
196
|
+
-- clientes numa só e o primeiro cliente sincronizado apagaria a posição dos
|
|
197
|
+
-- outros.
|
|
198
|
+
--
|
|
199
|
+
-- ═══ `next_attempt_after` é a defesa contra o cStat 656 ════════════════════
|
|
200
|
+
--
|
|
201
|
+
-- A NT 2014.002 §3.5 é explícita: "A empresa deverá aguardar um tempo mínimo de
|
|
202
|
+
-- UMA HORA para efetuar uma nova solicitação de distribuição caso receba a
|
|
203
|
+
-- indicação que não existem mais documentos" (`ultNSU` == `maxNSU`, cStat 137).
|
|
204
|
+
-- Consultar antes disso é "consumo indevido" e o ambiente nacional rejeita com
|
|
205
|
+
-- **cStat 656**, bloqueando o CNPJ.
|
|
206
|
+
--
|
|
207
|
+
-- E o CNPJ bloqueado é o DO CLIENTE, não o nosso. Um laço mal escrito aqui
|
|
208
|
+
-- produz dano num terceiro que não pediu nada — por isso a espera é uma coluna
|
|
209
|
+
-- do banco e não um `sleep` no processo. Processo morre; linha não.
|
|
210
|
+
CREATE TABLE IF NOT EXISTS fiscal_sync_cursor (
|
|
211
|
+
id uuid PRIMARY KEY,
|
|
212
|
+
tenant_id uuid NOT NULL REFERENCES tenant(id),
|
|
213
|
+
client_id uuid NOT NULL,
|
|
214
|
+
source text NOT NULL,
|
|
215
|
+
environment text NOT NULL
|
|
216
|
+
CHECK (environment IN ('synthetic', 'homologation', 'production')),
|
|
217
|
+
-- Última posição CONFIRMADAMENTE persistida. Nunca adiantada antes do commit
|
|
218
|
+
-- dos documentos daquele lote.
|
|
219
|
+
last_nsu text,
|
|
220
|
+
-- Maior NSU que o provedor declarou existir. `last_nsu = max_nsu` é a
|
|
221
|
+
-- condição que arma a espera de uma hora.
|
|
222
|
+
max_nsu text,
|
|
223
|
+
last_success_at timestamptz,
|
|
224
|
+
-- Antes deste instante, nenhuma requisição sai. É o que impede o 656.
|
|
225
|
+
next_attempt_after timestamptz,
|
|
226
|
+
consecutive_failures int NOT NULL DEFAULT 0 CHECK (consecutive_failures >= 0),
|
|
227
|
+
last_error_class text,
|
|
228
|
+
contract_version int NOT NULL DEFAULT 1,
|
|
229
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
230
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
231
|
+
CONSTRAINT fiscal_sync_cursor_tenant_id_uq UNIQUE (tenant_id, id),
|
|
232
|
+
FOREIGN KEY (tenant_id, client_id) REFERENCES client (tenant_id, id)
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
CREATE UNIQUE INDEX IF NOT EXISTS fiscal_sync_cursor_uq
|
|
236
|
+
ON fiscal_sync_cursor (tenant_id, client_id, source, environment);
|
|
237
|
+
|
|
238
|
+
ALTER TABLE fiscal_sync_cursor ENABLE ROW LEVEL SECURITY;
|
|
239
|
+
ALTER TABLE fiscal_sync_cursor FORCE ROW LEVEL SECURITY;
|
|
240
|
+
CREATE POLICY fiscal_sync_cursor_tenant_isolation ON fiscal_sync_cursor
|
|
241
|
+
USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
|
|
242
|
+
WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
|
|
243
|
+
|
|
244
|
+
COMMENT ON COLUMN fiscal_sync_cursor.next_attempt_after IS
|
|
245
|
+
'Defesa contra o cStat 656 da NT 2014.002: uma hora de espera depois de cStat 137. O CNPJ que o 656 bloqueia é o do CLIENTE — por isso a espera é linha de banco, não sleep de processo.';
|
|
246
|
+
|
|
247
|
+
-- ── 4 · A trilha do lote ───────────────────────────────────────────────────
|
|
248
|
+
--
|
|
249
|
+
-- `job_run` (Gate B0) responde "o worker pôde rodar?". Esta responde "o que a
|
|
250
|
+
-- busca trouxe?" — são perguntas diferentes e uma não substitui a outra.
|
|
251
|
+
--
|
|
252
|
+
-- Sem XML e sem PII: contadores, classe de erro e as duas pontas do cursor.
|
|
253
|
+
CREATE TABLE IF NOT EXISTS fiscal_sync_run (
|
|
254
|
+
id uuid PRIMARY KEY,
|
|
255
|
+
tenant_id uuid NOT NULL REFERENCES tenant(id),
|
|
256
|
+
client_id uuid NOT NULL,
|
|
257
|
+
source text NOT NULL,
|
|
258
|
+
environment text NOT NULL
|
|
259
|
+
CHECK (environment IN ('synthetic', 'homologation', 'production')),
|
|
260
|
+
outcome text NOT NULL
|
|
261
|
+
CHECK (outcome IN ('completed', 'no_documents', 'throttled',
|
|
262
|
+
'blocked_eligibility', 'blocked_credential',
|
|
263
|
+
'blocked_contract', 'provider_error', 'failed')),
|
|
264
|
+
documents_fetched int NOT NULL DEFAULT 0 CHECK (documents_fetched >= 0),
|
|
265
|
+
documents_new int NOT NULL DEFAULT 0 CHECK (documents_new >= 0),
|
|
266
|
+
documents_duplicate int NOT NULL DEFAULT 0 CHECK (documents_duplicate >= 0),
|
|
267
|
+
documents_failed int NOT NULL DEFAULT 0 CHECK (documents_failed >= 0),
|
|
268
|
+
cursor_before text,
|
|
269
|
+
cursor_after text,
|
|
270
|
+
error_class text,
|
|
271
|
+
detail text,
|
|
272
|
+
started_at timestamptz NOT NULL DEFAULT now(),
|
|
273
|
+
finished_at timestamptz,
|
|
274
|
+
duration_ms int,
|
|
275
|
+
CONSTRAINT fiscal_sync_run_tenant_id_uq UNIQUE (tenant_id, id),
|
|
276
|
+
FOREIGN KEY (tenant_id, client_id) REFERENCES client (tenant_id, id),
|
|
277
|
+
-- A mesma invariante do `job_run`, aplicada ao dado: um lote bloqueado não
|
|
278
|
+
-- trouxe documento e não moveu cursor. O banco recusa a linha incoerente em
|
|
279
|
+
-- vez de confiar na ordem das operações do TypeScript.
|
|
280
|
+
CONSTRAINT fiscal_sync_run_blocked_is_inert
|
|
281
|
+
CHECK (outcome NOT IN ('blocked_eligibility', 'blocked_credential', 'blocked_contract', 'throttled')
|
|
282
|
+
OR (documents_fetched = 0 AND documents_new = 0 AND cursor_after IS NOT DISTINCT FROM cursor_before))
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
CREATE INDEX IF NOT EXISTS fiscal_sync_run_idx
|
|
286
|
+
ON fiscal_sync_run (tenant_id, client_id, started_at DESC);
|
|
287
|
+
|
|
288
|
+
ALTER TABLE fiscal_sync_run ENABLE ROW LEVEL SECURITY;
|
|
289
|
+
ALTER TABLE fiscal_sync_run FORCE ROW LEVEL SECURITY;
|
|
290
|
+
CREATE POLICY fiscal_sync_run_tenant_isolation ON fiscal_sync_run
|
|
291
|
+
USING (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid)
|
|
292
|
+
WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid);
|
|
293
|
+
|
|
294
|
+
-- ── 5 · A capacidade que o worker fiscal vai exigir ────────────────────────
|
|
295
|
+
--
|
|
296
|
+
-- Declarada AQUI, na mesma migration que cria o schema que a sustenta — é a
|
|
297
|
+
-- regra expand → declare → deploy → contract do doc 142. Antes disso o worker
|
|
298
|
+
-- fica INCOMPATIBLE e não escreve; depois passa sozinho.
|
|
299
|
+
INSERT INTO platform_capability (key, label, contract_version, declared_by_migration) VALUES
|
|
300
|
+
('office.fiscal-ingestion.v1',
|
|
301
|
+
'Ingestão de documentos fiscais: registro canônico, eventos, cursor e trilha', 1, '0056')
|
|
302
|
+
ON CONFLICT (key) DO NOTHING;
|
|
303
|
+
|
|
304
|
+
-- ── 6 · O terceiro ambiente ────────────────────────────────────────────────
|
|
305
|
+
--
|
|
306
|
+
-- A 0055 modelou dois: `synthetic` e `production`. A pesquisa desta onda mostrou
|
|
307
|
+
-- que faltava um, e que ele é o mais importante do meio do caminho: a
|
|
308
|
+
-- **produção restrita** do ADN (`adn.producaorestrita.nfse.gov.br`) e a
|
|
309
|
+
-- homologação da SEFAZ não são nem laboratório nem produção. São ambientes
|
|
310
|
+
-- OFICIAIS, que respondem como o real, com documento que não vale nada.
|
|
311
|
+
--
|
|
312
|
+
-- Sem essa distinção, ligar homologação exigiria declarar o escritório em
|
|
313
|
+
-- `production` — e aí um adapter apontado para produção de verdade passaria a
|
|
314
|
+
-- elegibilidade que alguém abriu para ensaiar. É o fallback silencioso que o
|
|
315
|
+
-- Gate B0 proibiu, entrando pela porta do vocabulário.
|
|
316
|
+
ALTER TABLE tenant_fiscal_automation DROP CONSTRAINT IF EXISTS tenant_fiscal_automation_mode_check;
|
|
317
|
+
ALTER TABLE tenant_fiscal_automation ADD CONSTRAINT tenant_fiscal_automation_mode_check
|
|
318
|
+
CHECK (mode IN ('disabled', 'synthetic', 'homologation', 'production'));
|
|
319
|
+
|
|
320
|
+
COMMENT ON COLUMN tenant_fiscal_automation.mode IS
|
|
321
|
+
'disabled (ausência de linha também) | synthetic (fixture) | homologation (ambiente OFICIAL de teste, documento sem valor) | production. Sem fallback entre eles, em nenhuma direção.';
|
|
322
|
+
|
|
323
|
+
-- ── 6 · Retirada de `client_fiscal_credential` ─────────────────────────────
|
|
324
|
+
--
|
|
325
|
+
-- Criada ontem, na 0055, e é invenção: o domínio de certificado já existe em
|
|
326
|
+
-- `digital_certificate` (vertical contábil, migration 1002), COM consumidores
|
|
327
|
+
-- vivos — a rota de compliance e o painel do piloto. Duas tabelas para o mesmo
|
|
328
|
+
-- fato dariam duas respostas para "este cliente tem certificado?", e elas
|
|
329
|
+
-- divergiriam na primeira vez que alguém atualizasse só uma.
|
|
330
|
+
--
|
|
331
|
+
-- A remoção é segura e foi medida antes: em produção a tabela tem
|
|
332
|
+
-- `n_tup_ins = 0` — nenhuma inserção desde a criação, não apenas nenhuma linha
|
|
333
|
+
-- viva. Nada é perdido porque nada foi escrito.
|
|
334
|
+
--
|
|
335
|
+
-- A prontidão passa a sair de `digital_certificate`, que ganha o que lhe
|
|
336
|
+
-- faltava para responder à pergunta (ver a migration 1004 da vertical).
|
|
337
|
+
DROP TABLE IF EXISTS client_fiscal_credential;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
-- 0057 — a caixa de entrada da ingestão fiscal, e a direção que deixa de ser adivinhada.
|
|
2
|
+
--
|
|
3
|
+
-- ═══ O defeito que esta migration existe para fechar ═══════════════════════
|
|
4
|
+
--
|
|
5
|
+
-- A 0056 modelou `fiscal_document_event` como evento DE um documento: a coluna
|
|
6
|
+
-- `fiscal_document_id` é `NOT NULL` e tem chave estrangeira. Está certo — um
|
|
7
|
+
-- cancelamento é, por definição, o cancelamento de uma nota.
|
|
8
|
+
--
|
|
9
|
+
-- O que faltava é o que fazer com o evento que chega ANTES da nota. E ele
|
|
10
|
+
-- chega: o ambiente nacional ordena a distribuição por RECEPÇÃO, não por
|
|
11
|
+
-- emissão, e a NT 2014.002 não promete o contrário em lugar nenhum. Um evento
|
|
12
|
+
-- de NSU 100 sobre um documento que só será entregue no NSU 101 é o caso
|
|
13
|
+
-- normal, não a exceção.
|
|
14
|
+
--
|
|
15
|
+
-- O motor tratava esse evento como "duplicado", contava o item como absorvido e
|
|
16
|
+
-- **avançava o cursor**. O NSU 100 ficava commitado sem que nada de 100
|
|
17
|
+
-- existisse em lugar algum — e quando o documento 101 chegasse, o cancelamento
|
|
18
|
+
-- dele já teria sido perdido para sempre. Uma nota cancelada permaneceria
|
|
19
|
+
-- válida no fechamento, e a única forma de descobrir seria a fiscalização.
|
|
20
|
+
--
|
|
21
|
+
-- ═══ A invariante, escrita de uma vez ══════════════════════════════════════
|
|
22
|
+
--
|
|
23
|
+
-- NENHUM NSU É COMMITADO SEM QUE A INFORMAÇÃO CORRESPONDENTE ESTEJA
|
|
24
|
+
-- DURAVELMENTE PRESERVADA.
|
|
25
|
+
--
|
|
26
|
+
-- "Duravelmente preservada" tem quatro formas, e todas são linha de banco:
|
|
27
|
+
-- documento gravado, evento aplicado, evento GUARDADO À ESPERA do alvo, ou
|
|
28
|
+
-- item ilegível guardado como tal. Não encontrar o alvo não é nenhuma delas.
|
|
29
|
+
--
|
|
30
|
+
-- ═══ Por que uma caixa de entrada, e não `fiscal_document_event` nullable ══
|
|
31
|
+
--
|
|
32
|
+
-- Tornar `fiscal_document_id` nulável custaria mais do que parece:
|
|
33
|
+
--
|
|
34
|
+
-- · a deduplicação é `UNIQUE (tenant_id, fiscal_document_id, dedupe_key)`, e
|
|
35
|
+
-- em índice único NULL não colide com NULL — o mesmo evento pendente
|
|
36
|
+
-- entraria quantas vezes fosse reapresentado, que é exatamente a
|
|
37
|
+
-- propriedade que a dedupe existe para dar;
|
|
38
|
+
-- · a tabela não tem `client_id`, e sem ele não há como provar que o evento
|
|
39
|
+
-- do Cliente A não reconcilia com o documento do Cliente B — a RLS dela é
|
|
40
|
+
-- de tenant apenas, porque o documento-alvo já carregava a fronteira de
|
|
41
|
+
-- cliente;
|
|
42
|
+
-- · e a invariante "todo evento pertence a um documento", que hoje o banco
|
|
43
|
+
-- garante, viraria disciplina de código.
|
|
44
|
+
--
|
|
45
|
+
-- Então a espera vive em tabela própria. Ela NÃO é um domínio paralelo: nada
|
|
46
|
+
-- aqui é consultado como documento fiscal, nada aqui aparece na tela de
|
|
47
|
+
-- documentos, e a vida de uma linha daqui termina virando
|
|
48
|
+
-- `fiscal_document_event`. É uma caixa de entrada, e caixa de entrada é a
|
|
49
|
+
-- estrutura certa para "chegou, é válido, ainda não dá para arquivar".
|
|
50
|
+
--
|
|
51
|
+
-- ═══ Por que o RAW mora aqui dentro, em `bytea` ════════════════════════════
|
|
52
|
+
--
|
|
53
|
+
-- O documento fiscal guarda o XML no `blob` (storage externo, sha256, chave
|
|
54
|
+
-- particionada) e está certo: ele é grande, é permanente e tem valor
|
|
55
|
+
-- probatório. A caixa de entrada é o oposto — pequena, transitória e a única
|
|
56
|
+
-- coisa que separa o cursor de perder informação.
|
|
57
|
+
--
|
|
58
|
+
-- Se a preservação dependesse do storage, existiria uma janela real: gravar o
|
|
59
|
+
-- objeto, o processo morrer, e o cursor commitar depois com base num `PUT` que
|
|
60
|
+
-- não aconteceu. Guardando os bytes na MESMA transação que move o cursor, a
|
|
61
|
+
-- janela não existe — ou as duas coisas acontecem, ou nenhuma. É a diferença
|
|
62
|
+
-- entre uma invariante e uma intenção.
|
|
63
|
+
--
|
|
64
|
+
-- Quando o evento é reconciliado, o `fiscal_document_event` resultante segue o
|
|
65
|
+
-- caminho normal do `blob`; a linha desta caixa mantém os bytes originais como
|
|
66
|
+
-- histórico, e é isso que permite reprocessar um evento aplicado por engano sem
|
|
67
|
+
-- pedir nada ao provedor de novo.
|
|
68
|
+
|
|
69
|
+
-- ── 1 · A caixa de entrada ─────────────────────────────────────────────────
|
|
70
|
+
CREATE TABLE IF NOT EXISTS fiscal_ingestion_inbox (
|
|
71
|
+
id uuid PRIMARY KEY,
|
|
72
|
+
tenant_id uuid NOT NULL REFERENCES tenant(id),
|
|
73
|
+
-- Presente e NOT NULL de propósito: é a fronteira que impede o evento de um
|
|
74
|
+
-- cliente de reconciliar com o documento de outro dentro do mesmo escritório.
|
|
75
|
+
client_id uuid NOT NULL,
|
|
76
|
+
|
|
77
|
+
source text NOT NULL,
|
|
78
|
+
source_environment text NOT NULL
|
|
79
|
+
CHECK (source_environment IN ('synthetic', 'homologation', 'production')),
|
|
80
|
+
-- O NSU que entregou o item. NOT NULL aqui, ao contrário de
|
|
81
|
+
-- `fiscal_document.source_nsu`: uma linha desta tabela SÓ existe por causa de
|
|
82
|
+
-- um item de cursor, e sem o NSU não há como responder "o que havia em 100?".
|
|
83
|
+
source_nsu text NOT NULL,
|
|
84
|
+
|
|
85
|
+
-- Os três estados, e o que cada um significa:
|
|
86
|
+
--
|
|
87
|
+
-- pending_target evento válido cujo documento-alvo ainda não chegou.
|
|
88
|
+
-- applied já virou `fiscal_document_event`. Fica como histórico.
|
|
89
|
+
-- invalid o item não pôde ser interpretado. Os bytes ficam para
|
|
90
|
+
-- recuperação manual (`consNSU`) em vez de sumirem.
|
|
91
|
+
--
|
|
92
|
+
-- Não há estado `duplicate`: item repetido não cria linha nenhuma — o índice
|
|
93
|
+
-- único abaixo o absorve, e a repetição é um DESFECHO da ingestão, não um
|
|
94
|
+
-- estado do dado. Chamar de duplicata o evento sem alvo foi o defeito
|
|
95
|
+
-- original, e o vocabulário não vai voltar a permiti-lo.
|
|
96
|
+
state text NOT NULL DEFAULT 'pending_target'
|
|
97
|
+
CHECK (state IN ('pending_target', 'applied', 'invalid')),
|
|
98
|
+
|
|
99
|
+
document_type text CHECK (document_type IS NULL
|
|
100
|
+
OR document_type IN ('nfse', 'nfe', 'cte', 'nfce')),
|
|
101
|
+
event_type text CHECK (event_type IS NULL
|
|
102
|
+
OR event_type IN ('cancellation', 'replacement', 'correction',
|
|
103
|
+
'manifestation', 'other')),
|
|
104
|
+
event_code text,
|
|
105
|
+
-- `nSeqEvento` do leiaute. Entra na ordem de aplicação quando dois eventos
|
|
106
|
+
-- do mesmo tipo caem na mesma caixa.
|
|
107
|
+
event_sequence text,
|
|
108
|
+
occurred_at timestamptz,
|
|
109
|
+
-- Chave do documento que este evento altera. É por ela que a reconciliação
|
|
110
|
+
-- encontra o que estava esperando.
|
|
111
|
+
target_access_key text,
|
|
112
|
+
|
|
113
|
+
raw bytea NOT NULL CHECK (octet_length(raw) <= 8388608),
|
|
114
|
+
raw_sha256 text NOT NULL CHECK (raw_sha256 ~ '^[a-f0-9]{64}$'),
|
|
115
|
+
normalized jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
116
|
+
|
|
117
|
+
-- Classe do motivo, nunca a mensagem do provedor nem trecho de XML.
|
|
118
|
+
reject_reason text,
|
|
119
|
+
|
|
120
|
+
received_at timestamptz NOT NULL DEFAULT now(),
|
|
121
|
+
applied_at timestamptz,
|
|
122
|
+
applied_event_id uuid,
|
|
123
|
+
|
|
124
|
+
dedupe_key text NOT NULL,
|
|
125
|
+
|
|
126
|
+
CONSTRAINT fiscal_ingestion_inbox_tenant_id_uq UNIQUE (tenant_id, id),
|
|
127
|
+
FOREIGN KEY (tenant_id, client_id) REFERENCES client (tenant_id, id),
|
|
128
|
+
FOREIGN KEY (tenant_id, applied_event_id) REFERENCES fiscal_document_event (tenant_id, id),
|
|
129
|
+
|
|
130
|
+
-- Um evento sem chave-alvo não teria como ser reconciliado nunca: seria
|
|
131
|
+
-- guardado para sempre sem chance de sair. O banco recusa em vez de deixar a
|
|
132
|
+
-- caixa acumular linhas inertes.
|
|
133
|
+
CONSTRAINT fiscal_ingestion_inbox_event_is_addressable
|
|
134
|
+
CHECK (state = 'invalid' OR (target_access_key IS NOT NULL AND event_type IS NOT NULL)),
|
|
135
|
+
-- Aplicado sem o evento resultante seria uma afirmação sem lastro — a mesma
|
|
136
|
+
-- classe do `full` sem RAW da 0056.
|
|
137
|
+
CONSTRAINT fiscal_ingestion_inbox_applied_has_event
|
|
138
|
+
CHECK (state <> 'applied' OR (applied_at IS NOT NULL AND applied_event_id IS NOT NULL)),
|
|
139
|
+
-- E inválido sem motivo seria um item descartado em silêncio com aparência
|
|
140
|
+
-- de registro.
|
|
141
|
+
CONSTRAINT fiscal_ingestion_inbox_invalid_has_reason
|
|
142
|
+
CHECK (state <> 'invalid' OR reject_reason IS NOT NULL)
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
-- ═══ A deduplicação é do BANCO ═════════════════════════════════════════════
|
|
146
|
+
--
|
|
147
|
+
-- Por (tenant, cliente, chave de dedupe), sem NULL em coluna nenhuma do índice.
|
|
148
|
+
-- É o que faz o replay do mesmo lote, o retry depois de crash e o evento
|
|
149
|
+
-- reapresentado depois do documento existir convergirem para uma linha só.
|
|
150
|
+
CREATE UNIQUE INDEX IF NOT EXISTS fiscal_ingestion_inbox_dedupe_uq
|
|
151
|
+
ON fiscal_ingestion_inbox (tenant_id, client_id, dedupe_key);
|
|
152
|
+
|
|
153
|
+
-- A busca da reconciliação: "quem estava esperando por esta chave?". Parcial
|
|
154
|
+
-- porque só o que está pendente interessa a essa pergunta.
|
|
155
|
+
CREATE INDEX IF NOT EXISTS fiscal_ingestion_inbox_pending_idx
|
|
156
|
+
ON fiscal_ingestion_inbox (tenant_id, client_id, target_access_key)
|
|
157
|
+
WHERE state = 'pending_target';
|
|
158
|
+
|
|
159
|
+
CREATE INDEX IF NOT EXISTS fiscal_ingestion_inbox_age_idx
|
|
160
|
+
ON fiscal_ingestion_inbox (tenant_id, state, received_at);
|
|
161
|
+
|
|
162
|
+
ALTER TABLE fiscal_ingestion_inbox ENABLE ROW LEVEL SECURITY;
|
|
163
|
+
ALTER TABLE fiscal_ingestion_inbox FORCE ROW LEVEL SECURITY;
|
|
164
|
+
-- Duas fronteiras, como em `fiscal_document`: tenant sempre, cliente quando o
|
|
165
|
+
-- portal define `app.current_client`.
|
|
166
|
+
CREATE POLICY fiscal_ingestion_inbox_tenant_isolation ON fiscal_ingestion_inbox
|
|
167
|
+
USING (
|
|
168
|
+
tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid
|
|
169
|
+
AND (
|
|
170
|
+
NULLIF(current_setting('app.current_client', true), '') IS NULL
|
|
171
|
+
OR client_id = NULLIF(current_setting('app.current_client', true), '')::uuid
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
WITH CHECK (
|
|
175
|
+
tenant_id = NULLIF(current_setting('app.current_tenant', true), '')::uuid
|
|
176
|
+
AND (
|
|
177
|
+
NULLIF(current_setting('app.current_client', true), '') IS NULL
|
|
178
|
+
OR client_id = NULLIF(current_setting('app.current_client', true), '')::uuid
|
|
179
|
+
)
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
COMMENT ON TABLE fiscal_ingestion_inbox IS
|
|
183
|
+
'Itens de NSU que o modelo canônico ainda não pode representar: evento cujo documento-alvo não chegou, e item ilegível. Existe para que o cursor nunca avance sobre informação não preservada.';
|
|
184
|
+
COMMENT ON COLUMN fiscal_ingestion_inbox.raw IS
|
|
185
|
+
'Bytes originais do item, na MESMA transação que move o cursor. Externalizá-los abriria a janela entre o PUT no storage e o commit do cursor.';
|
|
186
|
+
COMMENT ON COLUMN fiscal_ingestion_inbox.state IS
|
|
187
|
+
'pending_target | applied | invalid. Não existe `duplicate`: item repetido não cria linha — chamar de duplicata o evento sem alvo foi o defeito que esta tabela corrige.';
|
|
188
|
+
|
|
189
|
+
-- ── 2 · Direção deixa de ser adivinhada ────────────────────────────────────
|
|
190
|
+
--
|
|
191
|
+
-- Até aqui o parser da NFS-e devolvia `direction: 'issued'` fixo, com um
|
|
192
|
+
-- comentário dizendo que a ingestão resolveria — e a ingestão não resolvia.
|
|
193
|
+
-- Toda nota capturada nascia "emitida pelo cliente", inclusive as em que ele é
|
|
194
|
+
-- o tomador. Num escritório contábil isso não é um rótulo errado: é a diferença
|
|
195
|
+
-- entre receita e despesa.
|
|
196
|
+
--
|
|
197
|
+
-- A direção passa a sair do CONFRONTO entre o documento do ator consultado e os
|
|
198
|
+
-- participantes declarados no leiaute (emitente, tomador, intermediário). E
|
|
199
|
+
-- quando o confronto não decide, o resultado é `unknown` — explícito, visível
|
|
200
|
+
-- na tela e filtrável — em vez de `issued` por omissão.
|
|
201
|
+
--
|
|
202
|
+
-- `unknown` não é um estado de erro: o ADN distribui ao contribuinte documentos
|
|
203
|
+
-- em que ele figura em qualquer dos três papéis, mas nada impede um leiaute
|
|
204
|
+
-- futuro, ou um documento parcial, de não trazer o participante que decidiria.
|
|
205
|
+
-- Um rótulo honesto de "não deu para dizer" é a única resposta que não mente.
|
|
206
|
+
ALTER TABLE fiscal_document DROP CONSTRAINT IF EXISTS fiscal_document_direction_check;
|
|
207
|
+
ALTER TABLE fiscal_document ADD CONSTRAINT fiscal_document_direction_check
|
|
208
|
+
CHECK (direction IN ('issued', 'received', 'intermediary', 'unknown'));
|
|
209
|
+
|
|
210
|
+
COMMENT ON COLUMN fiscal_document.direction IS
|
|
211
|
+
'issued | received | intermediary | unknown. Resultado do confronto entre o documento do ator consultado e os participantes do leiaute. `unknown` quando o confronto não decide — nunca `issued` por omissão.';
|
|
212
|
+
|
|
213
|
+
-- ── 3 · A capacidade da nova forma ─────────────────────────────────────────
|
|
214
|
+
--
|
|
215
|
+
-- Chave NOVA, não `contract_version` maior: o registro é lido inteiro e versões
|
|
216
|
+
-- divergentes na mesma tabela o tornam ilegível (`probePlatformCapabilities`).
|
|
217
|
+
-- A regra da 0055 é que o registro só CRESCE, e compatibilidade é continência
|
|
218
|
+
-- de conjunto — mudança incompatível ganha `.v2`.
|
|
219
|
+
--
|
|
220
|
+
-- E ela é incompatível de verdade: um worker que escrevesse pela forma nova num
|
|
221
|
+
-- schema sem esta tabela veria o INSERT falhar, o item ficar não preservado e o
|
|
222
|
+
-- cursor parar. Fail-closed por construção — mas o portão explícito diz o
|
|
223
|
+
-- motivo antes, em vez de deixar o job parar sem explicação.
|
|
224
|
+
INSERT INTO platform_capability (key, label, contract_version, declared_by_migration) VALUES
|
|
225
|
+
('office.fiscal-ingestion.v2',
|
|
226
|
+
'Ingestão fiscal com caixa de entrada de evento pendente, reconciliação e direção classificada',
|
|
227
|
+
1, '0057')
|
|
228
|
+
ON CONFLICT (key) DO NOTHING;
|