@baruk/core 0.1.0 → 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.
Files changed (429) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/dist/auth/password-reset.d.ts.map +1 -1
  3. package/dist/auth/password-reset.js +2 -4
  4. package/dist/auth/password-reset.js.map +1 -1
  5. package/dist/auth/password.d.ts +2 -18
  6. package/dist/auth/password.d.ts.map +1 -1
  7. package/dist/auth/password.js +12 -51
  8. package/dist/auth/password.js.map +1 -1
  9. package/dist/auth/service.d.ts +0 -12
  10. package/dist/auth/service.d.ts.map +1 -1
  11. package/dist/auth/service.js +3 -36
  12. package/dist/auth/service.js.map +1 -1
  13. package/dist/auth/session-token.d.ts +5 -2
  14. package/dist/auth/session-token.d.ts.map +1 -1
  15. package/dist/auth/session-token.js +7 -12
  16. package/dist/auth/session-token.js.map +1 -1
  17. package/dist/billing/dunning.d.ts +33 -0
  18. package/dist/billing/dunning.d.ts.map +1 -0
  19. package/dist/billing/dunning.js +49 -0
  20. package/dist/billing/dunning.js.map +1 -0
  21. package/dist/billing/provider/asaas.d.ts +15 -0
  22. package/dist/billing/provider/asaas.d.ts.map +1 -0
  23. package/dist/billing/provider/asaas.js +121 -0
  24. package/dist/billing/provider/asaas.js.map +1 -0
  25. package/dist/billing/provider/manual.d.ts +14 -0
  26. package/dist/billing/provider/manual.d.ts.map +1 -0
  27. package/dist/billing/provider/manual.js +24 -0
  28. package/dist/billing/provider/manual.js.map +1 -0
  29. package/dist/billing/provider/registry.d.ts +12 -0
  30. package/dist/billing/provider/registry.d.ts.map +1 -0
  31. package/dist/billing/provider/registry.js +22 -0
  32. package/dist/billing/provider/registry.js.map +1 -0
  33. package/dist/billing/provider/types.d.ts +76 -0
  34. package/dist/billing/provider/types.d.ts.map +1 -0
  35. package/dist/billing/provider/types.js +9 -0
  36. package/dist/billing/provider/types.js.map +1 -0
  37. package/dist/billing/receivable.d.ts +108 -0
  38. package/dist/billing/receivable.d.ts.map +1 -0
  39. package/dist/billing/receivable.js +2 -0
  40. package/dist/billing/receivable.js.map +1 -0
  41. package/dist/billing/repository.d.ts +97 -0
  42. package/dist/billing/repository.d.ts.map +1 -0
  43. package/dist/billing/repository.js +167 -0
  44. package/dist/billing/repository.js.map +1 -0
  45. package/dist/cjs/audit/audit.js +31 -0
  46. package/dist/cjs/audit/audit.js.map +1 -0
  47. package/dist/cjs/audit/repository.js +32 -0
  48. package/dist/cjs/audit/repository.js.map +1 -0
  49. package/dist/cjs/auth/password-reset.js +58 -0
  50. package/dist/cjs/auth/password-reset.js.map +1 -0
  51. package/dist/cjs/auth/password.js +32 -0
  52. package/dist/cjs/auth/password.js.map +1 -0
  53. package/dist/cjs/auth/service.js +191 -0
  54. package/dist/cjs/auth/service.js.map +1 -0
  55. package/dist/cjs/auth/session-token.js +18 -0
  56. package/dist/cjs/auth/session-token.js.map +1 -0
  57. package/dist/cjs/billing/dunning.js +54 -0
  58. package/dist/cjs/billing/dunning.js.map +1 -0
  59. package/dist/cjs/billing/provider/asaas.js +125 -0
  60. package/dist/cjs/billing/provider/asaas.js.map +1 -0
  61. package/dist/cjs/billing/provider/manual.js +28 -0
  62. package/dist/cjs/billing/provider/manual.js.map +1 -0
  63. package/dist/cjs/billing/provider/registry.js +27 -0
  64. package/dist/cjs/billing/provider/registry.js.map +1 -0
  65. package/dist/cjs/billing/provider/types.js +10 -0
  66. package/dist/cjs/billing/provider/types.js.map +1 -0
  67. package/dist/cjs/billing/receivable.js +3 -0
  68. package/dist/cjs/billing/receivable.js.map +1 -0
  69. package/dist/cjs/billing/repository.js +180 -0
  70. package/dist/cjs/billing/repository.js.map +1 -0
  71. package/dist/cjs/clients/repository.js +123 -0
  72. package/dist/cjs/clients/repository.js.map +1 -0
  73. package/dist/cjs/commercial-catalog/catalog.js +108 -0
  74. package/dist/cjs/commercial-catalog/catalog.js.map +1 -0
  75. package/dist/cjs/commercial-catalog/consumption-contracts.js +10 -0
  76. package/dist/cjs/commercial-catalog/consumption-contracts.js.map +1 -0
  77. package/dist/cjs/commercial-catalog/coupon.js +53 -0
  78. package/dist/cjs/commercial-catalog/coupon.js.map +1 -0
  79. package/dist/cjs/commercial-catalog/index.js +16 -0
  80. package/dist/cjs/commercial-catalog/index.js.map +1 -0
  81. package/dist/cjs/commercial-catalog/offer-application.js +53 -0
  82. package/dist/cjs/commercial-catalog/offer-application.js.map +1 -0
  83. package/dist/cjs/commercial-catalog/types.js +26 -0
  84. package/dist/cjs/commercial-catalog/types.js.map +1 -0
  85. package/dist/cjs/crm/repository.js +195 -0
  86. package/dist/cjs/crm/repository.js.map +1 -0
  87. package/dist/cjs/dashboard/repository.js +39 -0
  88. package/dist/cjs/dashboard/repository.js.map +1 -0
  89. package/dist/cjs/db/client.js +27 -0
  90. package/dist/cjs/db/client.js.map +1 -0
  91. package/dist/cjs/db/context.js +43 -0
  92. package/dist/cjs/db/context.js.map +1 -0
  93. package/dist/cjs/db/load-env.js +47 -0
  94. package/dist/cjs/db/load-env.js.map +1 -0
  95. package/dist/cjs/db/seed.js +69 -0
  96. package/dist/cjs/db/seed.js.map +1 -0
  97. package/dist/cjs/entitlements/decision.js +203 -0
  98. package/dist/cjs/entitlements/decision.js.map +1 -0
  99. package/dist/cjs/entitlements/derive.js +46 -0
  100. package/dist/cjs/entitlements/derive.js.map +1 -0
  101. package/dist/cjs/entitlements/index.js +23 -0
  102. package/dist/cjs/entitlements/index.js.map +1 -0
  103. package/dist/cjs/entitlements/sources.js +60 -0
  104. package/dist/cjs/entitlements/sources.js.map +1 -0
  105. package/dist/cjs/entitlements/standing.js +42 -0
  106. package/dist/cjs/entitlements/standing.js.map +1 -0
  107. package/dist/cjs/entitlements/types.js +16 -0
  108. package/dist/cjs/entitlements/types.js.map +1 -0
  109. package/dist/cjs/import/clients-import.js +147 -0
  110. package/dist/cjs/import/clients-import.js.map +1 -0
  111. package/dist/cjs/index.js +335 -0
  112. package/dist/cjs/index.js.map +1 -0
  113. package/dist/cjs/mail/dedup-store.js +56 -0
  114. package/dist/cjs/mail/dedup-store.js.map +1 -0
  115. package/dist/cjs/mail/index.js +24 -0
  116. package/dist/cjs/mail/index.js.map +1 -0
  117. package/dist/cjs/mail/provider.js +251 -0
  118. package/dist/cjs/mail/provider.js.map +1 -0
  119. package/dist/cjs/mail/resend-client.js +103 -0
  120. package/dist/cjs/mail/resend-client.js.map +1 -0
  121. package/dist/cjs/mail/resend.js +21 -0
  122. package/dist/cjs/mail/resend.js.map +1 -0
  123. package/dist/cjs/mail/sanitize.js +56 -0
  124. package/dist/cjs/mail/sanitize.js.map +1 -0
  125. package/dist/cjs/mail/sender-resolver.js +15 -0
  126. package/dist/cjs/mail/sender-resolver.js.map +1 -0
  127. package/dist/cjs/mail/template-renderer.js +21 -0
  128. package/dist/cjs/mail/template-renderer.js.map +1 -0
  129. package/dist/cjs/mail/types.js +38 -0
  130. package/dist/cjs/mail/types.js.map +1 -0
  131. package/dist/cjs/notifications/repository.js +49 -0
  132. package/dist/cjs/notifications/repository.js.map +1 -0
  133. package/dist/cjs/onboarding/domain.js +370 -0
  134. package/dist/cjs/onboarding/domain.js.map +1 -0
  135. package/dist/cjs/onboarding/interaction-review.js +425 -0
  136. package/dist/cjs/onboarding/interaction-review.js.map +1 -0
  137. package/dist/cjs/onboarding/persistence.js +444 -0
  138. package/dist/cjs/onboarding/persistence.js.map +1 -0
  139. package/dist/cjs/onboarding/portal-actions.js +157 -0
  140. package/dist/cjs/onboarding/portal-actions.js.map +1 -0
  141. package/dist/cjs/onboarding/portal.js +177 -0
  142. package/dist/cjs/onboarding/portal.js.map +1 -0
  143. package/dist/cjs/package.json +3 -0
  144. package/dist/cjs/portal/repository.js +37 -0
  145. package/dist/cjs/portal/repository.js.map +1 -0
  146. package/dist/cjs/pricing-engine/bundle.js +49 -0
  147. package/dist/cjs/pricing-engine/bundle.js.map +1 -0
  148. package/dist/cjs/pricing-engine/errors.js +48 -0
  149. package/dist/cjs/pricing-engine/errors.js.map +1 -0
  150. package/dist/cjs/pricing-engine/index.js +30 -0
  151. package/dist/cjs/pricing-engine/index.js.map +1 -0
  152. package/dist/cjs/pricing-engine/money.js +69 -0
  153. package/dist/cjs/pricing-engine/money.js.map +1 -0
  154. package/dist/cjs/pricing-engine/pipeline.js +330 -0
  155. package/dist/cjs/pricing-engine/pipeline.js.map +1 -0
  156. package/dist/cjs/pricing-engine/proration.js +53 -0
  157. package/dist/cjs/pricing-engine/proration.js.map +1 -0
  158. package/dist/cjs/pricing-engine/shadow.js +58 -0
  159. package/dist/cjs/pricing-engine/shadow.js.map +1 -0
  160. package/dist/cjs/pricing-engine/types.js +34 -0
  161. package/dist/cjs/pricing-engine/types.js.map +1 -0
  162. package/dist/cjs/products/catalog.js +10 -0
  163. package/dist/cjs/products/catalog.js.map +1 -0
  164. package/dist/cjs/products/repository.js +61 -0
  165. package/dist/cjs/products/repository.js.map +1 -0
  166. package/dist/cjs/rbac/authorize.js +36 -0
  167. package/dist/cjs/rbac/authorize.js.map +1 -0
  168. package/dist/cjs/rbac/catalog.js +455 -0
  169. package/dist/cjs/rbac/catalog.js.map +1 -0
  170. package/dist/cjs/requests/repository.js +114 -0
  171. package/dist/cjs/requests/repository.js.map +1 -0
  172. package/dist/cjs/subscription-billing/dunning.js +26 -0
  173. package/dist/cjs/subscription-billing/dunning.js.map +1 -0
  174. package/dist/cjs/subscription-billing/events.js +45 -0
  175. package/dist/cjs/subscription-billing/events.js.map +1 -0
  176. package/dist/cjs/subscription-billing/index.js +62 -0
  177. package/dist/cjs/subscription-billing/index.js.map +1 -0
  178. package/dist/cjs/subscription-billing/plans.js +88 -0
  179. package/dist/cjs/subscription-billing/plans.js.map +1 -0
  180. package/dist/cjs/subscription-billing/product-config.js +54 -0
  181. package/dist/cjs/subscription-billing/product-config.js.map +1 -0
  182. package/dist/cjs/subscription-billing/provider/asaas.js +233 -0
  183. package/dist/cjs/subscription-billing/provider/asaas.js.map +1 -0
  184. package/dist/cjs/subscription-billing/provider/disabled.js +46 -0
  185. package/dist/cjs/subscription-billing/provider/disabled.js.map +1 -0
  186. package/dist/cjs/subscription-billing/provider/registry.js +29 -0
  187. package/dist/cjs/subscription-billing/provider/registry.js.map +1 -0
  188. package/dist/cjs/subscription-billing/reconcile.js +198 -0
  189. package/dist/cjs/subscription-billing/reconcile.js.map +1 -0
  190. package/dist/cjs/subscription-billing/repository.js +359 -0
  191. package/dist/cjs/subscription-billing/repository.js.map +1 -0
  192. package/dist/cjs/subscription-billing/service.js +838 -0
  193. package/dist/cjs/subscription-billing/service.js.map +1 -0
  194. package/dist/cjs/subscription-billing/types.js +28 -0
  195. package/dist/cjs/subscription-billing/types.js.map +1 -0
  196. package/dist/cjs/tenancy/provisioning.js +126 -0
  197. package/dist/cjs/tenancy/provisioning.js.map +1 -0
  198. package/dist/cjs/users/repository.js +83 -0
  199. package/dist/cjs/users/repository.js.map +1 -0
  200. package/dist/cjs/vault/crypto.js +94 -0
  201. package/dist/cjs/vault/crypto.js.map +1 -0
  202. package/dist/cjs/vault/repository.js +120 -0
  203. package/dist/cjs/vault/repository.js.map +1 -0
  204. package/dist/commercial-catalog/catalog.d.ts +27 -0
  205. package/dist/commercial-catalog/catalog.d.ts.map +1 -0
  206. package/dist/commercial-catalog/catalog.js +104 -0
  207. package/dist/commercial-catalog/catalog.js.map +1 -0
  208. package/dist/commercial-catalog/consumption-contracts.d.ts +33 -0
  209. package/dist/commercial-catalog/consumption-contracts.d.ts.map +1 -0
  210. package/dist/commercial-catalog/consumption-contracts.js +9 -0
  211. package/dist/commercial-catalog/consumption-contracts.js.map +1 -0
  212. package/dist/commercial-catalog/coupon.d.ts +27 -0
  213. package/dist/commercial-catalog/coupon.d.ts.map +1 -0
  214. package/dist/commercial-catalog/coupon.js +47 -0
  215. package/dist/commercial-catalog/coupon.js.map +1 -0
  216. package/dist/commercial-catalog/index.d.ts +10 -0
  217. package/dist/commercial-catalog/index.d.ts.map +1 -0
  218. package/dist/commercial-catalog/index.js +5 -0
  219. package/dist/commercial-catalog/index.js.map +1 -0
  220. package/dist/commercial-catalog/offer-application.d.ts +39 -0
  221. package/dist/commercial-catalog/offer-application.d.ts.map +1 -0
  222. package/dist/commercial-catalog/offer-application.js +50 -0
  223. package/dist/commercial-catalog/offer-application.js.map +1 -0
  224. package/dist/commercial-catalog/types.d.ts +155 -0
  225. package/dist/commercial-catalog/types.d.ts.map +1 -0
  226. package/dist/commercial-catalog/types.js +23 -0
  227. package/dist/commercial-catalog/types.js.map +1 -0
  228. package/dist/crm/repository.d.ts +109 -0
  229. package/dist/crm/repository.d.ts.map +1 -0
  230. package/dist/crm/repository.js +181 -0
  231. package/dist/crm/repository.js.map +1 -0
  232. package/dist/db/context.d.ts +2 -0
  233. package/dist/db/context.d.ts.map +1 -1
  234. package/dist/db/context.js +3 -0
  235. package/dist/db/context.js.map +1 -1
  236. package/dist/db/migrate.js +7 -2
  237. package/dist/db/migrate.js.map +1 -1
  238. package/dist/db/seed.js +4 -1
  239. package/dist/db/seed.js.map +1 -1
  240. package/dist/entitlements/decision.d.ts +86 -0
  241. package/dist/entitlements/decision.d.ts.map +1 -0
  242. package/dist/entitlements/decision.js +196 -0
  243. package/dist/entitlements/decision.js.map +1 -0
  244. package/dist/entitlements/derive.d.ts +30 -0
  245. package/dist/entitlements/derive.d.ts.map +1 -0
  246. package/dist/entitlements/derive.js +42 -0
  247. package/dist/entitlements/derive.js.map +1 -0
  248. package/dist/entitlements/index.d.ts +10 -0
  249. package/dist/entitlements/index.d.ts.map +1 -0
  250. package/dist/entitlements/index.js +7 -0
  251. package/dist/entitlements/index.js.map +1 -0
  252. package/dist/entitlements/sources.d.ts +30 -0
  253. package/dist/entitlements/sources.d.ts.map +1 -0
  254. package/dist/entitlements/sources.js +55 -0
  255. package/dist/entitlements/sources.js.map +1 -0
  256. package/dist/entitlements/standing.d.ts +22 -0
  257. package/dist/entitlements/standing.d.ts.map +1 -0
  258. package/dist/entitlements/standing.js +38 -0
  259. package/dist/entitlements/standing.js.map +1 -0
  260. package/dist/entitlements/types.d.ts +26 -0
  261. package/dist/entitlements/types.d.ts.map +1 -0
  262. package/dist/entitlements/types.js +15 -0
  263. package/dist/entitlements/types.js.map +1 -0
  264. package/dist/index.d.ts +74 -3
  265. package/dist/index.d.ts.map +1 -1
  266. package/dist/index.js +51 -4
  267. package/dist/index.js.map +1 -1
  268. package/dist/mail/dedup-store.d.ts +25 -0
  269. package/dist/mail/dedup-store.d.ts.map +1 -0
  270. package/dist/mail/dedup-store.js +51 -0
  271. package/dist/mail/dedup-store.js.map +1 -0
  272. package/dist/mail/index.d.ts +10 -0
  273. package/dist/mail/index.d.ts.map +1 -0
  274. package/dist/mail/index.js +9 -0
  275. package/dist/mail/index.js.map +1 -0
  276. package/dist/mail/provider.d.ts +31 -0
  277. package/dist/mail/provider.d.ts.map +1 -0
  278. package/dist/mail/provider.js +248 -0
  279. package/dist/mail/provider.js.map +1 -0
  280. package/dist/mail/resend-client.d.ts +16 -0
  281. package/dist/mail/resend-client.d.ts.map +1 -0
  282. package/dist/mail/resend-client.js +100 -0
  283. package/dist/mail/resend-client.js.map +1 -0
  284. package/dist/mail/resend.d.ts.map +1 -1
  285. package/dist/mail/resend.js +2 -0
  286. package/dist/mail/resend.js.map +1 -1
  287. package/dist/mail/sanitize.d.ts +17 -0
  288. package/dist/mail/sanitize.d.ts.map +1 -0
  289. package/dist/mail/sanitize.js +51 -0
  290. package/dist/mail/sanitize.js.map +1 -0
  291. package/dist/mail/sender-resolver.d.ts +8 -0
  292. package/dist/mail/sender-resolver.d.ts.map +1 -0
  293. package/dist/mail/sender-resolver.js +11 -0
  294. package/dist/mail/sender-resolver.js.map +1 -0
  295. package/dist/mail/template-renderer.d.ts +10 -0
  296. package/dist/mail/template-renderer.d.ts.map +1 -0
  297. package/dist/mail/template-renderer.js +17 -0
  298. package/dist/mail/template-renderer.js.map +1 -0
  299. package/dist/mail/types.d.ts +143 -0
  300. package/dist/mail/types.d.ts.map +1 -0
  301. package/dist/mail/types.js +34 -0
  302. package/dist/mail/types.js.map +1 -0
  303. package/dist/onboarding/domain.d.ts +146 -0
  304. package/dist/onboarding/domain.d.ts.map +1 -0
  305. package/dist/onboarding/domain.js +348 -0
  306. package/dist/onboarding/domain.js.map +1 -0
  307. package/dist/onboarding/interaction-review.d.ts +123 -0
  308. package/dist/onboarding/interaction-review.d.ts.map +1 -0
  309. package/dist/onboarding/interaction-review.js +413 -0
  310. package/dist/onboarding/interaction-review.js.map +1 -0
  311. package/dist/onboarding/persistence.d.ts +106 -0
  312. package/dist/onboarding/persistence.d.ts.map +1 -0
  313. package/dist/onboarding/persistence.js +430 -0
  314. package/dist/onboarding/persistence.js.map +1 -0
  315. package/dist/onboarding/portal-actions.d.ts +48 -0
  316. package/dist/onboarding/portal-actions.d.ts.map +1 -0
  317. package/dist/onboarding/portal-actions.js +153 -0
  318. package/dist/onboarding/portal-actions.js.map +1 -0
  319. package/dist/onboarding/portal.d.ts +58 -0
  320. package/dist/onboarding/portal.d.ts.map +1 -0
  321. package/dist/onboarding/portal.js +170 -0
  322. package/dist/onboarding/portal.js.map +1 -0
  323. package/dist/pricing-engine/bundle.d.ts +22 -0
  324. package/dist/pricing-engine/bundle.d.ts.map +1 -0
  325. package/dist/pricing-engine/bundle.js +44 -0
  326. package/dist/pricing-engine/bundle.js.map +1 -0
  327. package/dist/pricing-engine/errors.d.ts +32 -0
  328. package/dist/pricing-engine/errors.d.ts.map +1 -0
  329. package/dist/pricing-engine/errors.js +44 -0
  330. package/dist/pricing-engine/errors.js.map +1 -0
  331. package/dist/pricing-engine/index.d.ts +12 -0
  332. package/dist/pricing-engine/index.d.ts.map +1 -0
  333. package/dist/pricing-engine/index.js +8 -0
  334. package/dist/pricing-engine/index.js.map +1 -0
  335. package/dist/pricing-engine/money.d.ts +32 -0
  336. package/dist/pricing-engine/money.d.ts.map +1 -0
  337. package/dist/pricing-engine/money.js +58 -0
  338. package/dist/pricing-engine/money.js.map +1 -0
  339. package/dist/pricing-engine/pipeline.d.ts +3 -0
  340. package/dist/pricing-engine/pipeline.d.ts.map +1 -0
  341. package/dist/pricing-engine/pipeline.js +327 -0
  342. package/dist/pricing-engine/pipeline.js.map +1 -0
  343. package/dist/pricing-engine/proration.d.ts +3 -0
  344. package/dist/pricing-engine/proration.d.ts.map +1 -0
  345. package/dist/pricing-engine/proration.js +50 -0
  346. package/dist/pricing-engine/proration.js.map +1 -0
  347. package/dist/pricing-engine/shadow.d.ts +51 -0
  348. package/dist/pricing-engine/shadow.d.ts.map +1 -0
  349. package/dist/pricing-engine/shadow.js +54 -0
  350. package/dist/pricing-engine/shadow.js.map +1 -0
  351. package/dist/pricing-engine/types.d.ts +184 -0
  352. package/dist/pricing-engine/types.d.ts.map +1 -0
  353. package/dist/pricing-engine/types.js +31 -0
  354. package/dist/pricing-engine/types.js.map +1 -0
  355. package/dist/rbac/authorize.d.ts +3 -6
  356. package/dist/rbac/authorize.d.ts.map +1 -1
  357. package/dist/rbac/authorize.js +4 -8
  358. package/dist/rbac/authorize.js.map +1 -1
  359. package/dist/rbac/catalog.d.ts.map +1 -1
  360. package/dist/rbac/catalog.js +414 -21
  361. package/dist/rbac/catalog.js.map +1 -1
  362. package/dist/subscription-billing/dunning.d.ts +18 -0
  363. package/dist/subscription-billing/dunning.d.ts.map +1 -0
  364. package/dist/subscription-billing/dunning.js +28 -0
  365. package/dist/subscription-billing/dunning.js.map +1 -0
  366. package/dist/subscription-billing/events.d.ts +58 -0
  367. package/dist/subscription-billing/events.d.ts.map +1 -0
  368. package/dist/subscription-billing/events.js +38 -0
  369. package/dist/subscription-billing/events.js.map +1 -0
  370. package/dist/subscription-billing/index.d.ts +18 -0
  371. package/dist/subscription-billing/index.d.ts.map +1 -0
  372. package/dist/subscription-billing/index.js +16 -0
  373. package/dist/subscription-billing/index.js.map +1 -0
  374. package/dist/subscription-billing/plans.d.ts +34 -0
  375. package/dist/subscription-billing/plans.d.ts.map +1 -0
  376. package/dist/subscription-billing/plans.js +85 -0
  377. package/dist/subscription-billing/plans.js.map +1 -0
  378. package/dist/subscription-billing/product-config.d.ts +61 -0
  379. package/dist/subscription-billing/product-config.d.ts.map +1 -0
  380. package/dist/subscription-billing/product-config.js +50 -0
  381. package/dist/subscription-billing/product-config.js.map +1 -0
  382. package/dist/subscription-billing/provider/asaas.d.ts +26 -0
  383. package/dist/subscription-billing/provider/asaas.d.ts.map +1 -0
  384. package/dist/subscription-billing/provider/asaas.js +229 -0
  385. package/dist/subscription-billing/provider/asaas.js.map +1 -0
  386. package/dist/subscription-billing/provider/disabled.d.ts +30 -0
  387. package/dist/subscription-billing/provider/disabled.d.ts.map +1 -0
  388. package/dist/subscription-billing/provider/disabled.js +42 -0
  389. package/dist/subscription-billing/provider/disabled.js.map +1 -0
  390. package/dist/subscription-billing/provider/registry.d.ts +10 -0
  391. package/dist/subscription-billing/provider/registry.d.ts.map +1 -0
  392. package/dist/subscription-billing/provider/registry.js +26 -0
  393. package/dist/subscription-billing/provider/registry.js.map +1 -0
  394. package/dist/subscription-billing/reconcile.d.ts +45 -0
  395. package/dist/subscription-billing/reconcile.d.ts.map +1 -0
  396. package/dist/subscription-billing/reconcile.js +192 -0
  397. package/dist/subscription-billing/reconcile.js.map +1 -0
  398. package/dist/subscription-billing/repository.d.ts +168 -0
  399. package/dist/subscription-billing/repository.d.ts.map +1 -0
  400. package/dist/subscription-billing/repository.js +336 -0
  401. package/dist/subscription-billing/repository.js.map +1 -0
  402. package/dist/subscription-billing/service.d.ts +175 -0
  403. package/dist/subscription-billing/service.d.ts.map +1 -0
  404. package/dist/subscription-billing/service.js +818 -0
  405. package/dist/subscription-billing/service.js.map +1 -0
  406. package/dist/subscription-billing/types.d.ts +161 -0
  407. package/dist/subscription-billing/types.d.ts.map +1 -0
  408. package/dist/subscription-billing/types.js +24 -0
  409. package/dist/subscription-billing/types.js.map +1 -0
  410. package/dist/vault/crypto.d.ts +22 -0
  411. package/dist/vault/crypto.d.ts.map +1 -0
  412. package/dist/vault/crypto.js +88 -0
  413. package/dist/vault/crypto.js.map +1 -0
  414. package/dist/vault/repository.d.ts +45 -0
  415. package/dist/vault/repository.d.ts.map +1 -0
  416. package/dist/vault/repository.js +111 -0
  417. package/dist/vault/repository.js.map +1 -0
  418. package/package.json +23 -13
  419. package/src/db/migrations/0012_vault.sql +51 -0
  420. package/src/db/migrations/0013_crm.sql +67 -0
  421. package/src/db/migrations/0014_billing.sql +146 -0
  422. package/src/db/migrations/0015_merchant_billing_ar.sql +201 -0
  423. package/src/db/migrations/0016_office_onboarding.sql +162 -0
  424. package/src/db/migrations/0017_office_onboarding_api.sql +21 -0
  425. package/src/db/migrations/0018_office_onboarding_portal_actions.sql +60 -0
  426. package/src/db/migrations/0019_office_onboarding_interaction_review.sql +134 -0
  427. package/src/db/migrations/0020_saas_billing.sql +157 -0
  428. package/src/db/migrations/0021_saas_billing_indexes.sql +23 -0
  429. package/src/db/migrations/0022_saas_billing_multi_product.sql +75 -0
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Money — contrato monetário seguro do Pricing Engine (RFC-CAPABILITY-PRICING-
3
+ * ENGINE-001 §4, herdado de RFC-CAPABILITY-MERCHANT-BILLING-CORE-001 §5).
4
+ *
5
+ * Unidade mínima: CENTAVOS, sempre inteiro. Nenhuma fração é acumulada sem
6
+ * arredondar — cada operação que introduz fração (percentual, prorata por
7
+ * dias) arredonda IMEDIATAMENTE por half-even (bankers') no ponto de uso.
8
+ * Isto é o que garante "arredondamento uma vez, no fim" nas somas finais: as
9
+ * frações já foram eliminadas antes de somar.
10
+ *
11
+ * Reutilizado por bundle.ts, coupon.ts, proration.ts e pipeline.ts — nenhum
12
+ * outro Money é criado em `@baruk/core` (nem o `ChargeRecord.amount`/
13
+ * `CommercialPriceItem.amount` existentes, que guardam REAIS como
14
+ * conveniência de schema, nem um terceiro tipo). Este módulo é o único que
15
+ * precisa de aritmética encadeada (percentual → prorata → soma), por isso é
16
+ * o único ponto onde a disciplina de centavos inteiros se paga.
17
+ */
18
+ export type Cents = number;
19
+ /** Arredondamento half-even (bankers') — determinístico, não depende de ordem de chamadas. */
20
+ export declare function roundHalfEven(value: number): number;
21
+ export declare function reaisToCents(reais: number): Cents;
22
+ export declare function centsToReais(cents: Cents): number;
23
+ export declare function addCents(...values: Cents[]): Cents;
24
+ export declare function subtractCents(a: Cents, b: Cents): Cents;
25
+ /** Multiplica por uma quantidade inteira (assentos, unidades) — sem fração, nada a arredondar. */
26
+ export declare function multiplyByQuantity(cents: Cents, quantity: number): Cents;
27
+ /** Aplica um percentual (0-100) com arredondamento half-even no ponto de aplicação. */
28
+ export declare function applyPercent(cents: Cents, percent: number): Cents;
29
+ /** Prorata por fração de dias — arredondamento half-even no ponto de aplicação. */
30
+ export declare function prorateByDays(cents: Cents, daysNumerator: number, daysDenominator: number): Cents;
31
+ export declare function clampNonNegative(cents: Cents): Cents;
32
+ //# sourceMappingURL=money.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"money.d.ts","sourceRoot":"","sources":["../../src/pricing-engine/money.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC;AAE3B,8FAA8F;AAC9F,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMnD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAEjD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAEjD;AAED,wBAAgB,QAAQ,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAElD;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,GAAG,KAAK,CAEvD;AAED,kGAAkG;AAClG,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,CAExE;AAED,uFAAuF;AACvF,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAEjE;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,KAAK,CAKjG;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAEpD"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Money — contrato monetário seguro do Pricing Engine (RFC-CAPABILITY-PRICING-
3
+ * ENGINE-001 §4, herdado de RFC-CAPABILITY-MERCHANT-BILLING-CORE-001 §5).
4
+ *
5
+ * Unidade mínima: CENTAVOS, sempre inteiro. Nenhuma fração é acumulada sem
6
+ * arredondar — cada operação que introduz fração (percentual, prorata por
7
+ * dias) arredonda IMEDIATAMENTE por half-even (bankers') no ponto de uso.
8
+ * Isto é o que garante "arredondamento uma vez, no fim" nas somas finais: as
9
+ * frações já foram eliminadas antes de somar.
10
+ *
11
+ * Reutilizado por bundle.ts, coupon.ts, proration.ts e pipeline.ts — nenhum
12
+ * outro Money é criado em `@baruk/core` (nem o `ChargeRecord.amount`/
13
+ * `CommercialPriceItem.amount` existentes, que guardam REAIS como
14
+ * conveniência de schema, nem um terceiro tipo). Este módulo é o único que
15
+ * precisa de aritmética encadeada (percentual → prorata → soma), por isso é
16
+ * o único ponto onde a disciplina de centavos inteiros se paga.
17
+ */
18
+ /** Arredondamento half-even (bankers') — determinístico, não depende de ordem de chamadas. */
19
+ export function roundHalfEven(value) {
20
+ const floor = Math.floor(value);
21
+ const diff = value - floor;
22
+ if (diff < 0.5)
23
+ return floor;
24
+ if (diff > 0.5)
25
+ return floor + 1;
26
+ return floor % 2 === 0 ? floor : floor + 1;
27
+ }
28
+ export function reaisToCents(reais) {
29
+ return roundHalfEven(reais * 100);
30
+ }
31
+ export function centsToReais(cents) {
32
+ return cents / 100;
33
+ }
34
+ export function addCents(...values) {
35
+ return values.reduce((sum, v) => sum + v, 0);
36
+ }
37
+ export function subtractCents(a, b) {
38
+ return a - b;
39
+ }
40
+ /** Multiplica por uma quantidade inteira (assentos, unidades) — sem fração, nada a arredondar. */
41
+ export function multiplyByQuantity(cents, quantity) {
42
+ return cents * quantity;
43
+ }
44
+ /** Aplica um percentual (0-100) com arredondamento half-even no ponto de aplicação. */
45
+ export function applyPercent(cents, percent) {
46
+ return roundHalfEven((cents * percent) / 100);
47
+ }
48
+ /** Prorata por fração de dias — arredondamento half-even no ponto de aplicação. */
49
+ export function prorateByDays(cents, daysNumerator, daysDenominator) {
50
+ if (daysDenominator <= 0) {
51
+ throw new Error('prorateByDays: daysDenominator deve ser positivo.');
52
+ }
53
+ return roundHalfEven((cents * daysNumerator) / daysDenominator);
54
+ }
55
+ export function clampNonNegative(cents) {
56
+ return Math.max(0, cents);
57
+ }
58
+ //# sourceMappingURL=money.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"money.js","sourceRoot":"","sources":["../../src/pricing-engine/money.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,8FAA8F;AAC9F,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,KAAK,GAAG,KAAK,CAAC;IAC3B,IAAI,IAAI,GAAG,GAAG;QAAE,OAAO,KAAK,CAAC;IAC7B,IAAI,IAAI,GAAG,GAAG;QAAE,OAAO,KAAK,GAAG,CAAC,CAAC;IACjC,OAAO,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO,aAAa,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAY;IACvC,OAAO,KAAK,GAAG,GAAG,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAG,MAAe;IACzC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,CAAQ,EAAE,CAAQ;IAC9C,OAAO,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,kBAAkB,CAAC,KAAY,EAAE,QAAgB;IAC/D,OAAO,KAAK,GAAG,QAAQ,CAAC;AAC1B,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,YAAY,CAAC,KAAY,EAAE,OAAe;IACxD,OAAO,aAAa,CAAC,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;AAChD,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,aAAa,CAAC,KAAY,EAAE,aAAqB,EAAE,eAAuB;IACxF,IAAI,eAAe,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,aAAa,CAAC,CAAC,KAAK,GAAG,aAAa,CAAC,GAAG,eAAe,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAY;IAC3C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { type EngineResult, type PricingQuote, type PricingRequest } from './types.js';
2
+ export declare function computePricingQuote(request: PricingRequest): EngineResult<PricingQuote>;
3
+ //# sourceMappingURL=pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/pricing-engine/pipeline.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,YAAY,EAGjB,KAAK,cAAc,EAEpB,MAAM,YAAY,CAAC;AAoHpB,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,cAAc,GAAG,YAAY,CAAC,YAAY,CAAC,CAOvF"}
@@ -0,0 +1,327 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { addCents, applyPercent, clampNonNegative, multiplyByQuantity, reaisToCents, subtractCents } from './money.js';
3
+ import { PricingEngineError } from './errors.js';
4
+ import { assertBundleModulesCovered, freeModuleCodesForBundle, resolveBundleDiscount } from './bundle.js';
5
+ import { PRICING_ENGINE_VERSION, } from './types.js';
6
+ /**
7
+ * Pipeline determinístico do Pricing Engine (RFC-CAPABILITY-PRICING-ENGINE-001
8
+ * §8, ETAPA 5). A ordem abaixo é a ORDEM OFICIAL DA RFC (não a restatada na
9
+ * ETAPA 5 do prompt de implementação, que diverge em 2 pontos — ver
10
+ * correspondência documentada em RFC-CAPABILITY-PRICING-ENGINE-001 §8 e no
11
+ * relatório de entrega): 1.plano 2.módulo 3.quantidade 4.add-on 5.bundle
12
+ * 6.desconto negociado (percentual, cumulativo) 7.cupom 8.campanha
13
+ * 9.crédito promocional (reservado) 10.contrato negociado/grandfathering
14
+ * (FIXA/SOBREPÕE) 11.impostos 12.arredondamento.
15
+ *
16
+ * Cada etapa 5-8 opera SEQUENCIALMENTE sobre o total corrente ("sobre o
17
+ * resultado até aqui", RFC §8 passo 7) — não sobre a base original — porque
18
+ * a ordem já é fixa e explícita (a RFC elimina ambiguidade por ORDEM, não por
19
+ * uma base comum). Erros de contrato são sempre RETORNADOS
20
+ * (`EngineResult`), nunca lançados na fronteira pública (RFC §2/§7) —
21
+ * internamente usamos `throw PricingEngineError` e capturamos em
22
+ * `computePricingQuote`.
23
+ */
24
+ function fingerprintOf(request) {
25
+ const basis = {
26
+ tenantId: request.tenantId,
27
+ productLine: request.productLine,
28
+ offerCode: request.offer.code,
29
+ planCode: request.plan.code,
30
+ moduleCodes: [...request.offer.moduleCodes].sort(),
31
+ bundleCodes: [...request.offer.bundleCodes].sort(),
32
+ addonCodes: [...request.offer.addonCodes].sort(),
33
+ priceTableCode: request.priceTable.code,
34
+ priceTableVersion: request.priceTable.version,
35
+ billingCycle: request.billingCycle,
36
+ extraSeats: request.extraSeats ?? 0,
37
+ addonQuantities: request.addonQuantities ?? {},
38
+ couponCode: request.coupon?.code ?? null,
39
+ campaignCode: request.campaign?.code ?? null,
40
+ negotiatedContractTenantId: request.negotiatedContract?.tenantId ?? null,
41
+ negotiatedDiscountPercent: request.negotiatedContract?.discountPercent ?? null,
42
+ negotiatedFixedTotalCents: request.negotiatedContract?.fixedTotalCents ?? null,
43
+ trialActive: request.trial?.active ?? false,
44
+ now: request.now,
45
+ };
46
+ return createHash('sha256').update(JSON.stringify(basis)).digest('hex');
47
+ }
48
+ function catalogFingerprint(plan, modules, bundles) {
49
+ const basis = {
50
+ plan: { code: plan.code, tier: plan.tier, franchises: plan.franchises },
51
+ modules: modules.map((m) => ({ code: m.code, class: m.class })).sort((a, b) => a.code.localeCompare(b.code)),
52
+ bundles: bundles
53
+ .map((b) => ({ code: b.code, moduleCodes: [...b.moduleCodes].sort() }))
54
+ .sort((a, b) => a.code.localeCompare(b.code)),
55
+ };
56
+ return createHash('sha256').update(JSON.stringify(basis)).digest('hex');
57
+ }
58
+ function addHours(iso, hours) {
59
+ const d = /^\d{4}-\d{2}-\d{2}$/.test(iso) ? new Date(`${iso}T00:00:00Z`) : new Date(iso);
60
+ d.setUTCHours(d.getUTCHours() + hours);
61
+ return d.toISOString();
62
+ }
63
+ function itemOf(origin, targetCode, quantity, unitPriceCents, subtotalCents) {
64
+ return { origin, targetCode, quantity, unitPriceCents, subtotalCents: subtotalCents ?? unitPriceCents * quantity };
65
+ }
66
+ /**
67
+ * Busca o preço por `targetType`+`targetCode` **filtrado pelo `billingCycle`**
68
+ * (mensal/anual) — o mesmo `targetCode` pode ter duas entradas na tabela
69
+ * (`interval: 'monthly'` e `interval: 'yearly'`), e ignorar `interval` faria
70
+ * o lookup pegar a primeira entrada arbitrária (bug real corrigido antes dos
71
+ * cenários Rep/Ind da ETAPA 12, que exigem cotação mensal E anual).
72
+ */
73
+ function findPriceItemReais(table, targetType, targetCode, billingCycle) {
74
+ const item = table.items.find((i) => i.targetType === targetType && i.targetCode === targetCode && i.interval === billingCycle);
75
+ if (!item) {
76
+ throw new PricingEngineError('price-rule-missing', `Sem preço para ${targetType}:${targetCode} (ciclo=${billingCycle}) na tabela "${table.code}" v${table.version}.`);
77
+ }
78
+ return item.amount;
79
+ }
80
+ /**
81
+ * Aplicabilidade de escopo (RFC §16.1 divergência #1 — o que `resolvePriceQuote`
82
+ * mínimo do Catálogo NÃO faz). `scopes` é declarado na TABELA (não por item —
83
+ * `CommercialPriceItem` não tem campo de escopo); interpretação: tabela sem
84
+ * `scopes` = ALL (compatível com o resolvedor mínimo); com `scopes`, aplica-se
85
+ * se QUALQUER escopo casar (TENANT por `tenantId`, PRODUCT_LINE por
86
+ * `productLine`, ALL sempre casa). SEGMENT nunca casa nesta fase (sem contexto
87
+ * de segmento no `PricingRequest` — decisão explícita, não um bug silencioso).
88
+ */
89
+ function isTableApplicable(table, tenantId, productLine) {
90
+ if (!table.scopes || table.scopes.length === 0)
91
+ return true;
92
+ return table.scopes.some((s) => {
93
+ if (s.scopeType === 'ALL')
94
+ return true;
95
+ if (s.scopeType === 'TENANT')
96
+ return s.matchValue === tenantId;
97
+ if (s.scopeType === 'PRODUCT_LINE')
98
+ return s.matchValue === productLine;
99
+ return false;
100
+ });
101
+ }
102
+ function mustFindModule(modules, code) {
103
+ const mod = modules.find((m) => m.code === code);
104
+ if (!mod)
105
+ throw new PricingEngineError('price-rule-missing', `Módulo "${code}" não existe no catálogo recebido.`);
106
+ return mod;
107
+ }
108
+ function mustFindBundle(bundles, code) {
109
+ const bundle = bundles.find((b) => b.code === code);
110
+ if (!bundle)
111
+ throw new PricingEngineError('invalid-bundle', `Bundle "${code}" não existe no catálogo recebido.`);
112
+ return bundle;
113
+ }
114
+ export function computePricingQuote(request) {
115
+ try {
116
+ return { ok: true, value: computeInternal(request) };
117
+ }
118
+ catch (err) {
119
+ if (err instanceof PricingEngineError)
120
+ return { ok: false, error: err.toJSON() };
121
+ throw err;
122
+ }
123
+ }
124
+ function computeInternal(request) {
125
+ const { tenantId, productLine, offer, plan, modules, bundles, priceTable, bundleRules = [], extraSeats = 0, addonQuantities = {}, negotiatedContract, coupon, campaign, trial, now, billingCycle, quoteValidityHours = 24, } = request;
126
+ if (priceTable.code !== offer.priceTableCode) {
127
+ throw new PricingEngineError('price-rule-missing', `Offer "${offer.code}" referencia a tabela "${offer.priceTableCode}", recebida "${priceTable.code}".`);
128
+ }
129
+ if (priceTable.status !== 'active') {
130
+ throw new PricingEngineError('catalog-version-not-found', `Tabela "${priceTable.code}" não está ativa (status="${priceTable.status}").`);
131
+ }
132
+ if (now < priceTable.effectiveFrom || (priceTable.effectiveTo != null && now > priceTable.effectiveTo)) {
133
+ throw new PricingEngineError('invalid-effective-date', `Tabela "${priceTable.code}" fora de vigência em ${now}.`);
134
+ }
135
+ if (!isTableApplicable(priceTable, tenantId, productLine)) {
136
+ throw new PricingEngineError('catalog-version-not-found', `Tabela "${priceTable.code}" não se aplica ao escopo tenant="${tenantId}"/productLine="${productLine}".`);
137
+ }
138
+ if (negotiatedContract && (now < negotiatedContract.validFrom || (negotiatedContract.validTo != null && now > negotiatedContract.validTo))) {
139
+ throw new PricingEngineError('negotiated-contract-invalid', `Contrato negociado do tenant "${negotiatedContract.tenantId}" fora de vigência em ${now}.`);
140
+ }
141
+ const warnings = [];
142
+ const appliedRules = [];
143
+ const items = [];
144
+ // Passo 1 — BASE_PLAN_PRICE
145
+ items.push(itemOf('plan', offer.planCode, 1, reaisToCents(findPriceItemReais(priceTable, 'PLAN', offer.planCode, billingCycle))));
146
+ appliedRules.push('BASE_PLAN_PRICE');
147
+ // Módulos free_module de bundle precisam ser conhecidos ANTES de precificar (passo 2 não pode cobrar 2x depois descontar).
148
+ const freeModuleCodes = new Set();
149
+ for (const bundleCode of offer.bundleCodes) {
150
+ const bundle = mustFindBundle(bundles, bundleCode);
151
+ const rule = bundleRules.find((r) => r.bundleCode === bundleCode);
152
+ for (const code of freeModuleCodesForBundle(bundle, rule))
153
+ freeModuleCodes.add(code);
154
+ }
155
+ // Passo 2 — MODULE_PRICE
156
+ const chargedModuleCodes = new Set();
157
+ for (const moduleCode of offer.moduleCodes) {
158
+ mustFindModule(modules, moduleCode);
159
+ if (chargedModuleCodes.has(moduleCode)) {
160
+ throw new PricingEngineError('duplicate-charge-item', `Módulo "${moduleCode}" duplicado na oferta "${offer.code}".`);
161
+ }
162
+ chargedModuleCodes.add(moduleCode);
163
+ const unitCents = freeModuleCodes.has(moduleCode) ? 0 : reaisToCents(findPriceItemReais(priceTable, 'MODULE', moduleCode, billingCycle));
164
+ items.push(itemOf('module', moduleCode, 1, unitCents));
165
+ }
166
+ if (offer.moduleCodes.length > 0)
167
+ appliedRules.push('MODULE_PRICE');
168
+ // Passo 3 — QUANTITY_PRICE (assentos excedentes da franquia — delta já calculado pelo consumidor)
169
+ if (extraSeats > 0) {
170
+ const unitCents = reaisToCents(findPriceItemReais(priceTable, 'SEAT', 'extra_seat', billingCycle));
171
+ items.push(itemOf('seat', 'extra_seat', extraSeats, unitCents, multiplyByQuantity(unitCents, extraSeats)));
172
+ appliedRules.push('QUANTITY_PRICE');
173
+ }
174
+ // Passo 4 — ADDON_PRICE
175
+ for (const addonCode of offer.addonCodes) {
176
+ const qty = addonQuantities[addonCode] ?? 1;
177
+ const unitCents = reaisToCents(findPriceItemReais(priceTable, 'ADDON', addonCode, billingCycle));
178
+ items.push(itemOf('addon', addonCode, qty, unitCents, multiplyByQuantity(unitCents, qty)));
179
+ }
180
+ if (offer.addonCodes.length > 0)
181
+ appliedRules.push('ADDON_PRICE');
182
+ const subtotalCents = addCents(...items.map((i) => i.subtotalCents));
183
+ const discounts = [];
184
+ let runningCents = subtotalCents;
185
+ // Exclusividade (§8): cupom/campanha `exclusive` suprime bundle+desconto negociado (passos 5/6).
186
+ // Dois exclusivos → prioridade explícita decide; empate → erro (nunca escolha silenciosa).
187
+ const exclusiveCandidates = [];
188
+ if (coupon?.exclusive)
189
+ exclusiveCandidates.push({ key: 'coupon', priority: coupon.priority ?? 0, code: coupon.code });
190
+ if (campaign?.exclusive)
191
+ exclusiveCandidates.push({ key: 'campaign', priority: campaign.priority ?? 0, code: campaign.code });
192
+ let suppressBundleAndNegotiated = false;
193
+ let ignoredExclusiveKey = null;
194
+ if (exclusiveCandidates.length === 1) {
195
+ suppressBundleAndNegotiated = true;
196
+ }
197
+ else if (exclusiveCandidates.length === 2) {
198
+ const a = exclusiveCandidates[0];
199
+ const b = exclusiveCandidates[1];
200
+ if (a.priority === b.priority) {
201
+ throw new PricingEngineError('conflicting-rules', `Cupom "${a.code}" e campanha "${b.code}" são ambos exclusivos com a mesma prioridade (${a.priority}) — conflito não resolvível automaticamente.`, [a.code, b.code]);
202
+ }
203
+ suppressBundleAndNegotiated = true;
204
+ ignoredExclusiveKey = a.priority > b.priority ? 'campaign' : 'coupon';
205
+ }
206
+ // Passo 5 — BUNDLE_DISCOUNT
207
+ if (offer.bundleCodes.length > 0) {
208
+ for (const bundleCode of offer.bundleCodes) {
209
+ assertBundleModulesCovered(mustFindBundle(bundles, bundleCode), chargedModuleCodes);
210
+ }
211
+ }
212
+ if (!suppressBundleAndNegotiated) {
213
+ for (const bundleCode of offer.bundleCodes) {
214
+ const bundle = mustFindBundle(bundles, bundleCode);
215
+ const rule = bundleRules.find((r) => r.bundleCode === bundleCode);
216
+ const amount = resolveBundleDiscount(bundle, rule, items);
217
+ if (amount != null && amount > 0) {
218
+ const applied = Math.min(amount, runningCents);
219
+ discounts.push({ ruleId: bundleCode, step: 'BUNDLE_DISCOUNT', kind: 'bundle', amountCents: applied, appliesTo: bundle.moduleCodes });
220
+ runningCents = subtractCents(runningCents, applied);
221
+ }
222
+ }
223
+ if (offer.bundleCodes.length > 0)
224
+ appliedRules.push('BUNDLE_DISCOUNT');
225
+ }
226
+ else if (offer.bundleCodes.length > 0) {
227
+ warnings.push('Desconto de bundle suprimido: regra exclusiva de cupom/campanha está ativa.');
228
+ }
229
+ // Passo 6 — NEGOTIATED_DISCOUNT (percentual, cumulativo — distinto do override do passo 10)
230
+ if (negotiatedContract?.discountPercent != null) {
231
+ if (!suppressBundleAndNegotiated) {
232
+ const amount = applyPercent(runningCents, negotiatedContract.discountPercent);
233
+ const applied = Math.min(amount, runningCents);
234
+ discounts.push({
235
+ ruleId: `negotiated:${tenantId}`,
236
+ step: 'NEGOTIATED_DISCOUNT',
237
+ kind: 'negotiated_percent',
238
+ amountCents: applied,
239
+ appliesTo: ['*'],
240
+ });
241
+ runningCents = subtractCents(runningCents, applied);
242
+ appliedRules.push('NEGOTIATED_DISCOUNT');
243
+ }
244
+ else {
245
+ warnings.push('Desconto negociado (percentual) suprimido por regra exclusiva de cupom/campanha.');
246
+ }
247
+ }
248
+ // Passo 7 — COUPON (sobre o resultado até aqui — RFC §8)
249
+ if (coupon) {
250
+ if (ignoredExclusiveKey !== 'coupon') {
251
+ const raw = coupon.effectType === 'percent_off' ? applyPercent(runningCents, coupon.percentOff ?? 0) : (coupon.amountOffCents ?? 0);
252
+ const applied = Math.min(Math.max(raw, 0), runningCents);
253
+ discounts.push({ ruleId: coupon.code, step: 'COUPON', kind: coupon.effectType, amountCents: applied, appliesTo: ['*'] });
254
+ runningCents = subtractCents(runningCents, applied);
255
+ appliedRules.push('COUPON');
256
+ }
257
+ else {
258
+ warnings.push(`Cupom "${coupon.code}" ignorado: campanha exclusiva de maior prioridade está ativa.`);
259
+ }
260
+ }
261
+ // Passo 8 — CAMPAIGN
262
+ if (campaign) {
263
+ if (ignoredExclusiveKey !== 'campaign') {
264
+ const raw = campaign.effectType === 'percent_off' ? applyPercent(runningCents, campaign.percentOff ?? 0) : (campaign.amountOffCents ?? 0);
265
+ const applied = Math.min(Math.max(raw, 0), runningCents);
266
+ discounts.push({ ruleId: campaign.code, step: 'CAMPAIGN', kind: campaign.effectType, amountCents: applied, appliesTo: ['*'] });
267
+ runningCents = subtractCents(runningCents, applied);
268
+ appliedRules.push('CAMPAIGN');
269
+ }
270
+ else {
271
+ warnings.push(`Campanha "${campaign.code}" ignorada: cupom exclusivo de maior prioridade está ativa.`);
272
+ }
273
+ }
274
+ // Passo 9 — PROMOTIONAL_CREDIT (reservado — só preenchido quando Wallet/Rating existirem, RFC §12)
275
+ const promotionalCreditsCents = 0;
276
+ appliedRules.push('PROMOTIONAL_CREDIT');
277
+ // Passo 10 — CONTRACT_OVERRIDE_OR_GRANDFATHERING (fixa/sobrepõe o total — nunca um desconto adicional)
278
+ if (negotiatedContract?.fixedTotalCents != null) {
279
+ runningCents = negotiatedContract.fixedTotalCents;
280
+ appliedRules.push('CONTRACT_OVERRIDE_OR_GRANDFATHERING');
281
+ }
282
+ runningCents = clampNonNegative(runningCents);
283
+ const totalDiscountCents = clampNonNegative(subtractCents(subtotalCents, runningCents));
284
+ // Passo 11 — TAX (MVP: passthrough/zero configurável — política fiscal fora do escopo, RFC §5)
285
+ const taxes = [];
286
+ const totalTaxCents = 0;
287
+ appliedRules.push('TAX');
288
+ // Passo 12 — ROUNDING (cada etapa já arredondou half-even no ponto de uso — nada fracionário resta a arredondar)
289
+ const totalBeforeTrial = addCents(runningCents, totalTaxCents);
290
+ appliedRules.push('ROUNDING');
291
+ const trialActive = trial?.active ?? false;
292
+ const totalCents = trialActive ? 0 : totalBeforeTrial;
293
+ const postTrialTotalCents = trialActive ? totalBeforeTrial : null;
294
+ const fingerprint = fingerprintOf(request);
295
+ const quoteId = `pq_${fingerprint.slice(0, 24)}`;
296
+ return {
297
+ quoteId,
298
+ engineVersion: PRICING_ENGINE_VERSION,
299
+ tenantId,
300
+ productLine,
301
+ offerCode: offer.code,
302
+ priceTableCode: priceTable.code,
303
+ priceTableVersion: priceTable.version,
304
+ catalogVersion: catalogFingerprint(plan, modules, bundles),
305
+ pricingPolicyVersion: PRICING_ENGINE_VERSION,
306
+ currency: priceTable.currency,
307
+ now,
308
+ effectiveAt: now,
309
+ expiresAt: addHours(now, quoteValidityHours),
310
+ items,
311
+ discounts,
312
+ taxes,
313
+ promotionalCreditsCents,
314
+ subtotalCents,
315
+ totalDiscountCents,
316
+ totalTaxCents,
317
+ totalCents,
318
+ postTrialTotalCents,
319
+ trial: trial ?? null,
320
+ appliedRules,
321
+ warnings,
322
+ fingerprint,
323
+ auditMetadata: {},
324
+ proration: null,
325
+ };
326
+ }
327
+ //# sourceMappingURL=pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/pricing-engine/pipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ProrationInput, ProrationResult } from './types.js';
2
+ export declare function computeProration(input: ProrationInput): ProrationResult;
3
+ //# sourceMappingURL=proration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proration.d.ts","sourceRoot":"","sources":["../../src/pricing-engine/proration.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,MAAM,YAAY,CAAC;AA+BnF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,eAAe,CA6BvE"}
@@ -0,0 +1,50 @@
1
+ import { PricingEngineError } from './errors.js';
2
+ import { prorateByDays, subtractCents } from './money.js';
3
+ /**
4
+ * Proração (RFC §11, ETAPA 9) — PURA e determinística. Datas são sempre
5
+ * comparadas via `Date`/epoch-ms (nunca comparação frágil de string — mesma
6
+ * disciplina de `parseIso` do subscription-billing), o que resolve
7
+ * corretamente meses com dias diferentes, fim de mês e ano bissexto sem
8
+ * lógica de calendário adicional (a diferença em ms já contém isso).
9
+ */
10
+ /** Aceita data pura (`YYYY-MM-DD`) ou datetime ISO completo (mesma normalização do subscription-billing/commercial-catalog). */
11
+ function parseIso(iso) {
12
+ return /^\d{4}-\d{2}-\d{2}$/.test(iso) ? new Date(`${iso}T00:00:00Z`) : new Date(iso);
13
+ }
14
+ function daysBetween(a, b) {
15
+ return Math.round((parseIso(b).getTime() - parseIso(a).getTime()) / 86_400_000);
16
+ }
17
+ const DEFAULT_TIMING = {
18
+ upgrade: 'immediate',
19
+ add_module: 'immediate',
20
+ seats_up: 'immediate',
21
+ cycle_change: 'immediate',
22
+ reactivate: 'immediate',
23
+ downgrade: 'next_renewal',
24
+ remove_module: 'next_renewal',
25
+ seats_down: 'next_renewal',
26
+ cancel: 'immediate',
27
+ };
28
+ export function computeProration(input) {
29
+ const { reason, cycleStart, cycleEnd, now, oldValueCents, newValueCents } = input;
30
+ const daysInCycle = daysBetween(cycleStart, cycleEnd);
31
+ if (daysInCycle <= 0) {
32
+ throw new PricingEngineError('proration-invalid', `Ciclo inválido: "${cycleStart}" a "${cycleEnd}" não é um intervalo positivo.`);
33
+ }
34
+ const daysSinceStart = daysBetween(cycleStart, now);
35
+ if (daysSinceStart < 0) {
36
+ throw new PricingEngineError('proration-invalid', `Proração retroativa proibida: "now" (${now}) é anterior ao início do ciclo (${cycleStart}).`);
37
+ }
38
+ const timing = input.timingPolicy ?? DEFAULT_TIMING[reason];
39
+ const daysElapsed = Math.min(daysInCycle, daysSinceStart);
40
+ const daysRemaining = daysInCycle - daysElapsed;
41
+ if (timing === 'next_renewal') {
42
+ // Mudança só produz efeito no próximo ciclo — nenhum ajuste financeiro agora.
43
+ return { reason, effective: timing, daysRemaining, daysInCycle, creditCents: 0, debitCents: 0, netCents: 0 };
44
+ }
45
+ const creditCents = prorateByDays(oldValueCents, daysRemaining, daysInCycle);
46
+ const debitCents = reason === 'cancel' ? 0 : prorateByDays(newValueCents, daysRemaining, daysInCycle);
47
+ const netCents = subtractCents(debitCents, creditCents);
48
+ return { reason, effective: timing, daysRemaining, daysInCycle, creditCents, debitCents, netCents };
49
+ }
50
+ //# sourceMappingURL=proration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proration.js","sourceRoot":"","sources":["../../src/pricing-engine/proration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG1D;;;;;;GAMG;AAEH,gIAAgI;AAChI,SAAS,QAAQ,CAAC,GAAW;IAC3B,OAAO,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;AACxF,CAAC;AAED,SAAS,WAAW,CAAC,CAAS,EAAE,CAAS;IACvC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,cAAc,GAAsD;IACxE,OAAO,EAAE,WAAW;IACpB,UAAU,EAAE,WAAW;IACvB,QAAQ,EAAE,WAAW;IACrB,YAAY,EAAE,WAAW;IACzB,UAAU,EAAE,WAAW;IACvB,SAAS,EAAE,cAAc;IACzB,aAAa,EAAE,cAAc;IAC7B,UAAU,EAAE,cAAc;IAC1B,MAAM,EAAE,WAAW;CACpB,CAAC;AAEF,MAAM,UAAU,gBAAgB,CAAC,KAAqB;IACpD,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,aAAa,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;IAElF,MAAM,WAAW,GAAG,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACtD,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,kBAAkB,CAAC,mBAAmB,EAAE,oBAAoB,UAAU,QAAQ,QAAQ,gCAAgC,CAAC,CAAC;IACpI,CAAC;IACD,MAAM,cAAc,GAAG,WAAW,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACpD,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,kBAAkB,CAC1B,mBAAmB,EACnB,wCAAwC,GAAG,oCAAoC,UAAU,IAAI,CAC9F,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;IAC5D,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IAC1D,MAAM,aAAa,GAAG,WAAW,GAAG,WAAW,CAAC;IAEhD,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;QAC9B,8EAA8E;QAC9E,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IAC/G,CAAC;IAED,MAAM,WAAW,GAAG,aAAa,CAAC,aAAa,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC;IAC7E,MAAM,UAAU,GAAG,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,aAAa,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC;IACtG,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IAExD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AACtG,CAAC"}
@@ -0,0 +1,51 @@
1
+ import type { Cents } from './money.js';
2
+ import type { PricingQuote } from './types.js';
3
+ /**
4
+ * Shadow Comparison — SOMENTE o contrato técnico (RFC-CAPABILITY-PRICING-
5
+ * ENGINE-001 §13, ETAPA 13). Compara a saída do Pricing Engine canônico
6
+ * contra uma saída normalizada equivalente (ex.: o cálculo vivo do
7
+ * `manga-verde-bi`), SEM integrar com `manga-verde-bi` nesta sessão, SEM
8
+ * cobrar, SEM escrever dado de produção — `compareQuotes` é uma função pura
9
+ * de diff sobre dois objetos já normalizados injetados pelo chamador. O
10
+ * adapter mvb→`NormalizedQuoteForComparison` é trabalho de P4 (fora do
11
+ * escopo P1-P3), não construído aqui.
12
+ */
13
+ export type ShadowComparisonStatus = 'match' | 'mismatch' | 'not-comparable' | 'error';
14
+ /** Forma normalizada e mínima necessária para comparar — tanto o canônico quanto o shadow devem produzir isto. */
15
+ export interface NormalizedQuoteForComparison {
16
+ currency: string;
17
+ items: Array<{
18
+ targetCode: string;
19
+ amountCents: Cents;
20
+ }>;
21
+ totalDiscountCents: Cents;
22
+ totalCents: Cents;
23
+ }
24
+ export interface QuoteItemDiff {
25
+ targetCode: string;
26
+ canonicalCents: Cents | null;
27
+ shadowCents: Cents | null;
28
+ diffCents: Cents;
29
+ }
30
+ export interface ShadowComparisonResult {
31
+ status: ShadowComparisonStatus;
32
+ quoteId: string;
33
+ toleranceCents: Cents;
34
+ subtotalDiffCents: Cents;
35
+ discountDiffCents: Cents;
36
+ totalDiffCents: Cents;
37
+ itemDiffs: QuoteItemDiff[];
38
+ divergentRules: string[];
39
+ errorCode?: string;
40
+ errorMessage?: string;
41
+ }
42
+ export declare function normalizeCanonicalQuote(quote: PricingQuote): NormalizedQuoteForComparison;
43
+ /**
44
+ * Compara canônico vs shadow. `toleranceCents` (default 0 — igualdade exata
45
+ * em centavos, RFC §13 "igualdade exata em centavos no total") permite uma
46
+ * folga configurável para cenários de arredondamento de terceiros ainda não
47
+ * alinhados. Divergência de decomposição é logada mesmo com total igual
48
+ * (`itemDiffs`), para achar regra faltante sem esperar o total divergir.
49
+ */
50
+ export declare function compareQuotes(quoteId: string, canonical: NormalizedQuoteForComparison, shadow: NormalizedQuoteForComparison, toleranceCents?: Cents): ShadowComparisonResult;
51
+ //# sourceMappingURL=shadow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow.d.ts","sourceRoot":"","sources":["../../src/pricing-engine/shadow.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;;;;;GASG;AAEH,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,UAAU,GAAG,gBAAgB,GAAG,OAAO,CAAC;AAEvF,kHAAkH;AAClH,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;IACzD,kBAAkB,EAAE,KAAK,CAAC;IAC1B,UAAU,EAAE,KAAK,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,KAAK,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,KAAK,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,sBAAsB,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,KAAK,CAAC;IACtB,iBAAiB,EAAE,KAAK,CAAC;IACzB,iBAAiB,EAAE,KAAK,CAAC;IACzB,cAAc,EAAE,KAAK,CAAC;IACtB,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,YAAY,GAAG,4BAA4B,CAOzF;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,4BAA4B,EACvC,MAAM,EAAE,4BAA4B,EACpC,cAAc,GAAE,KAAS,GACxB,sBAAsB,CAwCxB"}
@@ -0,0 +1,54 @@
1
+ import { PricingEngineError } from './errors.js';
2
+ export function normalizeCanonicalQuote(quote) {
3
+ return {
4
+ currency: quote.currency,
5
+ items: quote.items.map((i) => ({ targetCode: i.targetCode, amountCents: i.subtotalCents })),
6
+ totalDiscountCents: quote.totalDiscountCents,
7
+ totalCents: quote.totalCents,
8
+ };
9
+ }
10
+ /**
11
+ * Compara canônico vs shadow. `toleranceCents` (default 0 — igualdade exata
12
+ * em centavos, RFC §13 "igualdade exata em centavos no total") permite uma
13
+ * folga configurável para cenários de arredondamento de terceiros ainda não
14
+ * alinhados. Divergência de decomposição é logada mesmo com total igual
15
+ * (`itemDiffs`), para achar regra faltante sem esperar o total divergir.
16
+ */
17
+ export function compareQuotes(quoteId, canonical, shadow, toleranceCents = 0) {
18
+ if (canonical.currency !== shadow.currency) {
19
+ const err = new PricingEngineError('currency-mismatch', `Moedas incompatíveis: canônico="${canonical.currency}", shadow="${shadow.currency}".`);
20
+ return {
21
+ status: 'not-comparable',
22
+ quoteId,
23
+ toleranceCents,
24
+ subtotalDiffCents: 0,
25
+ discountDiffCents: 0,
26
+ totalDiffCents: 0,
27
+ itemDiffs: [],
28
+ divergentRules: [],
29
+ errorCode: err.code,
30
+ errorMessage: err.message,
31
+ };
32
+ }
33
+ const targetCodes = new Set([...canonical.items.map((i) => i.targetCode), ...shadow.items.map((i) => i.targetCode)]);
34
+ const itemDiffs = [];
35
+ const divergentRules = [];
36
+ for (const targetCode of targetCodes) {
37
+ const canonicalItem = canonical.items.find((i) => i.targetCode === targetCode) ?? null;
38
+ const shadowItem = shadow.items.find((i) => i.targetCode === targetCode) ?? null;
39
+ const canonicalCents = canonicalItem?.amountCents ?? null;
40
+ const shadowCents = shadowItem?.amountCents ?? null;
41
+ const diffCents = (canonicalCents ?? 0) - (shadowCents ?? 0);
42
+ itemDiffs.push({ targetCode, canonicalCents, shadowCents, diffCents });
43
+ if (Math.abs(diffCents) > toleranceCents)
44
+ divergentRules.push(targetCode);
45
+ }
46
+ const subtotalCanonical = canonical.items.reduce((s, i) => s + i.amountCents, 0);
47
+ const subtotalShadow = shadow.items.reduce((s, i) => s + i.amountCents, 0);
48
+ const subtotalDiffCents = subtotalCanonical - subtotalShadow;
49
+ const discountDiffCents = canonical.totalDiscountCents - shadow.totalDiscountCents;
50
+ const totalDiffCents = canonical.totalCents - shadow.totalCents;
51
+ const status = Math.abs(totalDiffCents) <= toleranceCents && divergentRules.length === 0 ? 'match' : 'mismatch';
52
+ return { status, quoteId, toleranceCents, subtotalDiffCents, discountDiffCents, totalDiffCents, itemDiffs, divergentRules };
53
+ }
54
+ //# sourceMappingURL=shadow.js.map