@baruk/core 0.4.2 → 0.5.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.
Files changed (465) hide show
  1. package/.baruk-provenance.json +4 -4
  2. package/CHANGELOG.md +42 -0
  3. package/dist/audit/repository.d.ts +33 -1
  4. package/dist/audit/repository.d.ts.map +1 -1
  5. package/dist/audit/repository.js +41 -7
  6. package/dist/audit/repository.js.map +1 -1
  7. package/dist/auth/service.d.ts +21 -0
  8. package/dist/auth/service.d.ts.map +1 -1
  9. package/dist/auth/service.js +46 -1
  10. package/dist/auth/service.js.map +1 -1
  11. package/dist/billing/ar-repository.d.ts +41 -1
  12. package/dist/billing/ar-repository.d.ts.map +1 -1
  13. package/dist/billing/ar-repository.js +82 -6
  14. package/dist/billing/ar-repository.js.map +1 -1
  15. package/dist/billing/provider-account.d.ts +38 -0
  16. package/dist/billing/provider-account.d.ts.map +1 -1
  17. package/dist/billing/provider-account.js +58 -2
  18. package/dist/billing/provider-account.js.map +1 -1
  19. package/dist/billing/repository.d.ts +44 -0
  20. package/dist/billing/repository.d.ts.map +1 -1
  21. package/dist/billing/repository.js +49 -5
  22. package/dist/billing/repository.js.map +1 -1
  23. package/dist/cjs/audit/repository.js +41 -7
  24. package/dist/cjs/audit/repository.js.map +1 -1
  25. package/dist/cjs/auth/service.js +46 -1
  26. package/dist/cjs/auth/service.js.map +1 -1
  27. package/dist/cjs/billing/ar-repository.js +82 -6
  28. package/dist/cjs/billing/ar-repository.js.map +1 -1
  29. package/dist/cjs/billing/provider-account.js +60 -1
  30. package/dist/cjs/billing/provider-account.js.map +1 -1
  31. package/dist/cjs/billing/repository.js +51 -5
  32. package/dist/cjs/billing/repository.js.map +1 -1
  33. package/dist/cjs/clients/ibge.js +103 -0
  34. package/dist/cjs/clients/ibge.js.map +1 -0
  35. package/dist/cjs/clients/repository.js +186 -9
  36. package/dist/cjs/clients/repository.js.map +1 -1
  37. package/dist/cjs/collection/branding.js +190 -0
  38. package/dist/cjs/collection/branding.js.map +1 -1
  39. package/dist/cjs/collection/clearance-store.js +74 -0
  40. package/dist/cjs/collection/clearance-store.js.map +1 -0
  41. package/dist/cjs/collection/communication-runtime.js +65 -2
  42. package/dist/cjs/collection/communication-runtime.js.map +1 -1
  43. package/dist/cjs/collection/engine.js +20 -0
  44. package/dist/cjs/collection/engine.js.map +1 -1
  45. package/dist/cjs/collection/policy.js +29 -1
  46. package/dist/cjs/collection/policy.js.map +1 -1
  47. package/dist/cjs/communication/clearance.js +18 -0
  48. package/dist/cjs/communication/clearance.js.map +1 -0
  49. package/dist/cjs/communication/dry-run-scenario.js +5 -0
  50. package/dist/cjs/communication/dry-run-scenario.js.map +1 -1
  51. package/dist/cjs/communication/engine.js +12 -0
  52. package/dist/cjs/communication/engine.js.map +1 -1
  53. package/dist/cjs/communication/policy.js.map +1 -1
  54. package/dist/cjs/competence/business-days.js +155 -0
  55. package/dist/cjs/competence/business-days.js.map +1 -0
  56. package/dist/cjs/competence/catalog-validation.js +174 -0
  57. package/dist/cjs/competence/catalog-validation.js.map +1 -0
  58. package/dist/cjs/competence/obligation-preview.js +190 -0
  59. package/dist/cjs/competence/obligation-preview.js.map +1 -0
  60. package/dist/cjs/competence/repository.js +330 -17
  61. package/dist/cjs/competence/repository.js.map +1 -1
  62. package/dist/cjs/dashboard/pilot-panel.js +90 -0
  63. package/dist/cjs/dashboard/pilot-panel.js.map +1 -0
  64. package/dist/cjs/dashboard/repository.js +11 -1
  65. package/dist/cjs/dashboard/repository.js.map +1 -1
  66. package/dist/cjs/db/client.js +17 -11
  67. package/dist/cjs/db/client.js.map +1 -1
  68. package/dist/cjs/db/provision-e2e-identity.js +111 -0
  69. package/dist/cjs/db/provision-e2e-identity.js.map +1 -0
  70. package/dist/cjs/fiscal/applicability.js +164 -0
  71. package/dist/cjs/fiscal/applicability.js.map +1 -0
  72. package/dist/cjs/fiscal/conditions.js +198 -0
  73. package/dist/cjs/fiscal/conditions.js.map +1 -0
  74. package/dist/cjs/fiscal/contracts/nfse-adn-contract.js +390 -0
  75. package/dist/cjs/fiscal/contracts/nfse-adn-contract.js.map +1 -0
  76. package/dist/cjs/fiscal/contracts/nfse-adn-endpoint.js +108 -0
  77. package/dist/cjs/fiscal/contracts/nfse-adn-endpoint.js.map +1 -0
  78. package/dist/cjs/fiscal/contracts/nfse-adn-envelope.js +220 -0
  79. package/dist/cjs/fiscal/contracts/nfse-adn-envelope.js.map +1 -0
  80. package/dist/cjs/fiscal/coverage/model.js +127 -0
  81. package/dist/cjs/fiscal/coverage/model.js.map +1 -0
  82. package/dist/cjs/fiscal/coverage/requests.js +99 -0
  83. package/dist/cjs/fiscal/coverage/requests.js.map +1 -0
  84. package/dist/cjs/fiscal/credentials/material.js +168 -0
  85. package/dist/cjs/fiscal/credentials/material.js.map +1 -0
  86. package/dist/cjs/fiscal/credentials/readiness.js +163 -0
  87. package/dist/cjs/fiscal/credentials/readiness.js.map +1 -0
  88. package/dist/cjs/fiscal/eligibility.js +199 -0
  89. package/dist/cjs/fiscal/eligibility.js.map +1 -0
  90. package/dist/cjs/fiscal/ingestion/__fixtures__/nfse.js +128 -0
  91. package/dist/cjs/fiscal/ingestion/__fixtures__/nfse.js.map +1 -0
  92. package/dist/cjs/fiscal/ingestion/adn-transport.js +229 -0
  93. package/dist/cjs/fiscal/ingestion/adn-transport.js.map +1 -0
  94. package/dist/cjs/fiscal/ingestion/direction.js +36 -0
  95. package/dist/cjs/fiscal/ingestion/direction.js.map +1 -0
  96. package/dist/cjs/fiscal/ingestion/nfse-adn.js +228 -0
  97. package/dist/cjs/fiscal/ingestion/nfse-adn.js.map +1 -0
  98. package/dist/cjs/fiscal/ingestion/pipeline.js +704 -0
  99. package/dist/cjs/fiscal/ingestion/pipeline.js.map +1 -0
  100. package/dist/cjs/fiscal/ingestion/provider.js +51 -0
  101. package/dist/cjs/fiscal/ingestion/provider.js.map +1 -0
  102. package/dist/cjs/fiscal/ingestion/repository.js +132 -0
  103. package/dist/cjs/fiscal/ingestion/repository.js.map +1 -0
  104. package/dist/cjs/fiscal/ingestion/synthetic-provider.js +103 -0
  105. package/dist/cjs/fiscal/ingestion/synthetic-provider.js.map +1 -0
  106. package/dist/cjs/fiscal/ingestion/synthetic-transport-types.js +13 -0
  107. package/dist/cjs/fiscal/ingestion/synthetic-transport-types.js.map +1 -0
  108. package/dist/cjs/fiscal/ingestion/synthetic-transport.js +61 -0
  109. package/dist/cjs/fiscal/ingestion/synthetic-transport.js.map +1 -0
  110. package/dist/cjs/fiscal/ingestion/xml-reader.js +121 -0
  111. package/dist/cjs/fiscal/ingestion/xml-reader.js.map +1 -0
  112. package/dist/cjs/fiscal/repository.js +470 -0
  113. package/dist/cjs/fiscal/repository.js.map +1 -0
  114. package/dist/cjs/fiscal/sync/circuit.js +124 -0
  115. package/dist/cjs/fiscal/sync/circuit.js.map +1 -0
  116. package/dist/cjs/fiscal/sync/intervention.js +140 -0
  117. package/dist/cjs/fiscal/sync/intervention.js.map +1 -0
  118. package/dist/cjs/fiscal/sync/lease.js +146 -0
  119. package/dist/cjs/fiscal/sync/lease.js.map +1 -0
  120. package/dist/cjs/fiscal/sync/observability.js +244 -0
  121. package/dist/cjs/fiscal/sync/observability.js.map +1 -0
  122. package/dist/cjs/fiscal/sync/orchestrator.js +490 -0
  123. package/dist/cjs/fiscal/sync/orchestrator.js.map +1 -0
  124. package/dist/cjs/fiscal/sync/policy.js +143 -0
  125. package/dist/cjs/fiscal/sync/policy.js.map +1 -0
  126. package/dist/cjs/fiscal/sync/reprocess.js +241 -0
  127. package/dist/cjs/fiscal/sync/reprocess.js.map +1 -0
  128. package/dist/cjs/fiscal/sync/retry.js +183 -0
  129. package/dist/cjs/fiscal/sync/retry.js.map +1 -0
  130. package/dist/cjs/fiscal/sync/secret-boundary.js +123 -0
  131. package/dist/cjs/fiscal/sync/secret-boundary.js.map +1 -0
  132. package/dist/cjs/fiscal/transport/https.js +309 -0
  133. package/dist/cjs/fiscal/transport/https.js.map +1 -0
  134. package/dist/cjs/fiscal/transport/synthetic-tls.js +328 -0
  135. package/dist/cjs/fiscal/transport/synthetic-tls.js.map +1 -0
  136. package/dist/cjs/fiscal/transport/types.js +93 -0
  137. package/dist/cjs/fiscal/transport/types.js.map +1 -0
  138. package/dist/cjs/import/br-documents.js +85 -0
  139. package/dist/cjs/import/br-documents.js.map +1 -0
  140. package/dist/cjs/import/clients-import.js +347 -40
  141. package/dist/cjs/import/clients-import.js.map +1 -1
  142. package/dist/cjs/index.js +316 -11
  143. package/dist/cjs/index.js.map +1 -1
  144. package/dist/cjs/legal/documents.js +100 -15
  145. package/dist/cjs/legal/documents.js.map +1 -1
  146. package/dist/cjs/legal/index.js +3 -1
  147. package/dist/cjs/legal/index.js.map +1 -1
  148. package/dist/cjs/legal/types.js.map +1 -1
  149. package/dist/cjs/onboarding/persistence.js +4 -4
  150. package/dist/cjs/onboarding/persistence.js.map +1 -1
  151. package/dist/cjs/pilot/go-live-checklist.js +212 -0
  152. package/dist/cjs/pilot/go-live-checklist.js.map +1 -0
  153. package/dist/cjs/pilot/milestone.js +79 -0
  154. package/dist/cjs/pilot/milestone.js.map +1 -0
  155. package/dist/cjs/platform/capabilities.js +144 -0
  156. package/dist/cjs/platform/capabilities.js.map +1 -0
  157. package/dist/cjs/platform/job-contract.js +411 -0
  158. package/dist/cjs/platform/job-contract.js.map +1 -0
  159. package/dist/cjs/rbac/catalog.js +34 -0
  160. package/dist/cjs/rbac/catalog.js.map +1 -1
  161. package/dist/cjs/subscription-billing/index.js +2 -1
  162. package/dist/cjs/subscription-billing/index.js.map +1 -1
  163. package/dist/cjs/subscription-billing/service.js +153 -77
  164. package/dist/cjs/subscription-billing/service.js.map +1 -1
  165. package/dist/cjs/tenancy/features.js +131 -0
  166. package/dist/cjs/tenancy/features.js.map +1 -0
  167. package/dist/cjs/tenancy/settings.js +224 -0
  168. package/dist/cjs/tenancy/settings.js.map +1 -0
  169. package/dist/cjs/users/repository.js +24 -1
  170. package/dist/cjs/users/repository.js.map +1 -1
  171. package/dist/clients/ibge.d.ts +17 -0
  172. package/dist/clients/ibge.d.ts.map +1 -0
  173. package/dist/clients/ibge.js +98 -0
  174. package/dist/clients/ibge.js.map +1 -0
  175. package/dist/clients/repository.d.ts +154 -0
  176. package/dist/clients/repository.d.ts.map +1 -1
  177. package/dist/clients/repository.js +182 -9
  178. package/dist/clients/repository.js.map +1 -1
  179. package/dist/collection/branding.d.ts +65 -0
  180. package/dist/collection/branding.d.ts.map +1 -1
  181. package/dist/collection/branding.js +186 -0
  182. package/dist/collection/branding.js.map +1 -1
  183. package/dist/collection/clearance-store.d.ts +39 -0
  184. package/dist/collection/clearance-store.d.ts.map +1 -0
  185. package/dist/collection/clearance-store.js +69 -0
  186. package/dist/collection/clearance-store.js.map +1 -0
  187. package/dist/collection/communication-runtime.d.ts +37 -0
  188. package/dist/collection/communication-runtime.d.ts.map +1 -1
  189. package/dist/collection/communication-runtime.js +63 -1
  190. package/dist/collection/communication-runtime.js.map +1 -1
  191. package/dist/collection/engine.d.ts +23 -0
  192. package/dist/collection/engine.d.ts.map +1 -1
  193. package/dist/collection/engine.js +20 -0
  194. package/dist/collection/engine.js.map +1 -1
  195. package/dist/collection/policy.d.ts +25 -0
  196. package/dist/collection/policy.d.ts.map +1 -1
  197. package/dist/collection/policy.js +27 -0
  198. package/dist/collection/policy.js.map +1 -1
  199. package/dist/communication/clearance.d.ts +53 -0
  200. package/dist/communication/clearance.d.ts.map +1 -0
  201. package/dist/communication/clearance.js +15 -0
  202. package/dist/communication/clearance.js.map +1 -0
  203. package/dist/communication/dry-run-scenario.d.ts.map +1 -1
  204. package/dist/communication/dry-run-scenario.js +5 -0
  205. package/dist/communication/dry-run-scenario.js.map +1 -1
  206. package/dist/communication/engine.d.ts +10 -0
  207. package/dist/communication/engine.d.ts.map +1 -1
  208. package/dist/communication/engine.js +12 -0
  209. package/dist/communication/engine.js.map +1 -1
  210. package/dist/communication/policy.d.ts +16 -0
  211. package/dist/communication/policy.d.ts.map +1 -1
  212. package/dist/communication/policy.js.map +1 -1
  213. package/dist/competence/business-days.d.ts +51 -0
  214. package/dist/competence/business-days.d.ts.map +1 -0
  215. package/dist/competence/business-days.js +145 -0
  216. package/dist/competence/business-days.js.map +1 -0
  217. package/dist/competence/catalog-validation.d.ts +86 -0
  218. package/dist/competence/catalog-validation.d.ts.map +1 -0
  219. package/dist/competence/catalog-validation.js +168 -0
  220. package/dist/competence/catalog-validation.js.map +1 -0
  221. package/dist/competence/obligation-preview.d.ts +103 -0
  222. package/dist/competence/obligation-preview.d.ts.map +1 -0
  223. package/dist/competence/obligation-preview.js +184 -0
  224. package/dist/competence/obligation-preview.js.map +1 -0
  225. package/dist/competence/repository.d.ts +139 -1
  226. package/dist/competence/repository.d.ts.map +1 -1
  227. package/dist/competence/repository.js +325 -17
  228. package/dist/competence/repository.js.map +1 -1
  229. package/dist/dashboard/pilot-panel.d.ts +100 -0
  230. package/dist/dashboard/pilot-panel.d.ts.map +1 -0
  231. package/dist/dashboard/pilot-panel.js +87 -0
  232. package/dist/dashboard/pilot-panel.js.map +1 -0
  233. package/dist/dashboard/repository.d.ts.map +1 -1
  234. package/dist/dashboard/repository.js +11 -1
  235. package/dist/dashboard/repository.js.map +1 -1
  236. package/dist/db/client.d.ts +45 -0
  237. package/dist/db/client.d.ts.map +1 -1
  238. package/dist/db/client.js +16 -11
  239. package/dist/db/client.js.map +1 -1
  240. package/dist/db/migrate.d.ts +36 -1
  241. package/dist/db/migrate.d.ts.map +1 -1
  242. package/dist/db/migrate.js +199 -32
  243. package/dist/db/migrate.js.map +1 -1
  244. package/dist/db/provision-e2e-identity.d.ts +2 -0
  245. package/dist/db/provision-e2e-identity.d.ts.map +1 -0
  246. package/dist/db/provision-e2e-identity.js +109 -0
  247. package/dist/db/provision-e2e-identity.js.map +1 -0
  248. package/dist/fiscal/applicability.d.ts +73 -0
  249. package/dist/fiscal/applicability.d.ts.map +1 -0
  250. package/dist/fiscal/applicability.js +160 -0
  251. package/dist/fiscal/applicability.js.map +1 -0
  252. package/dist/fiscal/conditions.d.ts +99 -0
  253. package/dist/fiscal/conditions.d.ts.map +1 -0
  254. package/dist/fiscal/conditions.js +190 -0
  255. package/dist/fiscal/conditions.js.map +1 -0
  256. package/dist/fiscal/contracts/nfse-adn-contract.d.ts +315 -0
  257. package/dist/fiscal/contracts/nfse-adn-contract.d.ts.map +1 -0
  258. package/dist/fiscal/contracts/nfse-adn-contract.js +386 -0
  259. package/dist/fiscal/contracts/nfse-adn-contract.js.map +1 -0
  260. package/dist/fiscal/contracts/nfse-adn-endpoint.d.ts +13 -0
  261. package/dist/fiscal/contracts/nfse-adn-endpoint.d.ts.map +1 -0
  262. package/dist/fiscal/contracts/nfse-adn-endpoint.js +103 -0
  263. package/dist/fiscal/contracts/nfse-adn-endpoint.js.map +1 -0
  264. package/dist/fiscal/contracts/nfse-adn-envelope.d.ts +77 -0
  265. package/dist/fiscal/contracts/nfse-adn-envelope.d.ts.map +1 -0
  266. package/dist/fiscal/contracts/nfse-adn-envelope.js +215 -0
  267. package/dist/fiscal/contracts/nfse-adn-envelope.js.map +1 -0
  268. package/dist/fiscal/coverage/model.d.ts +86 -0
  269. package/dist/fiscal/coverage/model.d.ts.map +1 -0
  270. package/dist/fiscal/coverage/model.js +120 -0
  271. package/dist/fiscal/coverage/model.js.map +1 -0
  272. package/dist/fiscal/coverage/requests.d.ts +70 -0
  273. package/dist/fiscal/coverage/requests.d.ts.map +1 -0
  274. package/dist/fiscal/coverage/requests.js +95 -0
  275. package/dist/fiscal/coverage/requests.js.map +1 -0
  276. package/dist/fiscal/credentials/material.d.ts +81 -0
  277. package/dist/fiscal/credentials/material.d.ts.map +1 -0
  278. package/dist/fiscal/credentials/material.js +164 -0
  279. package/dist/fiscal/credentials/material.js.map +1 -0
  280. package/dist/fiscal/credentials/readiness.d.ts +92 -0
  281. package/dist/fiscal/credentials/readiness.d.ts.map +1 -0
  282. package/dist/fiscal/credentials/readiness.js +159 -0
  283. package/dist/fiscal/credentials/readiness.js.map +1 -0
  284. package/dist/fiscal/eligibility.d.ts +106 -0
  285. package/dist/fiscal/eligibility.d.ts.map +1 -0
  286. package/dist/fiscal/eligibility.js +194 -0
  287. package/dist/fiscal/eligibility.js.map +1 -0
  288. package/dist/fiscal/ingestion/__fixtures__/nfse.d.ts +57 -0
  289. package/dist/fiscal/ingestion/__fixtures__/nfse.d.ts.map +1 -0
  290. package/dist/fiscal/ingestion/__fixtures__/nfse.js +121 -0
  291. package/dist/fiscal/ingestion/__fixtures__/nfse.js.map +1 -0
  292. package/dist/fiscal/ingestion/adn-transport.d.ts +123 -0
  293. package/dist/fiscal/ingestion/adn-transport.d.ts.map +1 -0
  294. package/dist/fiscal/ingestion/adn-transport.js +220 -0
  295. package/dist/fiscal/ingestion/adn-transport.js.map +1 -0
  296. package/dist/fiscal/ingestion/direction.d.ts +60 -0
  297. package/dist/fiscal/ingestion/direction.d.ts.map +1 -0
  298. package/dist/fiscal/ingestion/direction.js +32 -0
  299. package/dist/fiscal/ingestion/direction.js.map +1 -0
  300. package/dist/fiscal/ingestion/nfse-adn.d.ts +91 -0
  301. package/dist/fiscal/ingestion/nfse-adn.d.ts.map +1 -0
  302. package/dist/fiscal/ingestion/nfse-adn.js +222 -0
  303. package/dist/fiscal/ingestion/nfse-adn.js.map +1 -0
  304. package/dist/fiscal/ingestion/pipeline.d.ts +168 -0
  305. package/dist/fiscal/ingestion/pipeline.d.ts.map +1 -0
  306. package/dist/fiscal/ingestion/pipeline.js +699 -0
  307. package/dist/fiscal/ingestion/pipeline.js.map +1 -0
  308. package/dist/fiscal/ingestion/provider.d.ts +206 -0
  309. package/dist/fiscal/ingestion/provider.d.ts.map +1 -0
  310. package/dist/fiscal/ingestion/provider.js +47 -0
  311. package/dist/fiscal/ingestion/provider.js.map +1 -0
  312. package/dist/fiscal/ingestion/repository.d.ts +82 -0
  313. package/dist/fiscal/ingestion/repository.d.ts.map +1 -0
  314. package/dist/fiscal/ingestion/repository.js +127 -0
  315. package/dist/fiscal/ingestion/repository.js.map +1 -0
  316. package/dist/fiscal/ingestion/synthetic-provider.d.ts +92 -0
  317. package/dist/fiscal/ingestion/synthetic-provider.d.ts.map +1 -0
  318. package/dist/fiscal/ingestion/synthetic-provider.js +99 -0
  319. package/dist/fiscal/ingestion/synthetic-provider.js.map +1 -0
  320. package/dist/fiscal/ingestion/synthetic-transport-types.d.ts +19 -0
  321. package/dist/fiscal/ingestion/synthetic-transport-types.d.ts.map +1 -0
  322. package/dist/fiscal/ingestion/synthetic-transport-types.js +9 -0
  323. package/dist/fiscal/ingestion/synthetic-transport-types.js.map +1 -0
  324. package/dist/fiscal/ingestion/synthetic-transport.d.ts +55 -0
  325. package/dist/fiscal/ingestion/synthetic-transport.d.ts.map +1 -0
  326. package/dist/fiscal/ingestion/synthetic-transport.js +57 -0
  327. package/dist/fiscal/ingestion/synthetic-transport.js.map +1 -0
  328. package/dist/fiscal/ingestion/xml-reader.d.ts +55 -0
  329. package/dist/fiscal/ingestion/xml-reader.d.ts.map +1 -0
  330. package/dist/fiscal/ingestion/xml-reader.js +112 -0
  331. package/dist/fiscal/ingestion/xml-reader.js.map +1 -0
  332. package/dist/fiscal/repository.d.ts +220 -0
  333. package/dist/fiscal/repository.d.ts.map +1 -0
  334. package/dist/fiscal/repository.js +449 -0
  335. package/dist/fiscal/repository.js.map +1 -0
  336. package/dist/fiscal/sync/circuit.d.ts +86 -0
  337. package/dist/fiscal/sync/circuit.d.ts.map +1 -0
  338. package/dist/fiscal/sync/circuit.js +118 -0
  339. package/dist/fiscal/sync/circuit.js.map +1 -0
  340. package/dist/fiscal/sync/intervention.d.ts +81 -0
  341. package/dist/fiscal/sync/intervention.d.ts.map +1 -0
  342. package/dist/fiscal/sync/intervention.js +135 -0
  343. package/dist/fiscal/sync/intervention.js.map +1 -0
  344. package/dist/fiscal/sync/lease.d.ts +118 -0
  345. package/dist/fiscal/sync/lease.d.ts.map +1 -0
  346. package/dist/fiscal/sync/lease.js +139 -0
  347. package/dist/fiscal/sync/lease.js.map +1 -0
  348. package/dist/fiscal/sync/observability.d.ts +148 -0
  349. package/dist/fiscal/sync/observability.d.ts.map +1 -0
  350. package/dist/fiscal/sync/observability.js +239 -0
  351. package/dist/fiscal/sync/observability.js.map +1 -0
  352. package/dist/fiscal/sync/orchestrator.d.ts +132 -0
  353. package/dist/fiscal/sync/orchestrator.d.ts.map +1 -0
  354. package/dist/fiscal/sync/orchestrator.js +487 -0
  355. package/dist/fiscal/sync/orchestrator.js.map +1 -0
  356. package/dist/fiscal/sync/policy.d.ts +87 -0
  357. package/dist/fiscal/sync/policy.d.ts.map +1 -0
  358. package/dist/fiscal/sync/policy.js +136 -0
  359. package/dist/fiscal/sync/policy.js.map +1 -0
  360. package/dist/fiscal/sync/reprocess.d.ts +76 -0
  361. package/dist/fiscal/sync/reprocess.d.ts.map +1 -0
  362. package/dist/fiscal/sync/reprocess.js +237 -0
  363. package/dist/fiscal/sync/reprocess.js.map +1 -0
  364. package/dist/fiscal/sync/retry.d.ts +82 -0
  365. package/dist/fiscal/sync/retry.d.ts.map +1 -0
  366. package/dist/fiscal/sync/retry.js +176 -0
  367. package/dist/fiscal/sync/retry.js.map +1 -0
  368. package/dist/fiscal/sync/secret-boundary.d.ts +169 -0
  369. package/dist/fiscal/sync/secret-boundary.d.ts.map +1 -0
  370. package/dist/fiscal/sync/secret-boundary.js +116 -0
  371. package/dist/fiscal/sync/secret-boundary.js.map +1 -0
  372. package/dist/fiscal/transport/https.d.ts +86 -0
  373. package/dist/fiscal/transport/https.d.ts.map +1 -0
  374. package/dist/fiscal/transport/https.js +303 -0
  375. package/dist/fiscal/transport/https.js.map +1 -0
  376. package/dist/fiscal/transport/synthetic-tls.d.ts +80 -0
  377. package/dist/fiscal/transport/synthetic-tls.d.ts.map +1 -0
  378. package/dist/fiscal/transport/synthetic-tls.js +323 -0
  379. package/dist/fiscal/transport/synthetic-tls.js.map +1 -0
  380. package/dist/fiscal/transport/types.d.ts +134 -0
  381. package/dist/fiscal/transport/types.d.ts.map +1 -0
  382. package/dist/fiscal/transport/types.js +88 -0
  383. package/dist/fiscal/transport/types.js.map +1 -0
  384. package/dist/import/br-documents.d.ts +26 -0
  385. package/dist/import/br-documents.d.ts.map +1 -0
  386. package/dist/import/br-documents.js +78 -0
  387. package/dist/import/br-documents.js.map +1 -0
  388. package/dist/import/clients-import.d.ts +122 -4
  389. package/dist/import/clients-import.d.ts.map +1 -1
  390. package/dist/import/clients-import.js +341 -41
  391. package/dist/import/clients-import.js.map +1 -1
  392. package/dist/index.d.ts +115 -11
  393. package/dist/index.d.ts.map +1 -1
  394. package/dist/index.js +100 -7
  395. package/dist/index.js.map +1 -1
  396. package/dist/legal/documents.d.ts +12 -1
  397. package/dist/legal/documents.d.ts.map +1 -1
  398. package/dist/legal/documents.js +98 -14
  399. package/dist/legal/documents.js.map +1 -1
  400. package/dist/legal/index.d.ts +1 -1
  401. package/dist/legal/index.d.ts.map +1 -1
  402. package/dist/legal/index.js +1 -1
  403. package/dist/legal/index.js.map +1 -1
  404. package/dist/legal/types.d.ts +37 -2
  405. package/dist/legal/types.d.ts.map +1 -1
  406. package/dist/legal/types.js.map +1 -1
  407. package/dist/onboarding/persistence.d.ts +10 -1
  408. package/dist/onboarding/persistence.d.ts.map +1 -1
  409. package/dist/onboarding/persistence.js +4 -4
  410. package/dist/onboarding/persistence.js.map +1 -1
  411. package/dist/pilot/go-live-checklist.d.ts +41 -0
  412. package/dist/pilot/go-live-checklist.d.ts.map +1 -0
  413. package/dist/pilot/go-live-checklist.js +209 -0
  414. package/dist/pilot/go-live-checklist.js.map +1 -0
  415. package/dist/pilot/milestone.d.ts +56 -0
  416. package/dist/pilot/milestone.d.ts.map +1 -0
  417. package/dist/pilot/milestone.js +74 -0
  418. package/dist/pilot/milestone.js.map +1 -0
  419. package/dist/platform/capabilities.d.ts +88 -0
  420. package/dist/platform/capabilities.d.ts.map +1 -0
  421. package/dist/platform/capabilities.js +140 -0
  422. package/dist/platform/capabilities.js.map +1 -0
  423. package/dist/platform/job-contract.d.ts +232 -0
  424. package/dist/platform/job-contract.d.ts.map +1 -0
  425. package/dist/platform/job-contract.js +403 -0
  426. package/dist/platform/job-contract.js.map +1 -0
  427. package/dist/rbac/catalog.d.ts.map +1 -1
  428. package/dist/rbac/catalog.js +34 -0
  429. package/dist/rbac/catalog.js.map +1 -1
  430. package/dist/subscription-billing/index.d.ts +6 -5
  431. package/dist/subscription-billing/index.d.ts.map +1 -1
  432. package/dist/subscription-billing/index.js +3 -3
  433. package/dist/subscription-billing/index.js.map +1 -1
  434. package/dist/subscription-billing/service.d.ts +21 -0
  435. package/dist/subscription-billing/service.d.ts.map +1 -1
  436. package/dist/subscription-billing/service.js +90 -15
  437. package/dist/subscription-billing/service.js.map +1 -1
  438. package/dist/tenancy/features.d.ts +69 -0
  439. package/dist/tenancy/features.d.ts.map +1 -0
  440. package/dist/tenancy/features.js +123 -0
  441. package/dist/tenancy/features.js.map +1 -0
  442. package/dist/tenancy/settings.d.ts +63 -0
  443. package/dist/tenancy/settings.d.ts.map +1 -0
  444. package/dist/tenancy/settings.js +218 -0
  445. package/dist/tenancy/settings.js.map +1 -0
  446. package/dist/users/repository.d.ts +16 -1
  447. package/dist/users/repository.d.ts.map +1 -1
  448. package/dist/users/repository.js +24 -1
  449. package/dist/users/repository.js.map +1 -1
  450. package/package.json +9 -2
  451. package/src/db/migrations/0045_role_write_scope.sql +122 -0
  452. package/src/db/migrations/0046_pilot_activation_model.sql +184 -0
  453. package/src/db/migrations/0047_recipient_clearance.sql +89 -0
  454. package/src/db/migrations/0048_item_type_note.sql +16 -0
  455. package/src/db/migrations/0049_national_fiscal_engine.sql +279 -0
  456. package/src/db/migrations/0050_fiscal_vocabulary_readonly.sql +29 -0
  457. package/src/db/migrations/0051_seed_rules_from_catalog.sql +72 -0
  458. package/src/db/migrations/0052_fiscal_rule_delete_scope.sql +57 -0
  459. package/src/db/migrations/0053_rule_validity_lower_bound.sql +44 -0
  460. package/src/db/migrations/0054_tenant_profile_and_rule_source.sql +89 -0
  461. package/src/db/migrations/0055_job_capability_contract.sql +300 -0
  462. package/src/db/migrations/0056_fiscal_document_ingestion.sql +337 -0
  463. package/src/db/migrations/0057_fiscal_pending_event_inbox.sql +228 -0
  464. package/src/db/migrations/0058_fiscal_operational_engine.sql +516 -0
  465. package/src/db/migrations/0059_fiscal_contract_version.sql +59 -0
