@fayz-ai/plugin-fiscal-br 0.2.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/LICENSE +21 -0
- package/README.md +99 -0
- package/dist/connectors/plugnotas.d.ts +34 -0
- package/dist/connectors/plugnotas.d.ts.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1136 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/financial-provider.d.ts +9 -0
- package/dist/lib/financial-provider.d.ts.map +1 -0
- package/dist/migrations/index.d.ts +7 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/connectors/plugnotas.ts","../src/migrations/index.ts","../src/lib/financial-provider.ts","../src/index.ts"],"names":[],"mappings":"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;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AA6jB/B,IAAM,0DAAA,GAA6D,CAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","file":"index.js","sourcesContent":["import type React from 'react'\nimport {\n connectionSettings,\n connectionStatus,\n createConnectionStore,\n settingsStatus,\n type ConnectionConfig,\n type ConnectorDefinition,\n type ConnectorField,\n type ConnectorSetting,\n} from '@fayz-ai/core'\nimport type { PlugNotasConnectorClient, PlugNotasEnvironment, PlugNotasSetupState } from '../types'\n\nexport const PLUGNOTAS_CONNECTOR_ID = 'plugnotas'\n\nconst PLUGNOTAS_MARK = \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%230F766E'/%3E%3Cpath d='M10 7h12v18l-2-1.5-2 1.5-2-1.5-2 1.5-2-1.5-2 1.5V7Z' fill='white'/%3E%3Cpath d='M13 12h6M13 16h6M13 20h4' stroke='%230F766E' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E\"\n\nexport const PLUGNOTAS_FIELDS = [\n {\n key: 'emitterCnpj',\n label: 'CNPJ do emitente',\n type: 'text',\n placeholder: '00.000.000/0000-00',\n },\n] as const satisfies readonly ConnectorField[]\n\nexport const PLUGNOTAS_SETTINGS = [{\n key: 'environment',\n label: 'Ambiente fiscal',\n description: 'Sandbox simula o emissor. Homologação envia para a SEFAZ sem valor fiscal.',\n type: 'select',\n options: [\n { value: 'sandbox', label: 'Sandbox simulado' },\n { value: 'homologation', label: 'Homologação SEFAZ' },\n ],\n requiredToOperate: true,\n defaultValue: 'sandbox',\n}] as const satisfies readonly ConnectorSetting[]\n\nconst INTERNAL_SETTINGS = [\n 'certificateReady',\n 'cscReady',\n 'providerEmitterId',\n 'certificateExpiresAt',\n 'certificateFingerprint',\n // Non-secret operational data written by the host's server-side setup flow.\n // Declaring these keys keeps the shared connection store authoritative while\n // credentials (API key, A1 bytes/password, CSC) remain outside public JSON.\n 'stateRegistration',\n 'corporateName',\n 'tradeName',\n 'email',\n 'taxRegime',\n 'address',\n 'series',\n 'paymentMethod',\n]\nconst DAY_MS = 24 * 60 * 60 * 1000\n\nfunction digits(value: string): string {\n return value.replace(/\\D/g, '')\n}\n\nexport function isValidCnpj(value: string): boolean {\n const normalized = digits(value)\n if (!/^\\d{14}$/.test(normalized) || /^(\\d)\\1{13}$/.test(normalized)) return false\n const digit = (base: string, weights: number[]) => {\n const sum = weights.reduce((total, weight, index) => total + Number(base[index]) * weight, 0)\n const remainder = sum % 11\n return remainder < 2 ? 0 : 11 - remainder\n }\n const first = digit(normalized.slice(0, 12), [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2])\n const second = digit(`${normalized.slice(0, 12)}${first}`, [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2])\n return normalized.endsWith(`${first}${second}`)\n}\n\nfunction environment(value: unknown): PlugNotasEnvironment {\n if (value === undefined || value === null || value === '' || value === 'sandbox') return 'sandbox'\n if (value === 'homologation') return value\n throw new Error('Produção não está disponível neste conector preview.')\n}\n\nfunction store() {\n return createConnectionStore(PLUGNOTAS_CONNECTOR_ID, {\n fields: [...PLUGNOTAS_FIELDS],\n settings: [...PLUGNOTAS_SETTINGS],\n settingsKeys: INTERNAL_SETTINGS,\n })\n}\n\nfunction deriveStatus(connection: ConnectionConfig | null) {\n if (!connection?.active) return { connected: false }\n const readiness = settingsStatus([...PLUGNOTAS_SETTINGS], connection)\n const certificateReady = connection.settings.certificateReady === true\n const cscReady = connection.settings.cscReady === true\n const expiry = typeof connection.settings.certificateExpiresAt === 'string'\n ? Date.parse(connection.settings.certificateExpiresAt)\n : Number.NaN\n const daysUntilExpiry = Number.isFinite(expiry) ? Math.ceil((expiry - Date.now()) / DAY_MS) : null\n const expired = daysUntilExpiry !== null && daysUntilExpiry <= 0\n const expiringSoon = daysUntilExpiry !== null && daysUntilExpiry > 0 && daysUntilExpiry <= 30\n const missingSettings = [...new Set([\n ...(readiness.missingSettings ?? []),\n ...(!certificateReady || expired ? ['certificate'] : []),\n ...(!cscReady ? ['csc'] : []),\n ])]\n\n return {\n connected: true,\n needsSetup: missingSettings.length > 0,\n ...(missingSettings.length ? { missingSettings } : {}),\n detail: expired\n ? 'Certificado A1 vencido'\n : !certificateReady\n ? 'Envie o certificado A1 do emitente.'\n : !cscReady\n ? 'Confirme o CSC e o ID Token do emitente.'\n : connection.settings.environment === 'homologation'\n ? 'Emitente pronto em homologação'\n : 'Emitente pronto no sandbox',\n ...(expiringSoon\n ? { issues: [`O certificado A1 vence em ${daysUntilExpiry} dia${daysUntilExpiry === 1 ? '' : 's'}.`] }\n : {}),\n plane: 'sync' as const,\n }\n}\n\nexport interface CreatePlugNotasConnectorOptions {\n client?: PlugNotasConnectorClient\n SetupPanel?: React.ComponentType\n}\n\nexport function createPlugNotasConnector(options: CreatePlugNotasConnectorOptions = {}): ConnectorDefinition {\n const connectionStore = store()\n return {\n id: PLUGNOTAS_CONNECTOR_ID,\n // PlugBank and PlugNotas are different products from the same vendor. The\n // directory key names the product, otherwise one silently replaces the\n // other in the generated connector map.\n catalogSlug: 'plugnotas',\n hostPluginId: 'financial',\n name: 'PlugNotas · NFC-e',\n description: 'Emita NFC-e pela TecnoSpeed sem expor certificado, senha ou API key no navegador.',\n icon: 'ReceiptText',\n logoUrl: PLUGNOTAS_MARK,\n authKind: 'api-key',\n category: 'erp',\n direction: 'outbound',\n planes: ['sync'],\n docsUrl: 'https://docs.plugnotas.com.br/',\n fields: [...PLUGNOTAS_FIELDS],\n settings: [...PLUGNOTAS_SETTINGS],\n permissions: [{\n kind: 'data',\n resource: 'fiscal-document',\n actions: ['read', 'write'],\n reason: 'Enviar a NFC-e e reconciliar situação, chave de acesso e artefatos no Financeiro.',\n sensitive: true,\n }],\n invokedAt: [{\n key: 'financial.nfce.issue',\n label: 'Quando um operador confirma a emissão da NFC-e de um pedido concluído',\n plane: 'sync',\n trigger: 'manual',\n touches: ['fiscal-document'],\n }],\n howItSyncs: [\n 'A emissão cria primeiro um comando durável e só depois chama o provedor.',\n 'Webhook e recuperação consultiva convergem o mesmo comando, sem reenviar no escuro.',\n ],\n ...connectionStatus(PLUGNOTAS_CONNECTOR_ID, deriveStatus, { store }),\n ...connectionSettings(connectionStore),\n async testConnection(values) {\n const emitterCnpj = digits(values.emitterCnpj ?? '')\n if (!isValidCnpj(emitterCnpj)) return { ok: false, message: 'Informe um CNPJ válido.' }\n let selected: PlugNotasEnvironment\n try {\n selected = environment(values.environment)\n } catch (error) {\n return { ok: false, message: error instanceof Error ? error.message : 'Ambiente inválido.' }\n }\n return options.client?.testEmitter\n ? options.client.testEmitter({ emitterCnpj, environment: selected })\n : { ok: true }\n },\n async saveConnection(values) {\n const emitterCnpj = digits(values.emitterCnpj ?? '')\n if (!isValidCnpj(emitterCnpj)) throw new Error('Informe um CNPJ válido.')\n await connectionStore.save({\n active: true,\n displayName: `Emitente ${emitterCnpj.slice(-6)}`,\n providerAccountKey: emitterCnpj,\n settings: {\n emitterCnpj,\n environment: environment(values.environment),\n certificateReady: false,\n cscReady: false,\n },\n })\n },\n ...(options.client?.disconnectEmitter\n ? { disconnect: () => options.client!.disconnectEmitter!() }\n : {}),\n disconnectNote: 'As notas existentes permanecem no Financeiro; somente novas emissões são interrompidas.',\n ExtraPanel: options.SetupPanel,\n }\n}\n\n/** Persist only server-confirmed readiness and non-secret certificate metadata. */\nexport async function markPlugNotasEmitterReady(input: PlugNotasSetupState): Promise<void> {\n const emitterCnpj = digits(input.emitterCnpj)\n if (!isValidCnpj(emitterCnpj)) throw new Error('Informe um CNPJ válido.')\n await store().save({\n active: true,\n providerAccountKey: emitterCnpj,\n settings: {\n emitterCnpj,\n environment: environment(input.environment),\n certificateReady: input.certificateReady,\n cscReady: input.cscReady,\n providerEmitterId: input.providerEmitterId,\n certificateExpiresAt: input.certificateExpiresAt,\n certificateFingerprint: input.certificateFingerprint,\n },\n })\n}\n","// AUTO-GENERATED from 000_baseline.sql, 001_preserve_terminal_results_and_recover_leases.sql — regenerate with scripts/embed-migrations.mjs\n// SQL files are the source of truth; this inline copy lets the manifest declare\n// migrations as data. Do not edit by hand — run the embed script instead.\n\nexport const MIGRATION_000_BASELINE = `-- Fiscal Brasil / PlugNotas baseline.\n--\n-- This addon does not create a second fiscal ledger. \\`plg_financial_nfe\\`\n-- remains the authoritative document owned by plugin-financial. The tables\n-- below describe delivery to an external issuer: durable commands, attempts,\n-- webhooks and emitter ownership.\n--\n-- The file is additive and idempotent because the current restaurant pool is\n-- live. Applying it is deliberately outside this draft PR.\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_nfce_jobs (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n -- Logical reference to plugin-financial's fiscal ledger. Cross-plugin\n -- physical foreign keys are intentionally forbidden: installation and\n -- removal of this addon must never rewrite another plugin's schema.\n nota_id uuid NOT NULL,\n order_id uuid NOT NULL REFERENCES public.orders(id) ON DELETE RESTRICT,\n connection_id uuid NOT NULL REFERENCES public.connections(id) ON DELETE RESTRICT,\n operation text NOT NULL CHECK (operation IN ('issue', 'cancel')),\n status text NOT NULL DEFAULT 'queued'\n CHECK (status IN ('queued', 'running', 'waiting', 'succeeded', 'failed', 'manual_review')),\n idempotency_key text NOT NULL,\n provider_document_id text,\n integration_id text,\n request_snapshot jsonb NOT NULL DEFAULT '{}'::jsonb,\n provider_response jsonb NOT NULL DEFAULT '{}'::jsonb,\n attempts integer NOT NULL DEFAULT 0 CHECK (attempts >= 0),\n next_attempt_at timestamptz,\n locked_until timestamptz,\n last_error text,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (tenant_id, idempotency_key)\n);\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_nfce_jobs_recovery_idx\n ON public.plg_fiscalbr_nfce_jobs (status, next_attempt_at, locked_until)\n WHERE status IN ('queued', 'waiting');\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_nfce_events (\n id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n nota_id uuid NOT NULL,\n job_id uuid REFERENCES public.plg_fiscalbr_nfce_jobs(id) ON DELETE SET NULL,\n event_type text NOT NULL,\n payload jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now()\n);\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_nfce_events_document_idx\n ON public.plg_fiscalbr_nfce_events (tenant_id, nota_id, created_at DESC);\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_webhook_receipts (\n id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n provider text NOT NULL DEFAULT 'plugnotas',\n provider_event_id text NOT NULL,\n tenant_id uuid REFERENCES public.tenants(id) ON DELETE SET NULL,\n nota_id uuid,\n payload_sha256 text NOT NULL,\n received_at timestamptz NOT NULL DEFAULT now(),\n processed_at timestamptz,\n processing_error text,\n UNIQUE (provider, provider_event_id)\n);\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_emitter_ownership (\n emitter_cnpj text PRIMARY KEY CHECK (emitter_cnpj ~ '^[0-9]{14}$'),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n connection_id uuid NOT NULL REFERENCES public.connections(id) ON DELETE CASCADE,\n environment text NOT NULL CHECK (environment IN ('sandbox', 'homologation')),\n provider_emitter_id text,\n certificate_expires_at timestamptz,\n certificate_fingerprint text,\n csc_ready boolean NOT NULL DEFAULT false,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (tenant_id, connection_id)\n);\n\nALTER TABLE public.plg_fiscalbr_nfce_jobs ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_nfce_events ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_webhook_receipts ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_emitter_ownership ENABLE ROW LEVEL SECURITY;\n\nDROP POLICY IF EXISTS plg_fiscalbr_nfce_jobs_read ON public.plg_fiscalbr_nfce_jobs;\nCREATE POLICY plg_fiscalbr_nfce_jobs_read ON public.plg_fiscalbr_nfce_jobs\n FOR SELECT TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.read', NULL))\n );\n\nDROP POLICY IF EXISTS plg_fiscalbr_nfce_events_read ON public.plg_fiscalbr_nfce_events;\nCREATE POLICY plg_fiscalbr_nfce_events_read ON public.plg_fiscalbr_nfce_events\n FOR SELECT TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.read', NULL))\n );\n\nDROP POLICY IF EXISTS plg_fiscalbr_emitter_ownership_read ON public.plg_fiscalbr_emitter_ownership;\nCREATE POLICY plg_fiscalbr_emitter_ownership_read ON public.plg_fiscalbr_emitter_ownership\n FOR SELECT TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.read', NULL))\n );\n\nREVOKE ALL ON public.plg_fiscalbr_nfce_jobs FROM anon, authenticated;\nREVOKE ALL ON public.plg_fiscalbr_nfce_events FROM anon, authenticated;\nREVOKE ALL ON public.plg_fiscalbr_webhook_receipts FROM anon, authenticated;\nREVOKE ALL ON public.plg_fiscalbr_emitter_ownership FROM anon, authenticated;\nGRANT SELECT ON public.plg_fiscalbr_nfce_jobs TO authenticated;\nGRANT SELECT ON public.plg_fiscalbr_nfce_events TO authenticated;\nGRANT SELECT ON public.plg_fiscalbr_emitter_ownership TO authenticated;\nGRANT ALL ON public.plg_fiscalbr_nfce_jobs TO service_role;\nGRANT ALL ON public.plg_fiscalbr_nfce_events TO service_role;\nGRANT ALL ON public.plg_fiscalbr_webhook_receipts TO service_role;\nGRANT ALL ON public.plg_fiscalbr_emitter_ownership TO service_role;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_register_emitter(\n p_tenant_id uuid,\n p_connection_id uuid,\n p_emitter_cnpj text,\n p_environment text,\n p_provider_emitter_id text DEFAULT NULL,\n p_certificate_expires_at timestamptz DEFAULT NULL,\n p_certificate_fingerprint text DEFAULT NULL,\n p_csc_ready boolean DEFAULT false\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_cnpj text := regexp_replace(coalesce(p_emitter_cnpj, ''), '[^0-9]', '', 'g');\nBEGIN\n IF v_cnpj !~ '^[0-9]{14}$' THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: invalid CNPJ' USING ERRCODE = '22023';\n END IF;\n IF p_environment NOT IN ('sandbox', 'homologation') THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: production is not enabled' USING ERRCODE = '22023';\n END IF;\n IF NOT EXISTS (\n SELECT 1 FROM public.connections c\n WHERE c.id = p_connection_id\n AND c.tenant_id = p_tenant_id\n AND c.connector_id = 'plugnotas'\n AND c.active\n ) THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: active connection not found' USING ERRCODE = 'P0002';\n END IF;\n\n INSERT INTO public.plg_fiscalbr_emitter_ownership\n (emitter_cnpj, tenant_id, connection_id, environment, provider_emitter_id,\n certificate_expires_at, certificate_fingerprint, csc_ready, updated_at)\n VALUES\n (v_cnpj, p_tenant_id, p_connection_id, p_environment, p_provider_emitter_id,\n p_certificate_expires_at, p_certificate_fingerprint, p_csc_ready, now())\n ON CONFLICT (emitter_cnpj) DO UPDATE SET\n tenant_id = EXCLUDED.tenant_id,\n connection_id = EXCLUDED.connection_id,\n environment = EXCLUDED.environment,\n provider_emitter_id = EXCLUDED.provider_emitter_id,\n certificate_expires_at = EXCLUDED.certificate_expires_at,\n certificate_fingerprint = EXCLUDED.certificate_fingerprint,\n csc_ready = EXCLUDED.csc_ready,\n updated_at = now()\n WHERE public.plg_fiscalbr_emitter_ownership.tenant_id = EXCLUDED.tenant_id;\n\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: CNPJ belongs to another tenant' USING ERRCODE = '23505';\n END IF;\n\n UPDATE public.connections\n SET provider_account_key = v_cnpj,\n settings = settings || jsonb_build_object(\n 'environment', p_environment,\n 'certificateReady', p_certificate_expires_at IS NOT NULL,\n 'certificateExpiresAt', p_certificate_expires_at,\n 'certificateFingerprint', p_certificate_fingerprint,\n 'providerEmitterId', p_provider_emitter_id,\n 'cscReady', p_csc_ready\n ),\n status = CASE WHEN p_certificate_expires_at IS NOT NULL AND p_csc_ready THEN 'connected' ELSE 'pending' END,\n updated_at = now()\n WHERE id = p_connection_id AND tenant_id = p_tenant_id;\n\n RETURN jsonb_build_object('emitterCnpj', v_cnpj, 'environment', p_environment);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_disconnect_emitter(\n p_tenant_id uuid,\n p_connection_id uuid\n) RETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n DELETE FROM public.plg_fiscalbr_emitter_ownership\n WHERE tenant_id = p_tenant_id AND connection_id = p_connection_id;\n UPDATE public.connections\n SET active = false, status = 'revoked', settings = '{}'::jsonb,\n provider_state = '{}'::jsonb, updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_connection_id AND connector_id = 'plugnotas';\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_create_nfce_draft_for_order(\n p_tenant_id uuid,\n p_order_id uuid\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_order public.orders%ROWTYPE;\n v_nota_id uuid;\nBEGIN\n -- Serialize draft creation per tenant/order without adding a column or\n -- index to the financial plugin's table. The order itself remains the\n -- stable idempotency boundary for one NFC-e draft.\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || ':' || p_order_id::text, 0));\n\n SELECT * INTO v_order FROM public.orders\n WHERE tenant_id = p_tenant_id AND id = p_order_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_create_nfce_draft_for_order: order not found' USING ERRCODE = 'P0002';\n END IF;\n IF v_order.status NOT IN ('completed', 'paid', 'invoiced') THEN\n RAISE EXCEPTION 'plugnotas_create_nfce_draft_for_order: order is not closed' USING ERRCODE = '23514';\n END IF;\n IF NOT EXISTS (SELECT 1 FROM public.items i WHERE i.tenant_id = p_tenant_id AND i.order_id = p_order_id) THEN\n RAISE EXCEPTION 'plugnotas_create_nfce_draft_for_order: order has no items' USING ERRCODE = '23514';\n END IF;\n\n SELECT n.id INTO v_nota_id FROM public.plg_financial_nfe n\n WHERE n.tenant_id = p_tenant_id AND n.order_id = p_order_id AND n.model = 'nfce'\n ORDER BY n.created_at DESC LIMIT 1;\n IF v_nota_id IS NOT NULL THEN RETURN v_nota_id; END IF;\n\n INSERT INTO public.plg_financial_nfe\n (tenant_id, unit_id, model, status, order_id, contact_id, total_amount,\n emissor, metadata)\n VALUES\n (p_tenant_id, v_order.unit_id, 'nfce', 'draft', p_order_id, v_order.party_id,\n coalesce(v_order.total, 0), 'plugnotas',\n jsonb_build_object('source', 'order', 'orderKind', v_order.kind, 'orderChannel', v_order.channel))\n RETURNING id INTO v_nota_id;\n RETURN v_nota_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_prepare_nfce(\n p_tenant_id uuid,\n p_nota_id uuid,\n p_connection_id uuid,\n p_idempotency_key text\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_nota public.plg_financial_nfe%ROWTYPE;\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_snapshot jsonb;\nBEGIN\n SELECT * INTO v_nota FROM public.plg_financial_nfe\n WHERE tenant_id = p_tenant_id AND id = p_nota_id FOR UPDATE;\n IF NOT FOUND OR v_nota.model <> 'nfce' OR v_nota.order_id IS NULL THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: order-backed NFC-e not found' USING ERRCODE = 'P0002';\n END IF;\n IF v_nota.status NOT IN ('draft', 'error', 'processing') THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: invalid document status %', v_nota.status USING ERRCODE = '23514';\n END IF;\n IF NOT EXISTS (\n SELECT 1 FROM public.plg_fiscalbr_emitter_ownership e\n WHERE e.tenant_id = p_tenant_id AND e.connection_id = p_connection_id\n AND e.csc_ready AND e.certificate_expires_at > now()\n ) THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: emitter is not ready' USING ERRCODE = '23514';\n END IF;\n\n SELECT jsonb_build_object(\n 'nota', to_jsonb(v_nota),\n 'order', to_jsonb(o),\n 'items', coalesce((\n SELECT jsonb_agg(to_jsonb(i) ORDER BY i.sort_order, i.id)\n FROM public.items i\n WHERE i.tenant_id = p_tenant_id AND i.order_id = v_nota.order_id\n ), '[]'::jsonb),\n -- Product tax metadata must be frozen in the same transaction as the order\n -- lines. Looking products up in the Edge Function would let a retry emit\n -- with NCM/CFOP changed after the operator confirmed the document.\n 'products', coalesce((\n SELECT jsonb_agg(to_jsonb(p) ORDER BY p.id)\n FROM public.products p\n WHERE p.tenant_id = p_tenant_id\n AND p.id IN (\n SELECT i.product_id FROM public.items i\n WHERE i.tenant_id = p_tenant_id\n AND i.order_id = v_nota.order_id\n AND i.product_id IS NOT NULL\n )\n ), '[]'::jsonb)\n ) INTO v_snapshot\n FROM public.orders o\n WHERE o.tenant_id = p_tenant_id AND o.id = v_nota.order_id;\n\n IF jsonb_array_length(v_snapshot->'items') = 0 THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: order has no items' USING ERRCODE = '23514';\n END IF;\n\n INSERT INTO public.plg_fiscalbr_nfce_jobs\n (tenant_id, nota_id, order_id, connection_id, operation, status,\n idempotency_key, request_snapshot, next_attempt_at, updated_at)\n VALUES\n (p_tenant_id, p_nota_id, v_nota.order_id, p_connection_id, 'issue', 'queued',\n p_idempotency_key, v_snapshot, now(), now())\n ON CONFLICT (tenant_id, idempotency_key) DO UPDATE\n SET updated_at = now()\n RETURNING * INTO v_job;\n\n UPDATE public.plg_financial_nfe\n SET status = 'processing', error_message = NULL,\n metadata = metadata || jsonb_build_object('plugnotas', jsonb_build_object(\n 'jobId', v_job.id, 'jobStatus', v_job.status, 'operation', 'issue'\n )), updated_at = now()\n WHERE id = p_nota_id AND tenant_id = p_tenant_id;\n\n INSERT INTO public.plg_fiscalbr_nfce_events (tenant_id, nota_id, job_id, event_type, payload)\n VALUES (p_tenant_id, p_nota_id, v_job.id, 'issue.queued', '{}'::jsonb);\n RETURN jsonb_build_object('jobId', v_job.id, 'snapshot', v_job.request_snapshot, 'replayed', v_job.attempts > 0);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_prepare_nfce_cancel(\n p_tenant_id uuid,\n p_nota_id uuid,\n p_connection_id uuid,\n p_reason text\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_nota public.plg_financial_nfe%ROWTYPE;\n v_job_id uuid;\n v_reason text := btrim(coalesce(p_reason, ''));\nBEGIN\n IF char_length(v_reason) NOT BETWEEN 15 AND 255 THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce_cancel: reason must contain 15 to 255 characters' USING ERRCODE = '22023';\n END IF;\n SELECT * INTO v_nota FROM public.plg_financial_nfe\n WHERE tenant_id = p_tenant_id AND id = p_nota_id FOR UPDATE;\n IF NOT FOUND OR v_nota.status <> 'issued' OR v_nota.access_key IS NULL THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce_cancel: authorized NFC-e not found' USING ERRCODE = '23514';\n END IF;\n\n INSERT INTO public.plg_fiscalbr_nfce_jobs\n (tenant_id, nota_id, order_id, connection_id, operation, status,\n idempotency_key, provider_document_id, integration_id,\n request_snapshot, next_attempt_at)\n VALUES\n (p_tenant_id, p_nota_id, v_nota.order_id, p_connection_id, 'cancel', 'queued',\n 'nfce-cancel:' || p_nota_id::text,\n v_nota.metadata #>> '{plugnotas,providerDocumentId}',\n v_nota.metadata #>> '{plugnotas,integrationId}',\n jsonb_build_object('reason', v_reason), now())\n ON CONFLICT (tenant_id, idempotency_key) DO UPDATE SET\n provider_document_id = coalesce(\n public.plg_fiscalbr_nfce_jobs.provider_document_id,\n EXCLUDED.provider_document_id\n ),\n integration_id = coalesce(\n public.plg_fiscalbr_nfce_jobs.integration_id,\n EXCLUDED.integration_id\n ),\n updated_at = now()\n RETURNING id INTO v_job_id;\n\n UPDATE public.plg_financial_nfe\n SET metadata = metadata || jsonb_build_object('plugnotas', jsonb_build_object(\n 'jobId', v_job_id, 'jobStatus', 'queued', 'operation', 'cancel', 'cancellationPending', true\n )), updated_at = now()\n WHERE id = p_nota_id AND tenant_id = p_tenant_id;\n RETURN jsonb_build_object('jobId', v_job_id, 'reason', v_reason);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_record_nfce_attempt(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_response jsonb DEFAULT '{}'::jsonb,\n p_error text DEFAULT NULL,\n p_next_attempt_at timestamptz DEFAULT NULL\n) RETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n IF p_status NOT IN ('running', 'waiting', 'failed', 'manual_review') THEN\n RAISE EXCEPTION 'plugnotas_record_nfce_attempt: invalid status' USING ERRCODE = '22023';\n END IF;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = p_status,\n -- One provider dispatch is one attempt. Moving that same attempt from\n -- running to waiting/failed must not count it a second time.\n attempts = attempts + CASE WHEN p_status = 'running' THEN 1 ELSE 0 END,\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = p_error, next_attempt_at = p_next_attempt_at,\n locked_until = NULL, updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_job_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_result(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_document_id text DEFAULT NULL,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_provider_response jsonb DEFAULT '{}'::jsonb\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_document_status text;\nBEGIN\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE tenant_id = p_tenant_id AND id = p_job_id FOR UPDATE;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: job not found' USING ERRCODE = 'P0002';\n END IF;\n IF p_status NOT IN ('processing', 'issued', 'cancelled', 'error') THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: invalid status' USING ERRCODE = '22023';\n END IF;\n\n v_document_status := CASE\n WHEN v_job.operation = 'cancel' AND p_status = 'processing' THEN 'issued'\n ELSE p_status\n END;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = CASE\n WHEN p_status IN ('issued', 'cancelled') THEN 'succeeded'\n WHEN p_status = 'error' THEN 'failed'\n ELSE 'waiting'\n END,\n provider_document_id = coalesce(p_provider_document_id, provider_document_id),\n integration_id = coalesce(p_integration_id, integration_id),\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = CASE WHEN p_status = 'error' THEN p_message ELSE NULL END,\n next_attempt_at = CASE WHEN p_status = 'processing' THEN now() + interval '2 minutes' ELSE NULL END,\n locked_until = NULL, updated_at = now()\n WHERE id = p_job_id;\n\n UPDATE public.plg_financial_nfe\n SET status = v_document_status,\n number = coalesce(p_number, number),\n series = coalesce(p_series, series),\n access_key = coalesce(p_access_key, access_key),\n issued_at = CASE WHEN p_status = 'issued' THEN coalesce(issued_at, now()) ELSE issued_at END,\n error_message = CASE WHEN p_status = 'error' THEN p_message ELSE NULL END,\n metadata = metadata || jsonb_build_object('plugnotas', jsonb_strip_nulls(jsonb_build_object(\n 'jobId', p_job_id,\n 'jobStatus', CASE WHEN p_status IN ('issued', 'cancelled') THEN 'succeeded' WHEN p_status = 'error' THEN 'failed' ELSE 'waiting' END,\n 'operation', v_job.operation,\n 'providerDocumentId', coalesce(p_provider_document_id, v_job.provider_document_id),\n 'integrationId', coalesce(p_integration_id, v_job.integration_id),\n 'cancellationPending', v_job.operation = 'cancel' AND p_status = 'processing'\n ))),\n updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = v_job.nota_id;\n\n INSERT INTO public.plg_fiscalbr_nfce_events (tenant_id, nota_id, job_id, event_type, payload)\n VALUES (p_tenant_id, v_job.nota_id, p_job_id, v_job.operation || '.' || p_status,\n coalesce(p_provider_response, '{}'::jsonb));\n RETURN v_job.nota_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_webhook(\n p_provider_event_id text,\n p_payload_sha256 text,\n p_provider_document_id text,\n p_status text,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_payload jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_receipt_id bigint;\nBEGIN\n INSERT INTO public.plg_fiscalbr_webhook_receipts\n (provider_event_id, payload_sha256)\n VALUES (p_provider_event_id, p_payload_sha256)\n ON CONFLICT (provider, provider_event_id) DO NOTHING\n RETURNING id INTO v_receipt_id;\n IF v_receipt_id IS NULL THEN RETURN jsonb_build_object('duplicate', true); END IF;\n\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE provider_document_id = p_provider_document_id\n ORDER BY created_at DESC LIMIT 1;\n IF NOT FOUND THEN\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET processed_at = now(), processing_error = 'job_not_found'\n WHERE id = v_receipt_id;\n RETURN jsonb_build_object('duplicate', false, 'matched', false);\n END IF;\n\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET tenant_id = v_job.tenant_id, nota_id = v_job.nota_id, processed_at = now()\n WHERE id = v_receipt_id;\n PERFORM public.plugnotas_apply_nfce_result(\n v_job.tenant_id, v_job.id, p_status, p_provider_document_id,\n coalesce(p_integration_id, v_job.integration_id), p_number, p_series,\n p_access_key, p_message, p_payload\n );\n RETURN jsonb_build_object('duplicate', false, 'matched', true, 'jobId', v_job.id);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_get_artifact_locator(\n p_tenant_id uuid,\n p_nota_id uuid\n) RETURNS jsonb\nLANGUAGE sql SECURITY DEFINER SET search_path = '' STABLE AS $$\n SELECT jsonb_build_object(\n 'notaId', n.id,\n 'status', n.status,\n 'providerDocumentId', n.metadata #>> '{plugnotas,providerDocumentId}',\n 'integrationId', n.metadata #>> '{plugnotas,integrationId}'\n )\n FROM public.plg_financial_nfe n\n WHERE n.tenant_id = p_tenant_id AND n.id = p_nota_id\n AND n.status IN ('issued', 'cancelled');\n$$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_claim_nfce_recovery(\n p_limit integer DEFAULT 20\n) RETURNS SETOF public.plg_fiscalbr_nfce_jobs\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n RETURN QUERY\n WITH candidates AS (\n SELECT j.id FROM public.plg_fiscalbr_nfce_jobs j\n WHERE j.status IN ('queued', 'waiting')\n AND coalesce(j.next_attempt_at, j.created_at) <= now()\n AND coalesce(j.locked_until, '-infinity'::timestamptz) < now()\n ORDER BY coalesce(j.next_attempt_at, j.created_at), j.created_at\n FOR UPDATE SKIP LOCKED\n LIMIT greatest(1, least(coalesce(p_limit, 20), 100))\n )\n UPDATE public.plg_fiscalbr_nfce_jobs j\n SET status = 'running', locked_until = now() + interval '2 minutes', updated_at = now()\n FROM candidates c WHERE j.id = c.id\n RETURNING j.*;\nEND $$;\n\nREVOKE ALL ON FUNCTION public.plugnotas_register_emitter(uuid, uuid, text, text, text, timestamptz, text, boolean) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_disconnect_emitter(uuid, uuid) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_create_nfce_draft_for_order(uuid, uuid) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_prepare_nfce(uuid, uuid, uuid, text) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_prepare_nfce_cancel(uuid, uuid, uuid, text) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_record_nfce_attempt(uuid, uuid, text, jsonb, text, timestamptz) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_apply_nfce_result(uuid, uuid, text, text, text, text, text, text, text, jsonb) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_apply_nfce_webhook(text, text, text, text, text, text, text, text, text, jsonb) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_get_artifact_locator(uuid, uuid) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_claim_nfce_recovery(integer) FROM PUBLIC, anon, authenticated;\n\nGRANT EXECUTE ON FUNCTION public.plugnotas_register_emitter(uuid, uuid, text, text, text, timestamptz, text, boolean) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_disconnect_emitter(uuid, uuid) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_create_nfce_draft_for_order(uuid, uuid) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_prepare_nfce(uuid, uuid, uuid, text) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_prepare_nfce_cancel(uuid, uuid, uuid, text) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_record_nfce_attempt(uuid, uuid, text, jsonb, text, timestamptz) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_apply_nfce_result(uuid, uuid, text, text, text, text, text, text, text, jsonb) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_apply_nfce_webhook(text, text, text, text, text, text, text, text, text, jsonb) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_get_artifact_locator(uuid, uuid) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_claim_nfce_recovery(integer) TO service_role;\n`\n\nexport const MIGRATION_001_PRESERVE_TERMINAL_RESULTS_AND_RECOVER_LEASES = `-- Incremental recovery fix. Preserve 000_baseline.sql and its recorded checksum.\n-- Only existing fiscal functions change; no parallel ledger/schema or backfill.\n-- CREATE OR REPLACE retains the service-role-only ACL from the baseline.\n\nCREATE OR REPLACE FUNCTION public.plugnotas_record_nfce_attempt(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_response jsonb DEFAULT '{}'::jsonb,\n p_error text DEFAULT NULL,\n p_next_attempt_at timestamptz DEFAULT NULL\n) RETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n IF p_status NOT IN ('running', 'waiting', 'failed', 'manual_review') THEN\n RAISE EXCEPTION 'plugnotas_record_nfce_attempt: invalid status' USING ERRCODE = '22023';\n END IF;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = p_status,\n -- One provider dispatch is one attempt. Moving that same attempt from\n -- running to waiting/failed must not count it a second time.\n attempts = attempts + CASE WHEN p_status = 'running' THEN 1 ELSE 0 END,\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = p_error, next_attempt_at = p_next_attempt_at,\n locked_until = CASE WHEN p_status = 'running'\n THEN greatest(coalesce(locked_until, now()), now() + interval '2 minutes') ELSE NULL END,\n updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_job_id AND status <> 'succeeded';\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_result(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_document_id text DEFAULT NULL,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_provider_response jsonb DEFAULT '{}'::jsonb\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_document_status text;\n v_existing_status text;\n v_job_status text;\nBEGIN\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE tenant_id = p_tenant_id AND id = p_job_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: job not found' USING ERRCODE = 'P0002';\n END IF;\n IF p_status NOT IN ('processing', 'issued', 'cancelled', 'error') THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: invalid status' USING ERRCODE = '22023';\n END IF;\n\n -- Match prepare/cancel's lock order: document, then job.\n SELECT status INTO v_existing_status FROM public.plg_financial_nfe\n WHERE tenant_id = p_tenant_id AND id = v_job.nota_id FOR UPDATE;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: document not found' USING ERRCODE = 'P0002';\n END IF;\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE tenant_id = p_tenant_id AND id = p_job_id FOR UPDATE;\n\n -- Late polling must not regress a concluded document or an active cancellation.\n IF v_existing_status = 'cancelled'\n OR (v_job.operation = 'issue' AND v_existing_status = 'issued' AND p_status <> 'cancelled')\n OR (v_job.status = 'succeeded' AND p_status IN ('processing', 'error')) THEN\n -- Old/interrupted jobs may still be running after the document concluded.\n -- Settle their lease too, otherwise recovery would claim them forever.\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = 'succeeded', locked_until = NULL, next_attempt_at = NULL, updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_job_id;\n RETURN v_job.nota_id;\n END IF;\n\n v_job_status := CASE\n WHEN p_status = 'cancelled' OR (v_job.operation = 'issue' AND p_status = 'issued') THEN 'succeeded'\n WHEN p_status = 'error' THEN 'failed'\n ELSE 'waiting' END;\n v_document_status := CASE\n WHEN v_job.operation = 'cancel' AND p_status <> 'cancelled' THEN v_existing_status\n ELSE p_status\n END;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = v_job_status,\n provider_document_id = coalesce(p_provider_document_id, provider_document_id),\n integration_id = coalesce(p_integration_id, integration_id),\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = CASE WHEN p_status = 'error' THEN p_message ELSE NULL END,\n next_attempt_at = CASE WHEN v_job_status = 'waiting' THEN now() + interval '2 minutes' ELSE NULL END,\n locked_until = NULL, updated_at = now()\n WHERE id = p_job_id;\n\n UPDATE public.plg_financial_nfe\n SET status = v_document_status,\n number = coalesce(p_number, number),\n series = coalesce(p_series, series),\n access_key = coalesce(p_access_key, access_key),\n issued_at = CASE WHEN p_status = 'issued' THEN coalesce(issued_at, now()) ELSE issued_at END,\n error_message = CASE WHEN v_document_status = 'error' THEN p_message ELSE NULL END,\n metadata = metadata || jsonb_build_object('plugnotas', jsonb_strip_nulls(jsonb_build_object(\n 'jobId', p_job_id,\n 'jobStatus', v_job_status,\n 'operation', v_job.operation,\n 'providerDocumentId', coalesce(p_provider_document_id, v_job.provider_document_id),\n 'integrationId', coalesce(p_integration_id, v_job.integration_id),\n 'cancellationPending', v_job.operation = 'cancel' AND v_job_status = 'waiting'\n ))),\n updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = v_job.nota_id;\n\n INSERT INTO public.plg_fiscalbr_nfce_events (tenant_id, nota_id, job_id, event_type, payload)\n VALUES (p_tenant_id, v_job.nota_id, p_job_id, v_job.operation || '.' || p_status,\n coalesce(p_provider_response, '{}'::jsonb));\n RETURN v_job.nota_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_webhook(\n p_provider_event_id text,\n p_payload_sha256 text,\n p_provider_document_id text,\n p_status text,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_payload jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_receipt_id bigint;\n v_receipt public.plg_fiscalbr_webhook_receipts%ROWTYPE;\nBEGIN\n INSERT INTO public.plg_fiscalbr_webhook_receipts\n (provider_event_id, payload_sha256)\n VALUES (p_provider_event_id, p_payload_sha256)\n ON CONFLICT (provider, provider_event_id) DO NOTHING\n RETURNING id INTO v_receipt_id;\n SELECT * INTO v_receipt FROM public.plg_fiscalbr_webhook_receipts\n WHERE provider = 'plugnotas' AND provider_event_id = p_provider_event_id FOR UPDATE;\n v_receipt_id := v_receipt.id;\n IF v_receipt.payload_sha256 IS DISTINCT FROM p_payload_sha256 THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_webhook: conflicting event payload' USING ERRCODE = '22023';\n END IF;\n IF v_receipt.processed_at IS NOT NULL AND v_receipt.processing_error IS NULL THEN\n RETURN jsonb_build_object('duplicate', true, 'matched', true);\n END IF;\n\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE provider_document_id = p_provider_document_id\n ORDER BY created_at DESC LIMIT 1;\n IF NOT FOUND THEN\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET processed_at = NULL, processing_error = 'job_not_found'\n WHERE id = v_receipt_id;\n RETURN jsonb_build_object('duplicate', false, 'matched', false);\n END IF;\n\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET tenant_id = v_job.tenant_id, nota_id = v_job.nota_id, processed_at = now(), processing_error = NULL\n WHERE id = v_receipt_id;\n PERFORM public.plugnotas_apply_nfce_result(\n v_job.tenant_id, v_job.id, p_status, p_provider_document_id,\n coalesce(p_integration_id, v_job.integration_id), p_number, p_series,\n p_access_key, p_message, p_payload\n );\n RETURN jsonb_build_object('duplicate', false, 'matched', true, 'jobId', v_job.id);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_claim_nfce_recovery(\n p_limit integer DEFAULT 20\n) RETURNS SETOF public.plg_fiscalbr_nfce_jobs\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n RETURN QUERY\n WITH candidates AS (\n SELECT j.id FROM public.plg_fiscalbr_nfce_jobs j\n WHERE j.status IN ('queued', 'waiting', 'running')\n AND coalesce(j.next_attempt_at, j.created_at) <= now()\n AND coalesce(j.locked_until, '-infinity'::timestamptz) < now()\n ORDER BY coalesce(j.next_attempt_at, j.created_at), j.created_at\n FOR UPDATE SKIP LOCKED\n LIMIT greatest(1, least(coalesce(p_limit, 20), 100))\n )\n UPDATE public.plg_fiscalbr_nfce_jobs j\n SET status = 'running', locked_until = now() + interval '2 minutes', updated_at = now()\n FROM candidates c WHERE j.id = c.id\n RETURNING j.*;\nEND $$;\n`\n\nexport const MIGRATIONS: Array<{ id: string; sql: string }> = [\n { id: \"000_baseline\", sql: MIGRATION_000_BASELINE },\n { id: \"001_preserve_terminal_results_and_recover_leases\", sql: MIGRATION_001_PRESERVE_TERMINAL_RESULTS_AND_RECOVER_LEASES },\n]\n","import type { FinancialDataProvider } from '@fayz-ai/plugin-financial'\nimport type { PlugNotasFinancialProviderOptions } from '../types'\n\ntype FiscalDocument = NonNullable<Awaited<ReturnType<NonNullable<FinancialDataProvider['getNotaById']>>>>\n\nfunction fiscalReader(provider: FinancialDataProvider) {\n if (!provider.getNotaById) throw new Error('PlugNotas requires fiscal document reads from Financial.')\n return provider.getNotaById.bind(provider)\n}\n\nasync function committed(read: (id: string) => Promise<FiscalDocument | null>, id: string) {\n const document = await read(id)\n if (!document) throw new Error('Fiscal document was not found after the server operation.')\n return document\n}\n\nfunction resultError(result: { status: string; message?: string }, document: FiscalDocument, fallback: string) {\n if (result.status !== 'error') return\n throw new Error(result.message?.trim() || document.errorMessage?.trim() || fallback)\n}\n\nfunction cancellationPending(metadata: Record<string, unknown> | undefined): boolean {\n const provider = metadata?.plugnotas\n if (!provider || typeof provider !== 'object' || Array.isArray(provider)) return false\n return (provider as Record<string, unknown>).cancellationPending === true\n}\n\nfunction artifactUrl(value: unknown): string {\n if (typeof value !== 'string' || !value.trim()) throw new Error('PlugNotas returned an invalid artifact URL.')\n let parsed: URL\n try {\n parsed = new URL(value)\n } catch {\n throw new Error('PlugNotas returned an invalid artifact URL.')\n }\n if (!['http:', 'https:'].includes(parsed.protocol)) throw new Error('PlugNotas returned an invalid artifact URL.')\n return parsed.toString()\n}\n\n/**\n * Decorates Financial without creating another fiscal ledger. The gateway only\n * requests server operations; every result returned to the UI is read back\n * from the server-committed `plg_financial_nfe` row.\n */\nexport function createPlugNotasFinancialProvider(\n options: PlugNotasFinancialProviderOptions,\n): FinancialDataProvider {\n const { base, gateway } = options\n\n const issueNota: NonNullable<FinancialDataProvider['issueNota']> = async (id) => {\n const read = fiscalReader(base)\n const document = await read(id)\n if (!document) throw new Error('Fiscal document not found.')\n if (document.model !== 'nfce') throw new Error('PlugNotas currently authorizes NFC-e only.')\n if (!document.orderId?.trim()) throw new Error('PlugNotas NFC-e must be created from an order.')\n if (!['draft', 'error'].includes(document.status)) return document\n const result = await gateway.issue({ notaId: id, idempotencyKey: `nfce:${id}` })\n const saved = await committed(read, id)\n resultError(result, saved, 'PlugNotas could not issue this NFC-e.')\n return saved\n }\n\n const refreshNota: NonNullable<FinancialDataProvider['refreshNota']> = async (id) => {\n const read = fiscalReader(base)\n const document = await read(id)\n if (!document) throw new Error('Fiscal document not found.')\n if (!['processing', 'error'].includes(document.status) && !cancellationPending(document.metadata)) return document\n const result = await gateway.refresh({ notaId: id })\n const saved = await committed(read, id)\n resultError(result, saved, 'PlugNotas could not refresh this NFC-e.')\n return saved\n }\n\n const cancelNota: NonNullable<FinancialDataProvider['cancelNota']> = async (id, reason) => {\n const read = fiscalReader(base)\n const document = await read(id)\n if (!document) throw new Error('Fiscal document not found.')\n if (document.status !== 'issued') throw new Error('Only an issued NFC-e can be cancelled.')\n if (cancellationPending(document.metadata)) throw new Error('NFC-e cancellation is already in progress.')\n const normalized = reason?.trim() ?? ''\n if (normalized.length < 15 || normalized.length > 255) {\n throw new Error('Cancellation reason must contain between 15 and 255 characters.')\n }\n const result = await gateway.cancel({ notaId: id, reason: normalized })\n const saved = await committed(read, id)\n resultError(result, saved, 'PlugNotas could not cancel this NFC-e.')\n return saved\n }\n\n const getNotaArtifactUrl: NonNullable<FinancialDataProvider['getNotaArtifactUrl']> = async (id, kind) => {\n const read = fiscalReader(base)\n const document = await read(id)\n if (!document) throw new Error('Fiscal document not found.')\n if (!['issued', 'cancelled'].includes(document.status)) {\n throw new Error('Fiscal artifacts are available only after authorization.')\n }\n if (kind === 'cancellation_xml' && document.status !== 'cancelled') {\n throw new Error('Cancellation XML is available only after cancellation.')\n }\n return artifactUrl((await gateway.artifact({ notaId: id, kind })).url)\n }\n\n return new Proxy(base, {\n get(target, property, receiver) {\n if (property === 'issueNota') return issueNota\n if (property === 'refreshNota') return refreshNota\n if (property === 'cancelNota') return cancelNota\n if (property === 'getNotaArtifactUrl') return getNotaArtifactUrl\n return Reflect.get(target, property, receiver)\n },\n })\n}\n","import { definePlugin, type PluginManifest } from '@fayz-ai/core'\nimport { createPlugNotasConnector, type CreatePlugNotasConnectorOptions } from './connectors/plugnotas'\nimport { MIGRATIONS } from './migrations'\n\nexport * from './connectors/plugnotas'\nexport * from './lib/financial-provider'\nexport * from './types'\n\nexport interface CreatePlugNotasPluginOptions extends CreatePlugNotasConnectorOptions {}\n\n/**\n * Fiscal Brasil is an addon: Financial owns the fiscal document, while this\n * package owns the provider connection and its asynchronous delivery trail.\n */\nexport function createPlugNotasPlugin(options: CreatePlugNotasPluginOptions = {}): PluginManifest {\n return definePlugin({\n id: 'fiscal-br',\n name: 'Fiscal Brasil',\n icon: 'ReceiptText',\n version: '0.1.0',\n apiVersion: 1,\n scope: 'addon',\n defaultEnabled: true,\n dependencies: ['financial'],\n navigation: [],\n routes: [],\n connectors: [createPlugNotasConnector(options)],\n functions: [{\n slug: 'plugnotas-bridge',\n ingress: 'none',\n verifyJwt: false,\n secrets: [\n 'PLUGNOTAS_API_KEY',\n 'PLUGNOTAS_BASE_URL',\n 'PLUGNOTAS_ENVIRONMENT',\n 'PLUGNOTAS_WEBHOOK_SECRET',\n 'PLUGNOTAS_ARTIFACT_SIGNING_KEY',\n 'PLUGNOTAS_ALLOWED_ORIGINS',\n 'PLUGNOTAS_WORKER_SECRET',\n 'SUPABASE_URL',\n 'SUPABASE_ANON_KEY',\n 'SUPABASE_SERVICE_ROLE_KEY'\n ],\n grants: [\n 'plugnotas_register_emitter',\n 'plugnotas_disconnect_emitter',\n 'plugnotas_create_nfce_draft_for_order',\n 'plugnotas_prepare_nfce',\n 'plugnotas_prepare_nfce_cancel',\n 'plugnotas_apply_nfce_result',\n 'plugnotas_apply_nfce_webhook',\n 'plugnotas_get_artifact_locator',\n 'plugnotas_claim_nfce_recovery',\n 'plugnotas_record_nfce_attempt'\n ],\n }],\n migrations: MIGRATIONS.map((entry) => ({\n id: `fiscal-br-${entry.id}`,\n version: '1.0.0',\n sql: entry.sql,\n description: 'Durable PlugNotas delivery, recovery, webhook and emitter-registration boundary.',\n })),\n diagnostics: [{\n id: 'plugnotas-nfce-ready',\n description: 'NFC-e requires the shared connection, order, item and financial fiscal-document contracts.',\n requires: {\n tables: [\n 'connections',\n 'orders',\n 'items',\n 'plg_financial_nfe',\n 'plg_fiscalbr_nfce_jobs',\n 'plg_fiscalbr_nfce_events',\n 'plg_fiscalbr_webhook_receipts',\n ],\n rpcs: [\n 'plugnotas_create_nfce_draft_for_order',\n 'plugnotas_prepare_nfce',\n 'plugnotas_apply_nfce_result',\n 'plugnotas_apply_nfce_webhook',\n 'plugnotas_claim_nfce_recovery',\n ],\n env: [\n 'PLUGNOTAS_API_KEY',\n 'PLUGNOTAS_BASE_URL',\n 'PLUGNOTAS_ENVIRONMENT',\n 'PLUGNOTAS_WEBHOOK_SECRET',\n 'PLUGNOTAS_ARTIFACT_SIGNING_KEY',\n 'PLUGNOTAS_ALLOWED_ORIGINS',\n 'PLUGNOTAS_WORKER_SECRET',\n ],\n },\n level: 'error',\n }],\n })\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FinancialDataProvider } from '@fayz-ai/plugin-financial';
|
|
2
|
+
import type { PlugNotasFinancialProviderOptions } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Decorates Financial without creating another fiscal ledger. The gateway only
|
|
5
|
+
* requests server operations; every result returned to the UI is read back
|
|
6
|
+
* from the server-committed `plg_financial_nfe` row.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createPlugNotasFinancialProvider(options: PlugNotasFinancialProviderOptions): FinancialDataProvider;
|
|
9
|
+
//# sourceMappingURL=financial-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"financial-provider.d.ts","sourceRoot":"","sources":["../../src/lib/financial-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACtE,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,UAAU,CAAA;AAsCjE;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,iCAAiC,GACzC,qBAAqB,CAiEvB"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const MIGRATION_000_BASELINE = "-- Fiscal Brasil / PlugNotas baseline.\n--\n-- This addon does not create a second fiscal ledger. `plg_financial_nfe`\n-- remains the authoritative document owned by plugin-financial. The tables\n-- below describe delivery to an external issuer: durable commands, attempts,\n-- webhooks and emitter ownership.\n--\n-- The file is additive and idempotent because the current restaurant pool is\n-- live. Applying it is deliberately outside this draft PR.\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_nfce_jobs (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n -- Logical reference to plugin-financial's fiscal ledger. Cross-plugin\n -- physical foreign keys are intentionally forbidden: installation and\n -- removal of this addon must never rewrite another plugin's schema.\n nota_id uuid NOT NULL,\n order_id uuid NOT NULL REFERENCES public.orders(id) ON DELETE RESTRICT,\n connection_id uuid NOT NULL REFERENCES public.connections(id) ON DELETE RESTRICT,\n operation text NOT NULL CHECK (operation IN ('issue', 'cancel')),\n status text NOT NULL DEFAULT 'queued'\n CHECK (status IN ('queued', 'running', 'waiting', 'succeeded', 'failed', 'manual_review')),\n idempotency_key text NOT NULL,\n provider_document_id text,\n integration_id text,\n request_snapshot jsonb NOT NULL DEFAULT '{}'::jsonb,\n provider_response jsonb NOT NULL DEFAULT '{}'::jsonb,\n attempts integer NOT NULL DEFAULT 0 CHECK (attempts >= 0),\n next_attempt_at timestamptz,\n locked_until timestamptz,\n last_error text,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (tenant_id, idempotency_key)\n);\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_nfce_jobs_recovery_idx\n ON public.plg_fiscalbr_nfce_jobs (status, next_attempt_at, locked_until)\n WHERE status IN ('queued', 'waiting');\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_nfce_events (\n id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n nota_id uuid NOT NULL,\n job_id uuid REFERENCES public.plg_fiscalbr_nfce_jobs(id) ON DELETE SET NULL,\n event_type text NOT NULL,\n payload jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now()\n);\n\nCREATE INDEX IF NOT EXISTS plg_fiscalbr_nfce_events_document_idx\n ON public.plg_fiscalbr_nfce_events (tenant_id, nota_id, created_at DESC);\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_webhook_receipts (\n id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n provider text NOT NULL DEFAULT 'plugnotas',\n provider_event_id text NOT NULL,\n tenant_id uuid REFERENCES public.tenants(id) ON DELETE SET NULL,\n nota_id uuid,\n payload_sha256 text NOT NULL,\n received_at timestamptz NOT NULL DEFAULT now(),\n processed_at timestamptz,\n processing_error text,\n UNIQUE (provider, provider_event_id)\n);\n\nCREATE TABLE IF NOT EXISTS public.plg_fiscalbr_emitter_ownership (\n emitter_cnpj text PRIMARY KEY CHECK (emitter_cnpj ~ '^[0-9]{14}$'),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n connection_id uuid NOT NULL REFERENCES public.connections(id) ON DELETE CASCADE,\n environment text NOT NULL CHECK (environment IN ('sandbox', 'homologation')),\n provider_emitter_id text,\n certificate_expires_at timestamptz,\n certificate_fingerprint text,\n csc_ready boolean NOT NULL DEFAULT false,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (tenant_id, connection_id)\n);\n\nALTER TABLE public.plg_fiscalbr_nfce_jobs ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_nfce_events ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_webhook_receipts ENABLE ROW LEVEL SECURITY;\nALTER TABLE public.plg_fiscalbr_emitter_ownership ENABLE ROW LEVEL SECURITY;\n\nDROP POLICY IF EXISTS plg_fiscalbr_nfce_jobs_read ON public.plg_fiscalbr_nfce_jobs;\nCREATE POLICY plg_fiscalbr_nfce_jobs_read ON public.plg_fiscalbr_nfce_jobs\n FOR SELECT TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.read', NULL))\n );\n\nDROP POLICY IF EXISTS plg_fiscalbr_nfce_events_read ON public.plg_fiscalbr_nfce_events;\nCREATE POLICY plg_fiscalbr_nfce_events_read ON public.plg_fiscalbr_nfce_events\n FOR SELECT TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.read', NULL))\n );\n\nDROP POLICY IF EXISTS plg_fiscalbr_emitter_ownership_read ON public.plg_fiscalbr_emitter_ownership;\nCREATE POLICY plg_fiscalbr_emitter_ownership_read ON public.plg_fiscalbr_emitter_ownership\n FOR SELECT TO authenticated\n USING (\n tenant_id = (SELECT app.current_tenant_id())\n AND (SELECT app.has_permission('financial.read', NULL))\n );\n\nREVOKE ALL ON public.plg_fiscalbr_nfce_jobs FROM anon, authenticated;\nREVOKE ALL ON public.plg_fiscalbr_nfce_events FROM anon, authenticated;\nREVOKE ALL ON public.plg_fiscalbr_webhook_receipts FROM anon, authenticated;\nREVOKE ALL ON public.plg_fiscalbr_emitter_ownership FROM anon, authenticated;\nGRANT SELECT ON public.plg_fiscalbr_nfce_jobs TO authenticated;\nGRANT SELECT ON public.plg_fiscalbr_nfce_events TO authenticated;\nGRANT SELECT ON public.plg_fiscalbr_emitter_ownership TO authenticated;\nGRANT ALL ON public.plg_fiscalbr_nfce_jobs TO service_role;\nGRANT ALL ON public.plg_fiscalbr_nfce_events TO service_role;\nGRANT ALL ON public.plg_fiscalbr_webhook_receipts TO service_role;\nGRANT ALL ON public.plg_fiscalbr_emitter_ownership TO service_role;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_register_emitter(\n p_tenant_id uuid,\n p_connection_id uuid,\n p_emitter_cnpj text,\n p_environment text,\n p_provider_emitter_id text DEFAULT NULL,\n p_certificate_expires_at timestamptz DEFAULT NULL,\n p_certificate_fingerprint text DEFAULT NULL,\n p_csc_ready boolean DEFAULT false\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_cnpj text := regexp_replace(coalesce(p_emitter_cnpj, ''), '[^0-9]', '', 'g');\nBEGIN\n IF v_cnpj !~ '^[0-9]{14}$' THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: invalid CNPJ' USING ERRCODE = '22023';\n END IF;\n IF p_environment NOT IN ('sandbox', 'homologation') THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: production is not enabled' USING ERRCODE = '22023';\n END IF;\n IF NOT EXISTS (\n SELECT 1 FROM public.connections c\n WHERE c.id = p_connection_id\n AND c.tenant_id = p_tenant_id\n AND c.connector_id = 'plugnotas'\n AND c.active\n ) THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: active connection not found' USING ERRCODE = 'P0002';\n END IF;\n\n INSERT INTO public.plg_fiscalbr_emitter_ownership\n (emitter_cnpj, tenant_id, connection_id, environment, provider_emitter_id,\n certificate_expires_at, certificate_fingerprint, csc_ready, updated_at)\n VALUES\n (v_cnpj, p_tenant_id, p_connection_id, p_environment, p_provider_emitter_id,\n p_certificate_expires_at, p_certificate_fingerprint, p_csc_ready, now())\n ON CONFLICT (emitter_cnpj) DO UPDATE SET\n tenant_id = EXCLUDED.tenant_id,\n connection_id = EXCLUDED.connection_id,\n environment = EXCLUDED.environment,\n provider_emitter_id = EXCLUDED.provider_emitter_id,\n certificate_expires_at = EXCLUDED.certificate_expires_at,\n certificate_fingerprint = EXCLUDED.certificate_fingerprint,\n csc_ready = EXCLUDED.csc_ready,\n updated_at = now()\n WHERE public.plg_fiscalbr_emitter_ownership.tenant_id = EXCLUDED.tenant_id;\n\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_register_emitter: CNPJ belongs to another tenant' USING ERRCODE = '23505';\n END IF;\n\n UPDATE public.connections\n SET provider_account_key = v_cnpj,\n settings = settings || jsonb_build_object(\n 'environment', p_environment,\n 'certificateReady', p_certificate_expires_at IS NOT NULL,\n 'certificateExpiresAt', p_certificate_expires_at,\n 'certificateFingerprint', p_certificate_fingerprint,\n 'providerEmitterId', p_provider_emitter_id,\n 'cscReady', p_csc_ready\n ),\n status = CASE WHEN p_certificate_expires_at IS NOT NULL AND p_csc_ready THEN 'connected' ELSE 'pending' END,\n updated_at = now()\n WHERE id = p_connection_id AND tenant_id = p_tenant_id;\n\n RETURN jsonb_build_object('emitterCnpj', v_cnpj, 'environment', p_environment);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_disconnect_emitter(\n p_tenant_id uuid,\n p_connection_id uuid\n) RETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n DELETE FROM public.plg_fiscalbr_emitter_ownership\n WHERE tenant_id = p_tenant_id AND connection_id = p_connection_id;\n UPDATE public.connections\n SET active = false, status = 'revoked', settings = '{}'::jsonb,\n provider_state = '{}'::jsonb, updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_connection_id AND connector_id = 'plugnotas';\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_create_nfce_draft_for_order(\n p_tenant_id uuid,\n p_order_id uuid\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_order public.orders%ROWTYPE;\n v_nota_id uuid;\nBEGIN\n -- Serialize draft creation per tenant/order without adding a column or\n -- index to the financial plugin's table. The order itself remains the\n -- stable idempotency boundary for one NFC-e draft.\n PERFORM pg_advisory_xact_lock(hashtextextended(p_tenant_id::text || ':' || p_order_id::text, 0));\n\n SELECT * INTO v_order FROM public.orders\n WHERE tenant_id = p_tenant_id AND id = p_order_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_create_nfce_draft_for_order: order not found' USING ERRCODE = 'P0002';\n END IF;\n IF v_order.status NOT IN ('completed', 'paid', 'invoiced') THEN\n RAISE EXCEPTION 'plugnotas_create_nfce_draft_for_order: order is not closed' USING ERRCODE = '23514';\n END IF;\n IF NOT EXISTS (SELECT 1 FROM public.items i WHERE i.tenant_id = p_tenant_id AND i.order_id = p_order_id) THEN\n RAISE EXCEPTION 'plugnotas_create_nfce_draft_for_order: order has no items' USING ERRCODE = '23514';\n END IF;\n\n SELECT n.id INTO v_nota_id FROM public.plg_financial_nfe n\n WHERE n.tenant_id = p_tenant_id AND n.order_id = p_order_id AND n.model = 'nfce'\n ORDER BY n.created_at DESC LIMIT 1;\n IF v_nota_id IS NOT NULL THEN RETURN v_nota_id; END IF;\n\n INSERT INTO public.plg_financial_nfe\n (tenant_id, unit_id, model, status, order_id, contact_id, total_amount,\n emissor, metadata)\n VALUES\n (p_tenant_id, v_order.unit_id, 'nfce', 'draft', p_order_id, v_order.party_id,\n coalesce(v_order.total, 0), 'plugnotas',\n jsonb_build_object('source', 'order', 'orderKind', v_order.kind, 'orderChannel', v_order.channel))\n RETURNING id INTO v_nota_id;\n RETURN v_nota_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_prepare_nfce(\n p_tenant_id uuid,\n p_nota_id uuid,\n p_connection_id uuid,\n p_idempotency_key text\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_nota public.plg_financial_nfe%ROWTYPE;\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_snapshot jsonb;\nBEGIN\n SELECT * INTO v_nota FROM public.plg_financial_nfe\n WHERE tenant_id = p_tenant_id AND id = p_nota_id FOR UPDATE;\n IF NOT FOUND OR v_nota.model <> 'nfce' OR v_nota.order_id IS NULL THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: order-backed NFC-e not found' USING ERRCODE = 'P0002';\n END IF;\n IF v_nota.status NOT IN ('draft', 'error', 'processing') THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: invalid document status %', v_nota.status USING ERRCODE = '23514';\n END IF;\n IF NOT EXISTS (\n SELECT 1 FROM public.plg_fiscalbr_emitter_ownership e\n WHERE e.tenant_id = p_tenant_id AND e.connection_id = p_connection_id\n AND e.csc_ready AND e.certificate_expires_at > now()\n ) THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: emitter is not ready' USING ERRCODE = '23514';\n END IF;\n\n SELECT jsonb_build_object(\n 'nota', to_jsonb(v_nota),\n 'order', to_jsonb(o),\n 'items', coalesce((\n SELECT jsonb_agg(to_jsonb(i) ORDER BY i.sort_order, i.id)\n FROM public.items i\n WHERE i.tenant_id = p_tenant_id AND i.order_id = v_nota.order_id\n ), '[]'::jsonb),\n -- Product tax metadata must be frozen in the same transaction as the order\n -- lines. Looking products up in the Edge Function would let a retry emit\n -- with NCM/CFOP changed after the operator confirmed the document.\n 'products', coalesce((\n SELECT jsonb_agg(to_jsonb(p) ORDER BY p.id)\n FROM public.products p\n WHERE p.tenant_id = p_tenant_id\n AND p.id IN (\n SELECT i.product_id FROM public.items i\n WHERE i.tenant_id = p_tenant_id\n AND i.order_id = v_nota.order_id\n AND i.product_id IS NOT NULL\n )\n ), '[]'::jsonb)\n ) INTO v_snapshot\n FROM public.orders o\n WHERE o.tenant_id = p_tenant_id AND o.id = v_nota.order_id;\n\n IF jsonb_array_length(v_snapshot->'items') = 0 THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce: order has no items' USING ERRCODE = '23514';\n END IF;\n\n INSERT INTO public.plg_fiscalbr_nfce_jobs\n (tenant_id, nota_id, order_id, connection_id, operation, status,\n idempotency_key, request_snapshot, next_attempt_at, updated_at)\n VALUES\n (p_tenant_id, p_nota_id, v_nota.order_id, p_connection_id, 'issue', 'queued',\n p_idempotency_key, v_snapshot, now(), now())\n ON CONFLICT (tenant_id, idempotency_key) DO UPDATE\n SET updated_at = now()\n RETURNING * INTO v_job;\n\n UPDATE public.plg_financial_nfe\n SET status = 'processing', error_message = NULL,\n metadata = metadata || jsonb_build_object('plugnotas', jsonb_build_object(\n 'jobId', v_job.id, 'jobStatus', v_job.status, 'operation', 'issue'\n )), updated_at = now()\n WHERE id = p_nota_id AND tenant_id = p_tenant_id;\n\n INSERT INTO public.plg_fiscalbr_nfce_events (tenant_id, nota_id, job_id, event_type, payload)\n VALUES (p_tenant_id, p_nota_id, v_job.id, 'issue.queued', '{}'::jsonb);\n RETURN jsonb_build_object('jobId', v_job.id, 'snapshot', v_job.request_snapshot, 'replayed', v_job.attempts > 0);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_prepare_nfce_cancel(\n p_tenant_id uuid,\n p_nota_id uuid,\n p_connection_id uuid,\n p_reason text\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_nota public.plg_financial_nfe%ROWTYPE;\n v_job_id uuid;\n v_reason text := btrim(coalesce(p_reason, ''));\nBEGIN\n IF char_length(v_reason) NOT BETWEEN 15 AND 255 THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce_cancel: reason must contain 15 to 255 characters' USING ERRCODE = '22023';\n END IF;\n SELECT * INTO v_nota FROM public.plg_financial_nfe\n WHERE tenant_id = p_tenant_id AND id = p_nota_id FOR UPDATE;\n IF NOT FOUND OR v_nota.status <> 'issued' OR v_nota.access_key IS NULL THEN\n RAISE EXCEPTION 'plugnotas_prepare_nfce_cancel: authorized NFC-e not found' USING ERRCODE = '23514';\n END IF;\n\n INSERT INTO public.plg_fiscalbr_nfce_jobs\n (tenant_id, nota_id, order_id, connection_id, operation, status,\n idempotency_key, provider_document_id, integration_id,\n request_snapshot, next_attempt_at)\n VALUES\n (p_tenant_id, p_nota_id, v_nota.order_id, p_connection_id, 'cancel', 'queued',\n 'nfce-cancel:' || p_nota_id::text,\n v_nota.metadata #>> '{plugnotas,providerDocumentId}',\n v_nota.metadata #>> '{plugnotas,integrationId}',\n jsonb_build_object('reason', v_reason), now())\n ON CONFLICT (tenant_id, idempotency_key) DO UPDATE SET\n provider_document_id = coalesce(\n public.plg_fiscalbr_nfce_jobs.provider_document_id,\n EXCLUDED.provider_document_id\n ),\n integration_id = coalesce(\n public.plg_fiscalbr_nfce_jobs.integration_id,\n EXCLUDED.integration_id\n ),\n updated_at = now()\n RETURNING id INTO v_job_id;\n\n UPDATE public.plg_financial_nfe\n SET metadata = metadata || jsonb_build_object('plugnotas', jsonb_build_object(\n 'jobId', v_job_id, 'jobStatus', 'queued', 'operation', 'cancel', 'cancellationPending', true\n )), updated_at = now()\n WHERE id = p_nota_id AND tenant_id = p_tenant_id;\n RETURN jsonb_build_object('jobId', v_job_id, 'reason', v_reason);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_record_nfce_attempt(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_response jsonb DEFAULT '{}'::jsonb,\n p_error text DEFAULT NULL,\n p_next_attempt_at timestamptz DEFAULT NULL\n) RETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n IF p_status NOT IN ('running', 'waiting', 'failed', 'manual_review') THEN\n RAISE EXCEPTION 'plugnotas_record_nfce_attempt: invalid status' USING ERRCODE = '22023';\n END IF;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = p_status,\n -- One provider dispatch is one attempt. Moving that same attempt from\n -- running to waiting/failed must not count it a second time.\n attempts = attempts + CASE WHEN p_status = 'running' THEN 1 ELSE 0 END,\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = p_error, next_attempt_at = p_next_attempt_at,\n locked_until = NULL, updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_job_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_result(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_document_id text DEFAULT NULL,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_provider_response jsonb DEFAULT '{}'::jsonb\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_document_status text;\nBEGIN\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE tenant_id = p_tenant_id AND id = p_job_id FOR UPDATE;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: job not found' USING ERRCODE = 'P0002';\n END IF;\n IF p_status NOT IN ('processing', 'issued', 'cancelled', 'error') THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: invalid status' USING ERRCODE = '22023';\n END IF;\n\n v_document_status := CASE\n WHEN v_job.operation = 'cancel' AND p_status = 'processing' THEN 'issued'\n ELSE p_status\n END;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = CASE\n WHEN p_status IN ('issued', 'cancelled') THEN 'succeeded'\n WHEN p_status = 'error' THEN 'failed'\n ELSE 'waiting'\n END,\n provider_document_id = coalesce(p_provider_document_id, provider_document_id),\n integration_id = coalesce(p_integration_id, integration_id),\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = CASE WHEN p_status = 'error' THEN p_message ELSE NULL END,\n next_attempt_at = CASE WHEN p_status = 'processing' THEN now() + interval '2 minutes' ELSE NULL END,\n locked_until = NULL, updated_at = now()\n WHERE id = p_job_id;\n\n UPDATE public.plg_financial_nfe\n SET status = v_document_status,\n number = coalesce(p_number, number),\n series = coalesce(p_series, series),\n access_key = coalesce(p_access_key, access_key),\n issued_at = CASE WHEN p_status = 'issued' THEN coalesce(issued_at, now()) ELSE issued_at END,\n error_message = CASE WHEN p_status = 'error' THEN p_message ELSE NULL END,\n metadata = metadata || jsonb_build_object('plugnotas', jsonb_strip_nulls(jsonb_build_object(\n 'jobId', p_job_id,\n 'jobStatus', CASE WHEN p_status IN ('issued', 'cancelled') THEN 'succeeded' WHEN p_status = 'error' THEN 'failed' ELSE 'waiting' END,\n 'operation', v_job.operation,\n 'providerDocumentId', coalesce(p_provider_document_id, v_job.provider_document_id),\n 'integrationId', coalesce(p_integration_id, v_job.integration_id),\n 'cancellationPending', v_job.operation = 'cancel' AND p_status = 'processing'\n ))),\n updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = v_job.nota_id;\n\n INSERT INTO public.plg_fiscalbr_nfce_events (tenant_id, nota_id, job_id, event_type, payload)\n VALUES (p_tenant_id, v_job.nota_id, p_job_id, v_job.operation || '.' || p_status,\n coalesce(p_provider_response, '{}'::jsonb));\n RETURN v_job.nota_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_webhook(\n p_provider_event_id text,\n p_payload_sha256 text,\n p_provider_document_id text,\n p_status text,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_payload jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_receipt_id bigint;\nBEGIN\n INSERT INTO public.plg_fiscalbr_webhook_receipts\n (provider_event_id, payload_sha256)\n VALUES (p_provider_event_id, p_payload_sha256)\n ON CONFLICT (provider, provider_event_id) DO NOTHING\n RETURNING id INTO v_receipt_id;\n IF v_receipt_id IS NULL THEN RETURN jsonb_build_object('duplicate', true); END IF;\n\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE provider_document_id = p_provider_document_id\n ORDER BY created_at DESC LIMIT 1;\n IF NOT FOUND THEN\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET processed_at = now(), processing_error = 'job_not_found'\n WHERE id = v_receipt_id;\n RETURN jsonb_build_object('duplicate', false, 'matched', false);\n END IF;\n\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET tenant_id = v_job.tenant_id, nota_id = v_job.nota_id, processed_at = now()\n WHERE id = v_receipt_id;\n PERFORM public.plugnotas_apply_nfce_result(\n v_job.tenant_id, v_job.id, p_status, p_provider_document_id,\n coalesce(p_integration_id, v_job.integration_id), p_number, p_series,\n p_access_key, p_message, p_payload\n );\n RETURN jsonb_build_object('duplicate', false, 'matched', true, 'jobId', v_job.id);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_get_artifact_locator(\n p_tenant_id uuid,\n p_nota_id uuid\n) RETURNS jsonb\nLANGUAGE sql SECURITY DEFINER SET search_path = '' STABLE AS $$\n SELECT jsonb_build_object(\n 'notaId', n.id,\n 'status', n.status,\n 'providerDocumentId', n.metadata #>> '{plugnotas,providerDocumentId}',\n 'integrationId', n.metadata #>> '{plugnotas,integrationId}'\n )\n FROM public.plg_financial_nfe n\n WHERE n.tenant_id = p_tenant_id AND n.id = p_nota_id\n AND n.status IN ('issued', 'cancelled');\n$$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_claim_nfce_recovery(\n p_limit integer DEFAULT 20\n) RETURNS SETOF public.plg_fiscalbr_nfce_jobs\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n RETURN QUERY\n WITH candidates AS (\n SELECT j.id FROM public.plg_fiscalbr_nfce_jobs j\n WHERE j.status IN ('queued', 'waiting')\n AND coalesce(j.next_attempt_at, j.created_at) <= now()\n AND coalesce(j.locked_until, '-infinity'::timestamptz) < now()\n ORDER BY coalesce(j.next_attempt_at, j.created_at), j.created_at\n FOR UPDATE SKIP LOCKED\n LIMIT greatest(1, least(coalesce(p_limit, 20), 100))\n )\n UPDATE public.plg_fiscalbr_nfce_jobs j\n SET status = 'running', locked_until = now() + interval '2 minutes', updated_at = now()\n FROM candidates c WHERE j.id = c.id\n RETURNING j.*;\nEND $$;\n\nREVOKE ALL ON FUNCTION public.plugnotas_register_emitter(uuid, uuid, text, text, text, timestamptz, text, boolean) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_disconnect_emitter(uuid, uuid) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_create_nfce_draft_for_order(uuid, uuid) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_prepare_nfce(uuid, uuid, uuid, text) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_prepare_nfce_cancel(uuid, uuid, uuid, text) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_record_nfce_attempt(uuid, uuid, text, jsonb, text, timestamptz) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_apply_nfce_result(uuid, uuid, text, text, text, text, text, text, text, jsonb) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_apply_nfce_webhook(text, text, text, text, text, text, text, text, text, jsonb) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_get_artifact_locator(uuid, uuid) FROM PUBLIC, anon, authenticated;\nREVOKE ALL ON FUNCTION public.plugnotas_claim_nfce_recovery(integer) FROM PUBLIC, anon, authenticated;\n\nGRANT EXECUTE ON FUNCTION public.plugnotas_register_emitter(uuid, uuid, text, text, text, timestamptz, text, boolean) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_disconnect_emitter(uuid, uuid) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_create_nfce_draft_for_order(uuid, uuid) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_prepare_nfce(uuid, uuid, uuid, text) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_prepare_nfce_cancel(uuid, uuid, uuid, text) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_record_nfce_attempt(uuid, uuid, text, jsonb, text, timestamptz) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_apply_nfce_result(uuid, uuid, text, text, text, text, text, text, text, jsonb) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_apply_nfce_webhook(text, text, text, text, text, text, text, text, text, jsonb) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_get_artifact_locator(uuid, uuid) TO service_role;\nGRANT EXECUTE ON FUNCTION public.plugnotas_claim_nfce_recovery(integer) TO service_role;\n";
|
|
2
|
+
export declare const MIGRATION_001_PRESERVE_TERMINAL_RESULTS_AND_RECOVER_LEASES = "-- Incremental recovery fix. Preserve 000_baseline.sql and its recorded checksum.\n-- Only existing fiscal functions change; no parallel ledger/schema or backfill.\n-- CREATE OR REPLACE retains the service-role-only ACL from the baseline.\n\nCREATE OR REPLACE FUNCTION public.plugnotas_record_nfce_attempt(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_response jsonb DEFAULT '{}'::jsonb,\n p_error text DEFAULT NULL,\n p_next_attempt_at timestamptz DEFAULT NULL\n) RETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n IF p_status NOT IN ('running', 'waiting', 'failed', 'manual_review') THEN\n RAISE EXCEPTION 'plugnotas_record_nfce_attempt: invalid status' USING ERRCODE = '22023';\n END IF;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = p_status,\n -- One provider dispatch is one attempt. Moving that same attempt from\n -- running to waiting/failed must not count it a second time.\n attempts = attempts + CASE WHEN p_status = 'running' THEN 1 ELSE 0 END,\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = p_error, next_attempt_at = p_next_attempt_at,\n locked_until = CASE WHEN p_status = 'running'\n THEN greatest(coalesce(locked_until, now()), now() + interval '2 minutes') ELSE NULL END,\n updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_job_id AND status <> 'succeeded';\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_result(\n p_tenant_id uuid,\n p_job_id uuid,\n p_status text,\n p_provider_document_id text DEFAULT NULL,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_provider_response jsonb DEFAULT '{}'::jsonb\n) RETURNS uuid\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_document_status text;\n v_existing_status text;\n v_job_status text;\nBEGIN\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE tenant_id = p_tenant_id AND id = p_job_id;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: job not found' USING ERRCODE = 'P0002';\n END IF;\n IF p_status NOT IN ('processing', 'issued', 'cancelled', 'error') THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: invalid status' USING ERRCODE = '22023';\n END IF;\n\n -- Match prepare/cancel's lock order: document, then job.\n SELECT status INTO v_existing_status FROM public.plg_financial_nfe\n WHERE tenant_id = p_tenant_id AND id = v_job.nota_id FOR UPDATE;\n IF NOT FOUND THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_result: document not found' USING ERRCODE = 'P0002';\n END IF;\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE tenant_id = p_tenant_id AND id = p_job_id FOR UPDATE;\n\n -- Late polling must not regress a concluded document or an active cancellation.\n IF v_existing_status = 'cancelled'\n OR (v_job.operation = 'issue' AND v_existing_status = 'issued' AND p_status <> 'cancelled')\n OR (v_job.status = 'succeeded' AND p_status IN ('processing', 'error')) THEN\n -- Old/interrupted jobs may still be running after the document concluded.\n -- Settle their lease too, otherwise recovery would claim them forever.\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = 'succeeded', locked_until = NULL, next_attempt_at = NULL, updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = p_job_id;\n RETURN v_job.nota_id;\n END IF;\n\n v_job_status := CASE\n WHEN p_status = 'cancelled' OR (v_job.operation = 'issue' AND p_status = 'issued') THEN 'succeeded'\n WHEN p_status = 'error' THEN 'failed'\n ELSE 'waiting' END;\n v_document_status := CASE\n WHEN v_job.operation = 'cancel' AND p_status <> 'cancelled' THEN v_existing_status\n ELSE p_status\n END;\n UPDATE public.plg_fiscalbr_nfce_jobs\n SET status = v_job_status,\n provider_document_id = coalesce(p_provider_document_id, provider_document_id),\n integration_id = coalesce(p_integration_id, integration_id),\n provider_response = coalesce(p_provider_response, '{}'::jsonb),\n last_error = CASE WHEN p_status = 'error' THEN p_message ELSE NULL END,\n next_attempt_at = CASE WHEN v_job_status = 'waiting' THEN now() + interval '2 minutes' ELSE NULL END,\n locked_until = NULL, updated_at = now()\n WHERE id = p_job_id;\n\n UPDATE public.plg_financial_nfe\n SET status = v_document_status,\n number = coalesce(p_number, number),\n series = coalesce(p_series, series),\n access_key = coalesce(p_access_key, access_key),\n issued_at = CASE WHEN p_status = 'issued' THEN coalesce(issued_at, now()) ELSE issued_at END,\n error_message = CASE WHEN v_document_status = 'error' THEN p_message ELSE NULL END,\n metadata = metadata || jsonb_build_object('plugnotas', jsonb_strip_nulls(jsonb_build_object(\n 'jobId', p_job_id,\n 'jobStatus', v_job_status,\n 'operation', v_job.operation,\n 'providerDocumentId', coalesce(p_provider_document_id, v_job.provider_document_id),\n 'integrationId', coalesce(p_integration_id, v_job.integration_id),\n 'cancellationPending', v_job.operation = 'cancel' AND v_job_status = 'waiting'\n ))),\n updated_at = now()\n WHERE tenant_id = p_tenant_id AND id = v_job.nota_id;\n\n INSERT INTO public.plg_fiscalbr_nfce_events (tenant_id, nota_id, job_id, event_type, payload)\n VALUES (p_tenant_id, v_job.nota_id, p_job_id, v_job.operation || '.' || p_status,\n coalesce(p_provider_response, '{}'::jsonb));\n RETURN v_job.nota_id;\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_apply_nfce_webhook(\n p_provider_event_id text,\n p_payload_sha256 text,\n p_provider_document_id text,\n p_status text,\n p_integration_id text DEFAULT NULL,\n p_number text DEFAULT NULL,\n p_series text DEFAULT NULL,\n p_access_key text DEFAULT NULL,\n p_message text DEFAULT NULL,\n p_payload jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nDECLARE\n v_job public.plg_fiscalbr_nfce_jobs%ROWTYPE;\n v_receipt_id bigint;\n v_receipt public.plg_fiscalbr_webhook_receipts%ROWTYPE;\nBEGIN\n INSERT INTO public.plg_fiscalbr_webhook_receipts\n (provider_event_id, payload_sha256)\n VALUES (p_provider_event_id, p_payload_sha256)\n ON CONFLICT (provider, provider_event_id) DO NOTHING\n RETURNING id INTO v_receipt_id;\n SELECT * INTO v_receipt FROM public.plg_fiscalbr_webhook_receipts\n WHERE provider = 'plugnotas' AND provider_event_id = p_provider_event_id FOR UPDATE;\n v_receipt_id := v_receipt.id;\n IF v_receipt.payload_sha256 IS DISTINCT FROM p_payload_sha256 THEN\n RAISE EXCEPTION 'plugnotas_apply_nfce_webhook: conflicting event payload' USING ERRCODE = '22023';\n END IF;\n IF v_receipt.processed_at IS NOT NULL AND v_receipt.processing_error IS NULL THEN\n RETURN jsonb_build_object('duplicate', true, 'matched', true);\n END IF;\n\n SELECT * INTO v_job FROM public.plg_fiscalbr_nfce_jobs\n WHERE provider_document_id = p_provider_document_id\n ORDER BY created_at DESC LIMIT 1;\n IF NOT FOUND THEN\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET processed_at = NULL, processing_error = 'job_not_found'\n WHERE id = v_receipt_id;\n RETURN jsonb_build_object('duplicate', false, 'matched', false);\n END IF;\n\n UPDATE public.plg_fiscalbr_webhook_receipts\n SET tenant_id = v_job.tenant_id, nota_id = v_job.nota_id, processed_at = now(), processing_error = NULL\n WHERE id = v_receipt_id;\n PERFORM public.plugnotas_apply_nfce_result(\n v_job.tenant_id, v_job.id, p_status, p_provider_document_id,\n coalesce(p_integration_id, v_job.integration_id), p_number, p_series,\n p_access_key, p_message, p_payload\n );\n RETURN jsonb_build_object('duplicate', false, 'matched', true, 'jobId', v_job.id);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.plugnotas_claim_nfce_recovery(\n p_limit integer DEFAULT 20\n) RETURNS SETOF public.plg_fiscalbr_nfce_jobs\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = '' AS $$\nBEGIN\n RETURN QUERY\n WITH candidates AS (\n SELECT j.id FROM public.plg_fiscalbr_nfce_jobs j\n WHERE j.status IN ('queued', 'waiting', 'running')\n AND coalesce(j.next_attempt_at, j.created_at) <= now()\n AND coalesce(j.locked_until, '-infinity'::timestamptz) < now()\n ORDER BY coalesce(j.next_attempt_at, j.created_at), j.created_at\n FOR UPDATE SKIP LOCKED\n LIMIT greatest(1, least(coalesce(p_limit, 20), 100))\n )\n UPDATE public.plg_fiscalbr_nfce_jobs j\n SET status = 'running', locked_until = now() + interval '2 minutes', updated_at = now()\n FROM candidates c WHERE j.id = c.id\n RETURNING j.*;\nEND $$;\n";
|
|
3
|
+
export declare const MIGRATIONS: Array<{
|
|
4
|
+
id: string;
|
|
5
|
+
sql: string;
|
|
6
|
+
}>;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,sBAAsB,2g0BA2jBlC,CAAA;AAED,eAAO,MAAM,0DAA0D,uzRAmMtE,CAAA;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAGzD,CAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** The preview contract deliberately excludes production emission. */
|
|
2
|
+
export type PlugNotasEnvironment = 'sandbox' | 'homologation';
|
|
3
|
+
export type PlugNotasDocumentStatus = 'draft' | 'processing' | 'issued' | 'cancelled' | 'error';
|
|
4
|
+
export interface PlugNotasSetupState {
|
|
5
|
+
emitterCnpj: string;
|
|
6
|
+
environment: PlugNotasEnvironment;
|
|
7
|
+
certificateReady: boolean;
|
|
8
|
+
cscReady: boolean;
|
|
9
|
+
providerEmitterId?: string;
|
|
10
|
+
certificateExpiresAt?: string;
|
|
11
|
+
certificateFingerprint?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface PlugNotasDocumentResult {
|
|
14
|
+
status: PlugNotasDocumentStatus;
|
|
15
|
+
providerDocumentId?: string;
|
|
16
|
+
integrationId?: string;
|
|
17
|
+
number?: string;
|
|
18
|
+
series?: string;
|
|
19
|
+
accessKey?: string;
|
|
20
|
+
message?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface PlugNotasFiscalGateway {
|
|
23
|
+
issue(input: {
|
|
24
|
+
notaId: string;
|
|
25
|
+
idempotencyKey: string;
|
|
26
|
+
}): Promise<PlugNotasDocumentResult>;
|
|
27
|
+
refresh(input: {
|
|
28
|
+
notaId: string;
|
|
29
|
+
}): Promise<PlugNotasDocumentResult>;
|
|
30
|
+
cancel(input: {
|
|
31
|
+
notaId: string;
|
|
32
|
+
reason: string;
|
|
33
|
+
}): Promise<PlugNotasDocumentResult>;
|
|
34
|
+
artifact(input: {
|
|
35
|
+
notaId: string;
|
|
36
|
+
kind: 'xml' | 'pdf' | 'cancellation_xml';
|
|
37
|
+
}): Promise<{
|
|
38
|
+
url: string;
|
|
39
|
+
}>;
|
|
40
|
+
}
|
|
41
|
+
export interface PlugNotasConnectorClient {
|
|
42
|
+
testEmitter?(input: {
|
|
43
|
+
emitterCnpj: string;
|
|
44
|
+
environment: PlugNotasEnvironment;
|
|
45
|
+
}): Promise<{
|
|
46
|
+
ok: boolean;
|
|
47
|
+
message?: string;
|
|
48
|
+
}>;
|
|
49
|
+
disconnectEmitter?(): Promise<void>;
|
|
50
|
+
}
|
|
51
|
+
export interface PlugNotasFinancialProviderOptions {
|
|
52
|
+
base: import('@fayz-ai/plugin-financial').FinancialDataProvider;
|
|
53
|
+
gateway: PlugNotasFiscalGateway;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,cAAc,CAAA;AAC7D,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,YAAY,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,CAAA;AAE/F,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,oBAAoB,CAAA;IACjC,gBAAgB,EAAE,OAAO,CAAA;IACzB,QAAQ,EAAE,OAAO,CAAA;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAChC;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,uBAAuB,CAAA;IAC/B,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;IAC1F,OAAO,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;IACpE,MAAM,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;IACnF,QAAQ,CAAC,KAAK,EAAE;QACd,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,kBAAkB,CAAA;KACzC,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC7B;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,CAAC,CAAC,KAAK,EAAE;QAClB,WAAW,EAAE,MAAM,CAAA;QACnB,WAAW,EAAE,oBAAoB,CAAA;KAClC,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC9C,iBAAiB,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACpC;AAED,MAAM,WAAW,iCAAiC;IAChD,IAAI,EAAE,OAAO,2BAA2B,EAAE,qBAAqB,CAAA;IAC/D,OAAO,EAAE,sBAAsB,CAAA;CAChC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fayz-ai/plugin-fiscal-br",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "[preview] Brazilian fiscal addon for asynchronous NFC-e emission through PlugNotas",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
21
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@fayz-ai/core": "^0.19.1",
|
|
25
|
+
"@fayz-ai/plugin-financial": "^0.14.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/react": "^18.3.0",
|
|
29
|
+
"@types/react-dom": "^18.3.0",
|
|
30
|
+
"react": "^18.3.0",
|
|
31
|
+
"react-dom": "^18.3.0",
|
|
32
|
+
"tsup": "^8.2.0",
|
|
33
|
+
"typescript": "^5.5.0",
|
|
34
|
+
"vitest": "^4.1.5"
|
|
35
|
+
},
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"keywords": [
|
|
38
|
+
"fayz",
|
|
39
|
+
"fayz-plugin",
|
|
40
|
+
"fiscal",
|
|
41
|
+
"nfce",
|
|
42
|
+
"plugnotas"
|
|
43
|
+
],
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"fayz": {
|
|
48
|
+
"status": "preview",
|
|
49
|
+
"dependencies": [
|
|
50
|
+
"financial"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsup && tsc -b --force",
|
|
55
|
+
"dev": "tsup --watch",
|
|
56
|
+
"typecheck": "tsc -b tsconfig.test.json",
|
|
57
|
+
"clean": "rm -rf dist .tsbuildinfo",
|
|
58
|
+
"test": "vitest run"
|
|
59
|
+
}
|
|
60
|
+
}
|