@@ -0,0 +1,220 @@
1
+ import type { Tx } from '../db/client.js';
2
+ import type { FiscalProfile } from './conditions.js';
3
+ import type { ClientJurisdiction, FiscalRuleRef, RuleStatus } from './applicability.js';
4
+ /** Um atributo do vocabulário global. */
5
+ export interface FiscalAttributeDefinition {
6
+ key: string;
7
+ label: string;
8
+ description: string | null;
9
+ valueType: 'boolean' | 'text' | 'enum';
10
+ allowedValues: string[] | null;
11
+ }
12
+ export declare function listFiscalAttributes(tx: Tx): Promise<FiscalAttributeDefinition[]>;
13
+ export declare class UnknownFiscalAttribute extends Error {
14
+ constructor(key: string);
15
+ }
16
+ export declare class InvalidAttributeValue extends Error {
17
+ constructor(message: string);
18
+ }
19
+ /**
20
+ * Grava um atributo do perfil.
21
+ *
22
+ * Valida o valor CONTRA A DEFINIÇÃO antes de gravar: booleano recebe booleano,
23
+ * enum recebe um dos valores declarados. Sem isso, `activity_segment` aceitaria
24
+ * "industria " com espaço e a regra que compara com "industria" nunca casaria —
25
+ * e ninguém saberia por quê, porque o dado *parece* certo na tela.
26
+ */
27
+ export declare function setClientFiscalAttribute(tx: Tx, input: {
28
+ clientId: string;
29
+ attributeKey: string;
30
+ value: string | boolean;
31
+ source?: string | null;
32
+ actorId?: string | null;
33
+ }): Promise<void>;
34
+ /**
35
+ * Remove um atributo — devolvendo-o ao estado DESCONHECIDO.
36
+ *
37
+ * Existe porque "não sei mais" é um estado legítimo e diferente de `false`.
38
+ * Sem esta operação, corrigir um dado errado exigiria gravar um valor que
39
+ * ninguém confirmou.
40
+ */
41
+ export declare function clearClientFiscalAttribute(tx: Tx, input: {
42
+ clientId: string;
43
+ attributeKey: string;
44
+ }): Promise<void>;
45
+ /**
46
+ * O perfil como o motor o enxerga.
47
+ *
48
+ * Atributo ausente simplesmente não aparece no objeto — e é assim que
49
+ * `evaluate` o distingue de `false`.
50
+ */
51
+ export declare function loadFiscalProfile(tx: Tx, clientId: string): Promise<FiscalProfile>;
52
+ export declare function loadClientJurisdiction(tx: Tx, clientId: string): Promise<ClientJurisdiction>;
53
+ /**
54
+ * As regras candidatas para um tipo de item numa competência.
55
+ *
56
+ * **Pré-filtra por jurisdição e vigência no banco**, antes de qualquer
57
+ * avaliação de condição. Avaliar a AST de todas as regras do país para cada
58
+ * cliente seria o desenho ingênuo que a premissa pede para evitar; aqui o
59
+ * índice `fiscal_rule_lookup_idx` reduz o conjunto a um punhado antes de o
60
+ * motor tocar nele.
61
+ *
62
+ * A regra do ESCRITÓRIO tem precedência sobre a global na mesma jurisdição —
63
+ * `DISTINCT ON` com `tenant_id NULLS LAST`, o mesmo padrão de
64
+ * `recurring_item_type`.
65
+ */
66
+ export declare function candidateRules(tx: Tx, input: {
67
+ itemTypeId: string;
68
+ jurisdiction: ClientJurisdiction;
69
+ referenceDate: string;
70
+ }): Promise<FiscalRuleRef[]>;
71
+ /**
72
+ * A regra mais específica que alcança o cliente.
73
+ *
74
+ * Municipal vence estadual, que vence federal. Um município que legisla sobre
75
+ * a obrigação está mais perto do fato que a União.
76
+ */
77
+ export declare function resolveRule(tx: Tx, input: {
78
+ itemTypeId: string;
79
+ jurisdiction: ClientJurisdiction;
80
+ referenceDate: string;
81
+ }): Promise<FiscalRuleRef | null>;
82
+ export interface CreateRuleInput {
83
+ itemTypeId: string;
84
+ jurisdictionScope: 'federal' | 'state' | 'municipal';
85
+ jurisdictionUf?: string | null;
86
+ jurisdictionCityIbge?: string | null;
87
+ validFrom: string;
88
+ validUntil?: string | null;
89
+ status?: RuleStatus;
90
+ conditions?: unknown;
91
+ dueRule?: Record<string, unknown> | null;
92
+ sourceReference?: string | null;
93
+ note?: string | null;
94
+ /** `null` cria regra GLOBAL — só o caminho de provisionamento consegue. */
95
+ tenantId?: string | null;
96
+ version?: number;
97
+ /**
98
+ * Quem conferiu. **Obrigatório quando `status` é `validated`.**
99
+ *
100
+ * Junto no INSERT, e não num UPDATE depois: o CHECK do banco recusa uma
101
+ * regra validada sem autor, e com razão — "está conferida" sem "por quem"
102
+ * é afirmação que ninguém assina. Exigir aqui move a recusa para a chamada,
103
+ * onde há contexto para corrigi-la.
104
+ */
105
+ validatedBy?: string | null;
106
+ }
107
+ /**
108
+ * Cria uma regra.
109
+ *
110
+ * A condição é validada AQUI, na escrita. Gravar uma AST malformada seria
111
+ * empurrar o erro para a madrugada da geração, onde a única saída seria não
112
+ * gerar sem explicar.
113
+ */
114
+ export declare function createFiscalRule(tx: Tx, input: CreateRuleInput): Promise<FiscalRuleRef>;
115
+ /**
116
+ * Publica uma nova versão, encerrando a anterior.
117
+ *
118
+ * **Não altera a versão antiga.** Ela recebe `valid_until` e continua lá,
119
+ * inteira: é ela que explica as obrigações já geradas. Editar a regra vigente
120
+ * em vez de versioná-la é como a mudança de amanhã reescreve o vencimento de
121
+ * ontem — e ninguém consegue mais dizer por que aquela data foi aquela.
122
+ */
123
+ export declare function supersedeFiscalRule(tx: Tx, input: {
124
+ currentRuleId: string;
125
+ validFrom: string;
126
+ changes: Partial<CreateRuleInput>;
127
+ }): Promise<{
128
+ previous: FiscalRuleRef;
129
+ next: FiscalRuleRef;
130
+ }>;
131
+ export declare function getFiscalRule(tx: Tx, id: string): Promise<FiscalRuleRef | null>;
132
+ /** Prazo interno do escritório, ao lado do legal. */
133
+ export interface TenantRulePolicy {
134
+ itemTypeId: string;
135
+ internalLeadDays: number | null;
136
+ enabled: boolean;
137
+ note: string | null;
138
+ }
139
+ export declare function setTenantRulePolicy(tx: Tx, input: {
140
+ itemTypeId: string;
141
+ internalLeadDays?: number | null;
142
+ enabled?: boolean;
143
+ note?: string | null;
144
+ actorId?: string | null;
145
+ }): Promise<void>;
146
+ export declare function listTenantRulePolicies(tx: Tx): Promise<TenantRulePolicy[]>;
147
+ export interface GovernanceRule {
148
+ id: string;
149
+ itemTypeId: string;
150
+ itemTypeKey: string;
151
+ itemTypeLabel: string;
152
+ sphere: string;
153
+ origin: 'global' | 'tenant';
154
+ jurisdiction: {
155
+ scope: string;
156
+ uf: string | null;
157
+ cityIbge: string | null;
158
+ };
159
+ version: number;
160
+ validFrom: string;
161
+ validUntil: string | null;
162
+ status: string;
163
+ sourceReference: string | null;
164
+ sourceUrl: string | null;
165
+ validatedAt: string | null;
166
+ validatedByName: string | null;
167
+ note: string | null;
168
+ /** A tela só oferece ação no que o escritório pode de fato alterar. */
169
+ editable: boolean;
170
+ }
171
+ export interface GovernanceSummary {
172
+ total: number;
173
+ byStatus: Record<string, number>;
174
+ withSource: number;
175
+ withoutSource: number;
176
+ /** Pendentes que já têm fonte anexada — a fila realmente pronta para revisão. */
177
+ readyForHumanReview: number;
178
+ }
179
+ /**
180
+ * A fila inteira: global e do escritório, com a procedência de cada linha.
181
+ *
182
+ * Sem filtro de vigência nem de jurisdição, ao contrário de `candidateRules` —
183
+ * são perguntas diferentes. Aquela responde "qual regra vale para este cliente
184
+ * hoje"; esta responde "o que existe e o que ainda não foi conferido", e uma
185
+ * regra vencida ou de outra UF continua sendo trabalho de governança.
186
+ */
187
+ export declare function listGovernanceRules(tx: Tx): Promise<GovernanceRule[]>;
188
+ export declare function summarizeGovernance(rules: readonly GovernanceRule[]): GovernanceSummary;
189
+ /**
190
+ * Registra a fonte e a observação de uma regra DO ESCRITÓRIO.
191
+ *
192
+ * Separado de validar de propósito: anexar evidência é preparação, e quem
193
+ * prepara não carimba. Não toca em `status`.
194
+ */
195
+ export declare function annotateFiscalRule(tx: Tx, input: {
196
+ id: string;
197
+ sourceUrl?: string | null;
198
+ sourceReference?: string | null;
199
+ note?: string | null;
200
+ }): Promise<void>;
201
+ /**
202
+ * O carimbo humano de conferência.
203
+ *
204
+ * Três guardas, e nenhum é redundante:
205
+ *
206
+ * 1. **Só regra do escritório.** A global é do produto; conferi-la para todo o
207
+ * Brasil não é decisão de um tenant.
208
+ * 2. **`validatedBy` obrigatório e vindo da SESSÃO**, nunca do corpo. Uma regra
209
+ * validada precisa responder "quem conferiu" com um nome que a pessoa não
210
+ * escolheu para si.
211
+ * 3. **Fonte obrigatória.** Validar sem apontar a norma é registrar uma opinião
212
+ * com aparência de conferência — e é exatamente o que a trilha não deve
213
+ * permitir que se pareça com evidência depois.
214
+ */
215
+ export declare function validateFiscalRule(tx: Tx, input: {
216
+ id: string;
217
+ validatedBy: string;
218
+ note?: string | null;
219
+ }): Promise<void>;
220
+ //# sourceMappingURL=repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/fiscal/repository.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAE1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAExF,yCAAyC;AACzC,MAAM,WAAW,yBAAyB;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;IACvC,aAAa,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAChC;AAED,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAoBvF;AAED,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,GAAG,EAAE,MAAM;CAIxB;AAED,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAC5C,EAAE,EAAE,EAAE,EACN,KAAK,EAAE;IACL,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,GACA,OAAO,CAAC,IAAI,CAAC,CA2Cf;AAED;;;;;;GAMG;AACH,wBAAsB,0BAA0B,CAC9C,EAAE,EAAE,EAAE,EACN,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAChD,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAYxF;AAED,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,CAAC,CAK7B;AA2CD;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,EAAE,EACN,KAAK,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,kBAAkB,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GACrF,OAAO,CAAC,aAAa,EAAE,CAAC,CAqB1B;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,EAAE,EACN,KAAK,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,kBAAkB,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GACrF,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAO/B;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,SAAS,GAAG,OAAO,GAAG,WAAW,CAAC;IACrD,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,aAAa,CAAC,CAyD7F;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,EAAE,EACN,KAAK,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,CAAA;CAAE,GACrF,OAAO,CAAC;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC,CAkC3D;AAED,wBAAsB,aAAa,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAKrF;AAED,qDAAqD;AACrD,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,EAAE,EACN,KAAK,EAAE;IACL,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,GACA,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,wBAAsB,sBAAsB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAiBhF;AAUD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,uEAAuE;IACvE,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAuBD;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAwC3E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,cAAc,EAAE,GAAG,iBAAiB,CAqBvF;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,EAAE,EACN,KAAK,EAAE;IACL,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,GACA,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,EAAE,EACN,KAAK,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC/D,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
@@ -0,0 +1,449 @@
1
+ import { uuidv7, ValidationError } from '@baruk/shared';
2
+ import { parseCondition } from './conditions.js';
3
+ export async function listFiscalAttributes(tx) {
4
+ const rows = await tx `
5
+ SELECT key, label, description, value_type, allowed_values
6
+ FROM fiscal_attribute_definition ORDER BY key
7
+ `;
8
+ return rows.map((r) => ({
9
+ key: r.key,
10
+ label: r.label,
11
+ description: r.description,
12
+ valueType: r.value_type,
13
+ allowedValues: Array.isArray(r.allowed_values) ? r.allowed_values : null,
14
+ }));
15
+ }
16
+ export class UnknownFiscalAttribute extends Error {
17
+ constructor(key) {
18
+ super(`Atributo fiscal desconhecido: ${key}`);
19
+ this.name = 'UnknownFiscalAttribute';
20
+ }
21
+ }
22
+ export class InvalidAttributeValue extends Error {
23
+ constructor(message) {
24
+ super(message);
25
+ this.name = 'InvalidAttributeValue';
26
+ }
27
+ }
28
+ /**
29
+ * Grava um atributo do perfil.
30
+ *
31
+ * Valida o valor CONTRA A DEFINIÇÃO antes de gravar: booleano recebe booleano,
32
+ * enum recebe um dos valores declarados. Sem isso, `activity_segment` aceitaria
33
+ * "industria " com espaço e a regra que compara com "industria" nunca casaria —
34
+ * e ninguém saberia por quê, porque o dado *parece* certo na tela.
35
+ */
36
+ export async function setClientFiscalAttribute(tx, input) {
37
+ const [def] = await tx `
38
+ SELECT value_type, allowed_values FROM fiscal_attribute_definition WHERE key = ${input.attributeKey}
39
+ `;
40
+ if (!def)
41
+ throw new UnknownFiscalAttribute(input.attributeKey);
42
+ let vBool = null;
43
+ let vText = null;
44
+ if (def.value_type === 'boolean') {
45
+ if (typeof input.value !== 'boolean') {
46
+ throw new InvalidAttributeValue(`"${input.attributeKey}" espera verdadeiro ou falso.`);
47
+ }
48
+ vBool = input.value;
49
+ }
50
+ else {
51
+ if (typeof input.value !== 'string' || input.value.trim() === '') {
52
+ throw new InvalidAttributeValue(`"${input.attributeKey}" espera texto não vazio.`);
53
+ }
54
+ vText = input.value.trim();
55
+ if (def.value_type === 'enum') {
56
+ const permitidos = Array.isArray(def.allowed_values) ? def.allowed_values : [];
57
+ if (!permitidos.includes(vText)) {
58
+ throw new InvalidAttributeValue(`"${vText}" não é aceito em "${input.attributeKey}". Valores: ${permitidos.join(', ')}.`);
59
+ }
60
+ }
61
+ }
62
+ await tx `
63
+ INSERT INTO client_fiscal_attribute
64
+ (id, tenant_id, client_id, attribute_key, value_bool, value_text, source, updated_by)
65
+ VALUES (
66
+ ${uuidv7()}, current_setting('app.current_tenant')::uuid, ${input.clientId},
67
+ ${input.attributeKey}, ${vBool}, ${vText}, ${input.source ?? null}, ${input.actorId ?? null}
68
+ )
69
+ ON CONFLICT (tenant_id, client_id, attribute_key) DO UPDATE SET
70
+ value_bool = EXCLUDED.value_bool,
71
+ value_text = EXCLUDED.value_text,
72
+ source = EXCLUDED.source,
73
+ updated_by = EXCLUDED.updated_by,
74
+ updated_at = now()
75
+ `;
76
+ }
77
+ /**
78
+ * Remove um atributo — devolvendo-o ao estado DESCONHECIDO.
79
+ *
80
+ * Existe porque "não sei mais" é um estado legítimo e diferente de `false`.
81
+ * Sem esta operação, corrigir um dado errado exigiria gravar um valor que
82
+ * ninguém confirmou.
83
+ */
84
+ export async function clearClientFiscalAttribute(tx, input) {
85
+ await tx `
86
+ DELETE FROM client_fiscal_attribute
87
+ WHERE client_id = ${input.clientId} AND attribute_key = ${input.attributeKey}
88
+ `;
89
+ }
90
+ /**
91
+ * O perfil como o motor o enxerga.
92
+ *
93
+ * Atributo ausente simplesmente não aparece no objeto — e é assim que
94
+ * `evaluate` o distingue de `false`.
95
+ */
96
+ export async function loadFiscalProfile(tx, clientId) {
97
+ const rows = await tx `
98
+ SELECT attribute_key, value_bool, value_text
99
+ FROM client_fiscal_attribute WHERE client_id = ${clientId}
100
+ `;
101
+ const perfil = {};
102
+ for (const r of rows) {
103
+ perfil[r.attribute_key] = r.value_bool !== null ? r.value_bool : r.value_text;
104
+ }
105
+ return perfil;
106
+ }
107
+ export async function loadClientJurisdiction(tx, clientId) {
108
+ const [r] = await tx `
109
+ SELECT state_uf, municipality_ibge_code FROM client WHERE id = ${clientId} AND deleted_at IS NULL
110
+ `;
111
+ return { uf: r?.state_uf ?? null, cityIbge: r?.municipality_ibge_code ?? null };
112
+ }
113
+ const iso = (d) => d.toISOString().slice(0, 10);
114
+ const mapRule = (r) => ({
115
+ id: r.id,
116
+ tenantId: r.tenant_id,
117
+ itemTypeId: r.item_type_id,
118
+ version: r.version,
119
+ jurisdiction: {
120
+ scope: r.jurisdiction_scope,
121
+ uf: r.jurisdiction_uf,
122
+ cityIbge: r.jurisdiction_city_ibge,
123
+ },
124
+ validFrom: iso(r.valid_from),
125
+ validUntil: r.valid_until ? iso(r.valid_until) : null,
126
+ status: r.status,
127
+ conditions: r.conditions ?? { op: 'always' },
128
+ dueRule: r.due_rule,
129
+ sourceReference: r.source_reference,
130
+ });
131
+ const RULE_COLS = `
132
+ id, tenant_id, item_type_id, version, jurisdiction_scope, jurisdiction_uf,
133
+ jurisdiction_city_ibge, valid_from, valid_until, status, conditions, due_rule, source_reference
134
+ `;
135
+ /**
136
+ * As regras candidatas para um tipo de item numa competência.
137
+ *
138
+ * **Pré-filtra por jurisdição e vigência no banco**, antes de qualquer
139
+ * avaliação de condição. Avaliar a AST de todas as regras do país para cada
140
+ * cliente seria o desenho ingênuo que a premissa pede para evitar; aqui o
141
+ * índice `fiscal_rule_lookup_idx` reduz o conjunto a um punhado antes de o
142
+ * motor tocar nele.
143
+ *
144
+ * A regra do ESCRITÓRIO tem precedência sobre a global na mesma jurisdição —
145
+ * `DISTINCT ON` com `tenant_id NULLS LAST`, o mesmo padrão de
146
+ * `recurring_item_type`.
147
+ */
148
+ export async function candidateRules(tx, input) {
149
+ const rows = await tx `
150
+ SELECT DISTINCT ON (jurisdiction_scope, coalesce(jurisdiction_uf,'-'), coalesce(jurisdiction_city_ibge,'-'))
151
+ ${tx.unsafe(RULE_COLS)}
152
+ FROM fiscal_rule
153
+ WHERE deleted_at IS NULL
154
+ AND item_type_id = ${input.itemTypeId}
155
+ AND valid_from <= ${input.referenceDate}::date
156
+ AND (valid_until IS NULL OR valid_until >= ${input.referenceDate}::date)
157
+ AND (
158
+ jurisdiction_scope = 'federal'
159
+ OR (jurisdiction_scope = 'state'
160
+ AND jurisdiction_uf = ${input.jurisdiction.uf})
161
+ OR (jurisdiction_scope = 'municipal'
162
+ AND jurisdiction_uf = ${input.jurisdiction.uf}
163
+ AND jurisdiction_city_ibge = ${input.jurisdiction.cityIbge})
164
+ )
165
+ ORDER BY jurisdiction_scope, coalesce(jurisdiction_uf,'-'), coalesce(jurisdiction_city_ibge,'-'),
166
+ tenant_id NULLS LAST, version DESC
167
+ `;
168
+ return rows.map(mapRule);
169
+ }
170
+ /**
171
+ * A regra mais específica que alcança o cliente.
172
+ *
173
+ * Municipal vence estadual, que vence federal. Um município que legisla sobre
174
+ * a obrigação está mais perto do fato que a União.
175
+ */
176
+ export async function resolveRule(tx, input) {
177
+ const candidatas = await candidateRules(tx, input);
178
+ const ordem = { municipal: 0, state: 1, federal: 2 };
179
+ return ([...candidatas].sort((a, b) => ordem[a.jurisdiction.scope] - ordem[b.jurisdiction.scope])[0] ??
180
+ null);
181
+ }
182
+ /**
183
+ * Cria uma regra.
184
+ *
185
+ * A condição é validada AQUI, na escrita. Gravar uma AST malformada seria
186
+ * empurrar o erro para a madrugada da geração, onde a única saída seria não
187
+ * gerar sem explicar.
188
+ */
189
+ export async function createFiscalRule(tx, input) {
190
+ parseCondition(input.conditions ?? { op: 'always' });
191
+ const status = input.status ?? 'pending_validation';
192
+ if (status === 'validated' && !input.validatedBy) {
193
+ throw new Error('Uma regra validada precisa de quem a validou.');
194
+ }
195
+ const validadaEm = status === 'validated' ? new Date() : null;
196
+ const validadaPor = status === 'validated' ? input.validatedBy : null;
197
+ // Três destinos possíveis, e cada um precisa de SQL diferente:
198
+ //
199
+ // `tenantId: null` → regra GLOBAL. Só o provisionamento consegue: a
200
+ // policy recusa `tenant_id NULL` vindo de sessão
201
+ // com tenant, e é essa recusa que impede um
202
+ // escritório de forjar regra nacional.
203
+ // `tenantId: '<uuid>'` → tenant explícito (provisionamento).
204
+ // ausente → o tenant da sessão, lido da GUC.
205
+ //
206
+ // Resolver isso com um único parâmetro misturaria valor e fragmento SQL —
207
+ // que compila e não faz o que parece.
208
+ const global = input.tenantId === null;
209
+ const explicito = typeof input.tenantId === 'string' ? input.tenantId : null;
210
+ const cond = tx.json((input.conditions ?? { op: 'always' }));
211
+ const due = input.dueRule ? tx.json(input.dueRule) : null;
212
+ const rows = global
213
+ ? await tx `
214
+ INSERT INTO fiscal_rule (
215
+ id, tenant_id, item_type_id, jurisdiction_scope, jurisdiction_uf, jurisdiction_city_ibge,
216
+ version, valid_from, valid_until, status, conditions, due_rule, source_reference, note,
217
+ validated_by, validated_at
218
+ ) VALUES (
219
+ ${uuidv7()}, NULL, ${input.itemTypeId}, ${input.jurisdictionScope},
220
+ ${input.jurisdictionUf ?? null}, ${input.jurisdictionCityIbge ?? null},
221
+ ${input.version ?? 1}, ${input.validFrom}, ${input.validUntil ?? null},
222
+ ${status}, ${cond}, ${due},
223
+ ${input.sourceReference ?? null}, ${input.note ?? null}, ${validadaPor}, ${validadaEm}
224
+ )
225
+ RETURNING ${tx.unsafe(RULE_COLS)}
226
+ `
227
+ : await tx `
228
+ INSERT INTO fiscal_rule (
229
+ id, tenant_id, item_type_id, jurisdiction_scope, jurisdiction_uf, jurisdiction_city_ibge,
230
+ version, valid_from, valid_until, status, conditions, due_rule, source_reference, note,
231
+ validated_by, validated_at
232
+ ) VALUES (
233
+ ${uuidv7()},
234
+ ${explicito ?? tx.unsafe("current_setting('app.current_tenant')::uuid")},
235
+ ${input.itemTypeId}, ${input.jurisdictionScope},
236
+ ${input.jurisdictionUf ?? null}, ${input.jurisdictionCityIbge ?? null},
237
+ ${input.version ?? 1}, ${input.validFrom}, ${input.validUntil ?? null},
238
+ ${status}, ${cond}, ${due},
239
+ ${input.sourceReference ?? null}, ${input.note ?? null}, ${validadaPor}, ${validadaEm}
240
+ )
241
+ RETURNING ${tx.unsafe(RULE_COLS)}
242
+ `;
243
+ return mapRule(rows[0]);
244
+ }
245
+ /**
246
+ * Publica uma nova versão, encerrando a anterior.
247
+ *
248
+ * **Não altera a versão antiga.** Ela recebe `valid_until` e continua lá,
249
+ * inteira: é ela que explica as obrigações já geradas. Editar a regra vigente
250
+ * em vez de versioná-la é como a mudança de amanhã reescreve o vencimento de
251
+ * ontem — e ninguém consegue mais dizer por que aquela data foi aquela.
252
+ */
253
+ export async function supersedeFiscalRule(tx, input) {
254
+ const [atual] = await tx `
255
+ SELECT ${tx.unsafe(RULE_COLS)} FROM fiscal_rule
256
+ WHERE id = ${input.currentRuleId} AND deleted_at IS NULL
257
+ `;
258
+ if (!atual)
259
+ throw new Error('Regra não encontrada.');
260
+ if (input.validFrom <= iso(atual.valid_from)) {
261
+ throw new Error('A nova versão precisa começar depois do início da anterior.');
262
+ }
263
+ // O dia anterior ao início da nova: sem vão e sem sobreposição.
264
+ const fim = new Date(`${input.validFrom}T00:00:00Z`);
265
+ fim.setUTCDate(fim.getUTCDate() - 1);
266
+ await tx `
267
+ UPDATE fiscal_rule SET valid_until = ${iso(fim)}, updated_at = now()
268
+ WHERE id = ${input.currentRuleId}
269
+ `;
270
+ const proxima = await createFiscalRule(tx, {
271
+ itemTypeId: atual.item_type_id,
272
+ jurisdictionScope: atual.jurisdiction_scope,
273
+ jurisdictionUf: atual.jurisdiction_uf,
274
+ jurisdictionCityIbge: atual.jurisdiction_city_ibge,
275
+ validFrom: input.validFrom,
276
+ version: atual.version + 1,
277
+ tenantId: atual.tenant_id,
278
+ conditions: input.changes.conditions ?? atual.conditions,
279
+ dueRule: input.changes.dueRule ?? atual.due_rule,
280
+ status: input.changes.status ?? 'pending_validation',
281
+ sourceReference: input.changes.sourceReference ?? atual.source_reference,
282
+ ...(input.changes.note !== undefined ? { note: input.changes.note } : {}),
283
+ });
284
+ return { previous: mapRule({ ...atual, valid_until: fim }), next: proxima };
285
+ }
286
+ export async function getFiscalRule(tx, id) {
287
+ const [r] = await tx `
288
+ SELECT ${tx.unsafe(RULE_COLS)} FROM fiscal_rule WHERE id = ${id} AND deleted_at IS NULL
289
+ `;
290
+ return r ? mapRule(r) : null;
291
+ }
292
+ export async function setTenantRulePolicy(tx, input) {
293
+ await tx `
294
+ INSERT INTO tenant_rule_policy
295
+ (id, tenant_id, item_type_id, internal_lead_days, enabled, note, updated_by)
296
+ VALUES (
297
+ ${uuidv7()}, current_setting('app.current_tenant')::uuid, ${input.itemTypeId},
298
+ ${input.internalLeadDays ?? null}, ${input.enabled ?? true}, ${input.note ?? null},
299
+ ${input.actorId ?? null}
300
+ )
301
+ ON CONFLICT (tenant_id, item_type_id) DO UPDATE SET
302
+ internal_lead_days = EXCLUDED.internal_lead_days,
303
+ enabled = EXCLUDED.enabled,
304
+ note = EXCLUDED.note,
305
+ updated_by = EXCLUDED.updated_by,
306
+ updated_at = now()
307
+ `;
308
+ }
309
+ export async function listTenantRulePolicies(tx) {
310
+ const rows = await tx `
311
+ SELECT item_type_id, internal_lead_days, enabled, note FROM tenant_rule_policy
312
+ `;
313
+ return rows.map((r) => ({
314
+ itemTypeId: r.item_type_id,
315
+ internalLeadDays: r.internal_lead_days,
316
+ enabled: r.enabled,
317
+ note: r.note,
318
+ }));
319
+ }
320
+ /**
321
+ * A fila inteira: global e do escritório, com a procedência de cada linha.
322
+ *
323
+ * Sem filtro de vigência nem de jurisdição, ao contrário de `candidateRules` —
324
+ * são perguntas diferentes. Aquela responde "qual regra vale para este cliente
325
+ * hoje"; esta responde "o que existe e o que ainda não foi conferido", e uma
326
+ * regra vencida ou de outra UF continua sendo trabalho de governança.
327
+ */
328
+ export async function listGovernanceRules(tx) {
329
+ const rows = await tx `
330
+ SELECT r.id, r.tenant_id, r.item_type_id,
331
+ t.key AS item_key, t.label AS item_label, t.sphere,
332
+ r.jurisdiction_scope, r.jurisdiction_uf, r.jurisdiction_city_ibge,
333
+ r.version, r.valid_from, r.valid_until, r.status,
334
+ r.source_reference, r.source_url, r.validated_at,
335
+ u.full_name AS validated_by_name, r.note
336
+ FROM fiscal_rule r
337
+ JOIN recurring_item_type t ON t.id = r.item_type_id
338
+ LEFT JOIN "user" u ON u.id = r.validated_by
339
+ WHERE r.deleted_at IS NULL AND t.deleted_at IS NULL
340
+ ORDER BY (r.status <> 'validated') DESC, t.sphere, t.label, r.version DESC
341
+ `;
342
+ return rows.map((r) => ({
343
+ id: r.id,
344
+ itemTypeId: r.item_type_id,
345
+ itemTypeKey: r.item_key,
346
+ itemTypeLabel: r.item_label,
347
+ sphere: r.sphere,
348
+ origin: r.tenant_id === null ? 'global' : 'tenant',
349
+ jurisdiction: {
350
+ scope: r.jurisdiction_scope,
351
+ uf: r.jurisdiction_uf,
352
+ cityIbge: r.jurisdiction_city_ibge,
353
+ },
354
+ version: r.version,
355
+ validFrom: iso(r.valid_from),
356
+ validUntil: r.valid_until ? iso(r.valid_until) : null,
357
+ status: r.status,
358
+ sourceReference: r.source_reference,
359
+ sourceUrl: r.source_url,
360
+ validatedAt: r.validated_at ? r.validated_at.toISOString() : null,
361
+ validatedByName: r.validated_by_name,
362
+ note: r.note,
363
+ // Regra global é do PRODUTO. O escritório lê, cria a própria em cima, e não
364
+ // reescreve a de todo mundo — a RLS já recusaria, e oferecer o botão seria
365
+ // prometer uma ação que o banco nega.
366
+ editable: r.tenant_id !== null,
367
+ }));
368
+ }
369
+ export function summarizeGovernance(rules) {
370
+ const byStatus = {};
371
+ for (const r of rules)
372
+ byStatus[r.status] = (byStatus[r.status] ?? 0) + 1;
373
+ const withSource = rules.filter((r) => r.sourceUrl || r.sourceReference).length;
374
+ return {
375
+ total: rules.length,
376
+ byStatus,
377
+ withSource,
378
+ withoutSource: rules.length - withSource,
379
+ /*
380
+ * "Pronta para revisão" NÃO é "validada".
381
+ *
382
+ * Uma regra entra nesta contagem quando está pendente E tem uma fonte
383
+ * oficial anexada — ou seja, quando existe algo concreto para a pessoa
384
+ * conferir. Sem a fonte, pedir conferência é pedir que alguém procure a
385
+ * norma sozinho, e é assim que uma fila de governança vira uma fila parada.
386
+ */
387
+ readyForHumanReview: rules.filter((r) => r.status === 'pending_validation' && Boolean(r.sourceUrl || r.sourceReference)).length,
388
+ };
389
+ }
390
+ /**
391
+ * Registra a fonte e a observação de uma regra DO ESCRITÓRIO.
392
+ *
393
+ * Separado de validar de propósito: anexar evidência é preparação, e quem
394
+ * prepara não carimba. Não toca em `status`.
395
+ */
396
+ export async function annotateFiscalRule(tx, input) {
397
+ if (input.sourceUrl && !/^https:\/\/[^\s"'<>]+$/i.test(input.sourceUrl)) {
398
+ throw new ValidationError('A fonte precisa ser uma URL https.');
399
+ }
400
+ const rows = await tx `
401
+ UPDATE fiscal_rule
402
+ SET source_url = COALESCE(${input.sourceUrl ?? null}, source_url),
403
+ source_reference = COALESCE(${input.sourceReference ?? null}, source_reference),
404
+ note = COALESCE(${input.note ?? null}, note),
405
+ updated_at = now()
406
+ WHERE id = ${input.id} AND tenant_id IS NOT NULL AND deleted_at IS NULL
407
+ RETURNING id
408
+ `;
409
+ if (!rows[0]) {
410
+ throw new ValidationError('Regra não encontrada neste escritório. Regras globais do produto não são editáveis aqui — crie uma regra do escritório para sobrepor.');
411
+ }
412
+ }
413
+ /**
414
+ * O carimbo humano de conferência.
415
+ *
416
+ * Três guardas, e nenhum é redundante:
417
+ *
418
+ * 1. **Só regra do escritório.** A global é do produto; conferi-la para todo o
419
+ * Brasil não é decisão de um tenant.
420
+ * 2. **`validatedBy` obrigatório e vindo da SESSÃO**, nunca do corpo. Uma regra
421
+ * validada precisa responder "quem conferiu" com um nome que a pessoa não
422
+ * escolheu para si.
423
+ * 3. **Fonte obrigatória.** Validar sem apontar a norma é registrar uma opinião
424
+ * com aparência de conferência — e é exatamente o que a trilha não deve
425
+ * permitir que se pareça com evidência depois.
426
+ */
427
+ export async function validateFiscalRule(tx, input) {
428
+ const atual = await tx `
429
+ SELECT id, source_url, source_reference FROM fiscal_rule
430
+ WHERE id = ${input.id} AND tenant_id IS NOT NULL AND deleted_at IS NULL
431
+ `;
432
+ const regra = atual[0];
433
+ if (!regra) {
434
+ throw new ValidationError('Regra não encontrada neste escritório. Regras globais do produto não são conferidas aqui.');
435
+ }
436
+ if (!regra.source_url && !regra.source_reference) {
437
+ throw new ValidationError('Antes de conferir, registre a fonte oficial da regra. Conferência sem fonte não é evidência.');
438
+ }
439
+ await tx `
440
+ UPDATE fiscal_rule
441
+ SET status = 'validated',
442
+ validated_by = ${input.validatedBy},
443
+ validated_at = now(),
444
+ note = COALESCE(${input.note ?? null}, note),
445
+ updated_at = now()
446
+ WHERE id = ${input.id} AND tenant_id IS NOT NULL AND deleted_at IS NULL
447
+ `;
448
+ }
449
+ //# sourceMappingURL=repository.js.map