@ducatjs/money 0.0.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 (398) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +51 -0
  3. package/README.md +1034 -3
  4. package/assets/CREDITS.md +12 -0
  5. package/data/adyen-fx.json +19 -0
  6. package/data/adyen.json +171 -0
  7. package/data/braintree.json +223 -0
  8. package/data/cash-rounding.json +520 -0
  9. package/data/checkout.json +230 -0
  10. package/data/cldr-cash.json +101 -0
  11. package/data/historic.json +78 -0
  12. package/data/iso4217-list-one.xml +1956 -0
  13. package/data/iso4217-list-three.xml +1185 -0
  14. package/data/klarna.json +95 -0
  15. package/data/paypal.json +65 -0
  16. package/data/stripe-fx.json +17 -0
  17. package/data/stripe.json +285 -0
  18. package/dist/adyen-fx.d.ts +25 -0
  19. package/dist/adyen-fx.d.ts.map +1 -0
  20. package/dist/adyen-fx.js +140 -0
  21. package/dist/adyen-fx.js.map +1 -0
  22. package/dist/adyen.d.ts +25 -0
  23. package/dist/adyen.d.ts.map +1 -0
  24. package/dist/adyen.js +34 -0
  25. package/dist/adyen.js.map +1 -0
  26. package/dist/allocate.d.ts +72 -0
  27. package/dist/allocate.d.ts.map +1 -0
  28. package/dist/allocate.js +314 -0
  29. package/dist/allocate.js.map +1 -0
  30. package/dist/bag.d.ts +58 -0
  31. package/dist/bag.d.ts.map +1 -0
  32. package/dist/bag.js +122 -0
  33. package/dist/bag.js.map +1 -0
  34. package/dist/boc.d.ts +31 -0
  35. package/dist/boc.d.ts.map +1 -0
  36. package/dist/boc.js +114 -0
  37. package/dist/boc.js.map +1 -0
  38. package/dist/boe.d.ts +33 -0
  39. package/dist/boe.d.ts.map +1 -0
  40. package/dist/boe.js +114 -0
  41. package/dist/boe.js.map +1 -0
  42. package/dist/braintree.d.ts +34 -0
  43. package/dist/braintree.d.ts.map +1 -0
  44. package/dist/braintree.js +45 -0
  45. package/dist/braintree.js.map +1 -0
  46. package/dist/cash.d.ts +64 -0
  47. package/dist/cash.d.ts.map +1 -0
  48. package/dist/cash.js +134 -0
  49. package/dist/cash.js.map +1 -0
  50. package/dist/checkout.d.ts +42 -0
  51. package/dist/checkout.d.ts.map +1 -0
  52. package/dist/checkout.js +52 -0
  53. package/dist/checkout.js.map +1 -0
  54. package/dist/convert.d.ts +52 -0
  55. package/dist/convert.d.ts.map +1 -0
  56. package/dist/convert.js +65 -0
  57. package/dist/convert.js.map +1 -0
  58. package/dist/currency.d.ts +22 -0
  59. package/dist/currency.d.ts.map +1 -0
  60. package/dist/currency.js +38 -0
  61. package/dist/currency.js.map +1 -0
  62. package/dist/decimal.d.ts +52 -0
  63. package/dist/decimal.d.ts.map +1 -0
  64. package/dist/decimal.js +251 -0
  65. package/dist/decimal.js.map +1 -0
  66. package/dist/drizzle/mysql.d.ts +105 -0
  67. package/dist/drizzle/mysql.d.ts.map +1 -0
  68. package/dist/drizzle/mysql.js +60 -0
  69. package/dist/drizzle/mysql.js.map +1 -0
  70. package/dist/drizzle/pg.d.ts +103 -0
  71. package/dist/drizzle/pg.d.ts.map +1 -0
  72. package/dist/drizzle/pg.js +60 -0
  73. package/dist/drizzle/pg.js.map +1 -0
  74. package/dist/drizzle/sqlite.d.ts +102 -0
  75. package/dist/drizzle/sqlite.d.ts.map +1 -0
  76. package/dist/drizzle/sqlite.js +59 -0
  77. package/dist/drizzle/sqlite.js.map +1 -0
  78. package/dist/ecb.d.ts +52 -0
  79. package/dist/ecb.d.ts.map +1 -0
  80. package/dist/ecb.js +285 -0
  81. package/dist/ecb.js.map +1 -0
  82. package/dist/exact.d.ts +62 -0
  83. package/dist/exact.d.ts.map +1 -0
  84. package/dist/exact.js +147 -0
  85. package/dist/exact.js.map +1 -0
  86. package/dist/fed.d.ts +35 -0
  87. package/dist/fed.d.ts.map +1 -0
  88. package/dist/fed.js +134 -0
  89. package/dist/fed.js.map +1 -0
  90. package/dist/fetch.d.ts +103 -0
  91. package/dist/fetch.d.ts.map +1 -0
  92. package/dist/fetch.js +222 -0
  93. package/dist/fetch.js.map +1 -0
  94. package/dist/fixed.d.ts +121 -0
  95. package/dist/fixed.d.ts.map +1 -0
  96. package/dist/fixed.js +420 -0
  97. package/dist/fixed.js.map +1 -0
  98. package/dist/fn.d.ts +34 -0
  99. package/dist/fn.d.ts.map +1 -0
  100. package/dist/fn.js +37 -0
  101. package/dist/fn.js.map +1 -0
  102. package/dist/format.d.ts +13 -0
  103. package/dist/format.d.ts.map +1 -0
  104. package/dist/format.js +90 -0
  105. package/dist/format.js.map +1 -0
  106. package/dist/generated/adyen.d.ts +3 -0
  107. package/dist/generated/adyen.d.ts.map +1 -0
  108. package/dist/generated/adyen.js +144 -0
  109. package/dist/generated/adyen.js.map +1 -0
  110. package/dist/generated/braintree.d.ts +3 -0
  111. package/dist/generated/braintree.d.ts.map +1 -0
  112. package/dist/generated/braintree.js +140 -0
  113. package/dist/generated/braintree.js.map +1 -0
  114. package/dist/generated/cash.d.ts +14 -0
  115. package/dist/generated/cash.d.ts.map +1 -0
  116. package/dist/generated/cash.js +465 -0
  117. package/dist/generated/cash.js.map +1 -0
  118. package/dist/generated/checkout.d.ts +3 -0
  119. package/dist/generated/checkout.d.ts.map +1 -0
  120. package/dist/generated/checkout.js +151 -0
  121. package/dist/generated/checkout.js.map +1 -0
  122. package/dist/generated/historic.d.ts +337 -0
  123. package/dist/generated/historic.d.ts.map +1 -0
  124. package/dist/generated/historic.js +66 -0
  125. package/dist/generated/historic.js.map +1 -0
  126. package/dist/generated/iso4217.d.ts +174 -0
  127. package/dist/generated/iso4217.d.ts.map +1 -0
  128. package/dist/generated/iso4217.js +175 -0
  129. package/dist/generated/iso4217.js.map +1 -0
  130. package/dist/generated/kernel.d.ts +17 -0
  131. package/dist/generated/kernel.d.ts.map +1 -0
  132. package/dist/generated/kernel.js +208 -0
  133. package/dist/generated/kernel.js.map +1 -0
  134. package/dist/generated/klarna.d.ts +3 -0
  135. package/dist/generated/klarna.d.ts.map +1 -0
  136. package/dist/generated/klarna.js +21 -0
  137. package/dist/generated/klarna.js.map +1 -0
  138. package/dist/generated/paypal.d.ts +3 -0
  139. package/dist/generated/paypal.d.ts.map +1 -0
  140. package/dist/generated/paypal.js +31 -0
  141. package/dist/generated/paypal.js.map +1 -0
  142. package/dist/generated/stripe.d.ts +8 -0
  143. package/dist/generated/stripe.d.ts.map +1 -0
  144. package/dist/generated/stripe.js +150 -0
  145. package/dist/generated/stripe.js.map +1 -0
  146. package/dist/historic.d.ts +40 -0
  147. package/dist/historic.d.ts.map +1 -0
  148. package/dist/historic.js +43 -0
  149. package/dist/historic.js.map +1 -0
  150. package/dist/history.d.ts +96 -0
  151. package/dist/history.d.ts.map +1 -0
  152. package/dist/history.js +213 -0
  153. package/dist/history.js.map +1 -0
  154. package/dist/hmrc.d.ts +28 -0
  155. package/dist/hmrc.d.ts.map +1 -0
  156. package/dist/hmrc.js +108 -0
  157. package/dist/hmrc.js.map +1 -0
  158. package/dist/index.d.ts +11 -0
  159. package/dist/index.d.ts.map +1 -0
  160. package/dist/index.js +11 -0
  161. package/dist/index.js.map +1 -0
  162. package/dist/klarna.d.ts +31 -0
  163. package/dist/klarna.d.ts.map +1 -0
  164. package/dist/klarna.js +38 -0
  165. package/dist/klarna.js.map +1 -0
  166. package/dist/kysely.d.ts +120 -0
  167. package/dist/kysely.d.ts.map +1 -0
  168. package/dist/kysely.js +309 -0
  169. package/dist/kysely.js.map +1 -0
  170. package/dist/money.d.ts +302 -0
  171. package/dist/money.d.ts.map +1 -0
  172. package/dist/money.js +703 -0
  173. package/dist/money.js.map +1 -0
  174. package/dist/parse.d.ts +55 -0
  175. package/dist/parse.d.ts.map +1 -0
  176. package/dist/parse.js +419 -0
  177. package/dist/parse.js.map +1 -0
  178. package/dist/paypal.d.ts +41 -0
  179. package/dist/paypal.d.ts.map +1 -0
  180. package/dist/paypal.js +58 -0
  181. package/dist/paypal.js.map +1 -0
  182. package/dist/pg.d.ts +100 -0
  183. package/dist/pg.d.ts.map +1 -0
  184. package/dist/pg.js +343 -0
  185. package/dist/pg.js.map +1 -0
  186. package/dist/plugins/adyen.d.ts +15 -0
  187. package/dist/plugins/adyen.d.ts.map +1 -0
  188. package/dist/plugins/adyen.js +10 -0
  189. package/dist/plugins/adyen.js.map +1 -0
  190. package/dist/plugins/all.d.ts +29 -0
  191. package/dist/plugins/all.d.ts.map +1 -0
  192. package/dist/plugins/all.js +30 -0
  193. package/dist/plugins/all.js.map +1 -0
  194. package/dist/plugins/allocate.d.ts +20 -0
  195. package/dist/plugins/allocate.d.ts.map +1 -0
  196. package/dist/plugins/allocate.js +26 -0
  197. package/dist/plugins/allocate.js.map +1 -0
  198. package/dist/plugins/braintree.d.ts +12 -0
  199. package/dist/plugins/braintree.d.ts.map +1 -0
  200. package/dist/plugins/braintree.js +12 -0
  201. package/dist/plugins/braintree.js.map +1 -0
  202. package/dist/plugins/cash.d.ts +19 -0
  203. package/dist/plugins/cash.d.ts.map +1 -0
  204. package/dist/plugins/cash.js +16 -0
  205. package/dist/plugins/cash.js.map +1 -0
  206. package/dist/plugins/checkout.d.ts +21 -0
  207. package/dist/plugins/checkout.d.ts.map +1 -0
  208. package/dist/plugins/checkout.js +16 -0
  209. package/dist/plugins/checkout.js.map +1 -0
  210. package/dist/plugins/convert.d.ts +19 -0
  211. package/dist/plugins/convert.d.ts.map +1 -0
  212. package/dist/plugins/convert.js +13 -0
  213. package/dist/plugins/convert.js.map +1 -0
  214. package/dist/plugins/exact.d.ts +15 -0
  215. package/dist/plugins/exact.d.ts.map +1 -0
  216. package/dist/plugins/exact.js +13 -0
  217. package/dist/plugins/exact.js.map +1 -0
  218. package/dist/plugins/fixed.d.ts +17 -0
  219. package/dist/plugins/fixed.d.ts.map +1 -0
  220. package/dist/plugins/fixed.js +13 -0
  221. package/dist/plugins/fixed.js.map +1 -0
  222. package/dist/plugins/format.d.ts +9 -0
  223. package/dist/plugins/format.d.ts.map +1 -0
  224. package/dist/plugins/format.js +16 -0
  225. package/dist/plugins/format.js.map +1 -0
  226. package/dist/plugins/klarna.d.ts +10 -0
  227. package/dist/plugins/klarna.d.ts.map +1 -0
  228. package/dist/plugins/klarna.js +10 -0
  229. package/dist/plugins/klarna.js.map +1 -0
  230. package/dist/plugins/paypal.d.ts +14 -0
  231. package/dist/plugins/paypal.d.ts.map +1 -0
  232. package/dist/plugins/paypal.js +16 -0
  233. package/dist/plugins/paypal.js.map +1 -0
  234. package/dist/plugins/prisma.d.ts +8 -0
  235. package/dist/plugins/prisma.d.ts.map +1 -0
  236. package/dist/plugins/prisma.js +13 -0
  237. package/dist/plugins/prisma.js.map +1 -0
  238. package/dist/plugins/stripe.d.ts +14 -0
  239. package/dist/plugins/stripe.d.ts.map +1 -0
  240. package/dist/plugins/stripe.js +16 -0
  241. package/dist/plugins/stripe.js.map +1 -0
  242. package/dist/plugins/tax.d.ts +20 -0
  243. package/dist/plugins/tax.d.ts.map +1 -0
  244. package/dist/plugins/tax.js +18 -0
  245. package/dist/plugins/tax.js.map +1 -0
  246. package/dist/policy.d.ts +34 -0
  247. package/dist/policy.d.ts.map +1 -0
  248. package/dist/policy.js +90 -0
  249. package/dist/policy.js.map +1 -0
  250. package/dist/prisma.d.ts +77 -0
  251. package/dist/prisma.d.ts.map +1 -0
  252. package/dist/prisma.js +76 -0
  253. package/dist/prisma.js.map +1 -0
  254. package/dist/processor.d.ts +28 -0
  255. package/dist/processor.d.ts.map +1 -0
  256. package/dist/processor.js +118 -0
  257. package/dist/processor.js.map +1 -0
  258. package/dist/provider.d.ts +103 -0
  259. package/dist/provider.d.ts.map +1 -0
  260. package/dist/provider.js +280 -0
  261. package/dist/provider.js.map +1 -0
  262. package/dist/rate-text.d.ts +38 -0
  263. package/dist/rate-text.d.ts.map +1 -0
  264. package/dist/rate-text.js +143 -0
  265. package/dist/rate-text.js.map +1 -0
  266. package/dist/rate.d.ts +175 -0
  267. package/dist/rate.d.ts.map +1 -0
  268. package/dist/rate.js +371 -0
  269. package/dist/rate.js.map +1 -0
  270. package/dist/rounding-error.d.ts +9 -0
  271. package/dist/rounding-error.d.ts.map +1 -0
  272. package/dist/rounding-error.js +9 -0
  273. package/dist/rounding-error.js.map +1 -0
  274. package/dist/rounding.d.ts +50 -0
  275. package/dist/rounding.d.ts.map +1 -0
  276. package/dist/rounding.js +87 -0
  277. package/dist/rounding.js.map +1 -0
  278. package/dist/schema.d.ts +43 -0
  279. package/dist/schema.d.ts.map +1 -0
  280. package/dist/schema.js +77 -0
  281. package/dist/schema.js.map +1 -0
  282. package/dist/sql.d.ts +54 -0
  283. package/dist/sql.d.ts.map +1 -0
  284. package/dist/sql.js +131 -0
  285. package/dist/sql.js.map +1 -0
  286. package/dist/stripe-fx.d.ts +22 -0
  287. package/dist/stripe-fx.d.ts.map +1 -0
  288. package/dist/stripe-fx.js +30 -0
  289. package/dist/stripe-fx.js.map +1 -0
  290. package/dist/stripe.d.ts +36 -0
  291. package/dist/stripe.d.ts.map +1 -0
  292. package/dist/stripe.js +39 -0
  293. package/dist/stripe.js.map +1 -0
  294. package/dist/tax.d.ts +33 -0
  295. package/dist/tax.d.ts.map +1 -0
  296. package/dist/tax.js +55 -0
  297. package/dist/tax.js.map +1 -0
  298. package/dist/testing/arbitraries.d.ts +43 -0
  299. package/dist/testing/arbitraries.d.ts.map +1 -0
  300. package/dist/testing/arbitraries.js +98 -0
  301. package/dist/testing/arbitraries.js.map +1 -0
  302. package/dist/testing/index.d.ts +67 -0
  303. package/dist/testing/index.d.ts.map +1 -0
  304. package/dist/testing/index.js +159 -0
  305. package/dist/testing/index.js.map +1 -0
  306. package/dist/testing/jest.d.ts +2 -0
  307. package/dist/testing/jest.d.ts.map +1 -0
  308. package/dist/testing/jest.js +15 -0
  309. package/dist/testing/jest.js.map +1 -0
  310. package/dist/testing/vitest.d.ts +7 -0
  311. package/dist/testing/vitest.d.ts.map +1 -0
  312. package/dist/testing/vitest.js +12 -0
  313. package/dist/testing/vitest.js.map +1 -0
  314. package/dist/valibot.d.ts +33 -0
  315. package/dist/valibot.d.ts.map +1 -0
  316. package/dist/valibot.js +61 -0
  317. package/dist/valibot.js.map +1 -0
  318. package/dist/zod.d.ts +36 -0
  319. package/dist/zod.d.ts.map +1 -0
  320. package/dist/zod.js +58 -0
  321. package/dist/zod.js.map +1 -0
  322. package/package.json +280 -5
  323. package/src/adyen-fx.ts +175 -0
  324. package/src/adyen.ts +46 -0
  325. package/src/allocate.ts +393 -0
  326. package/src/bag.ts +170 -0
  327. package/src/boc.ts +136 -0
  328. package/src/boe.ts +131 -0
  329. package/src/braintree.ts +71 -0
  330. package/src/cash.ts +183 -0
  331. package/src/checkout.ts +77 -0
  332. package/src/convert.ts +177 -0
  333. package/src/currency.ts +61 -0
  334. package/src/decimal.ts +283 -0
  335. package/src/drizzle/mysql.ts +78 -0
  336. package/src/drizzle/pg.ts +78 -0
  337. package/src/drizzle/sqlite.ts +70 -0
  338. package/src/ecb.ts +328 -0
  339. package/src/exact.ts +182 -0
  340. package/src/fed.ts +146 -0
  341. package/src/fetch.ts +306 -0
  342. package/src/fixed.ts +558 -0
  343. package/src/fn.ts +94 -0
  344. package/src/format.ts +106 -0
  345. package/src/generated/adyen.ts +144 -0
  346. package/src/generated/braintree.ts +140 -0
  347. package/src/generated/cash.ts +478 -0
  348. package/src/generated/checkout.ts +151 -0
  349. package/src/generated/historic.ts +67 -0
  350. package/src/generated/iso4217.ts +179 -0
  351. package/src/generated/kernel.ts +230 -0
  352. package/src/generated/klarna.ts +21 -0
  353. package/src/generated/paypal.ts +31 -0
  354. package/src/generated/stripe.ts +150 -0
  355. package/src/historic.ts +77 -0
  356. package/src/history.ts +333 -0
  357. package/src/hmrc.ts +125 -0
  358. package/src/index.ts +41 -0
  359. package/src/klarna.ts +54 -0
  360. package/src/kysely.ts +588 -0
  361. package/src/money.ts +979 -0
  362. package/src/parse.ts +511 -0
  363. package/src/paypal.ts +93 -0
  364. package/src/pg.ts +410 -0
  365. package/src/plugins/adyen.ts +25 -0
  366. package/src/plugins/all.ts +57 -0
  367. package/src/plugins/allocate.ts +53 -0
  368. package/src/plugins/braintree.ts +23 -0
  369. package/src/plugins/cash.ts +33 -0
  370. package/src/plugins/checkout.ts +32 -0
  371. package/src/plugins/convert.ts +49 -0
  372. package/src/plugins/exact.ts +23 -0
  373. package/src/plugins/fixed.ts +28 -0
  374. package/src/plugins/format.ts +28 -0
  375. package/src/plugins/klarna.ts +21 -0
  376. package/src/plugins/paypal.ts +29 -0
  377. package/src/plugins/prisma.ts +24 -0
  378. package/src/plugins/stripe.ts +29 -0
  379. package/src/plugins/tax.ts +40 -0
  380. package/src/policy.ts +124 -0
  381. package/src/prisma.ts +199 -0
  382. package/src/processor.ts +181 -0
  383. package/src/provider.ts +389 -0
  384. package/src/rate-text.ts +151 -0
  385. package/src/rate.ts +546 -0
  386. package/src/rounding-error.ts +8 -0
  387. package/src/rounding.ts +122 -0
  388. package/src/schema.ts +119 -0
  389. package/src/sql.ts +178 -0
  390. package/src/stripe-fx.ts +49 -0
  391. package/src/stripe.ts +69 -0
  392. package/src/tax.ts +102 -0
  393. package/src/testing/arbitraries.ts +134 -0
  394. package/src/testing/index.ts +247 -0
  395. package/src/testing/jest.ts +18 -0
  396. package/src/testing/vitest.ts +18 -0
  397. package/src/valibot.ts +87 -0
  398. package/src/zod.ts +78 -0
@@ -0,0 +1,95 @@
1
+ {
2
+ "processor": "Klarna",
3
+ "retrieved": "2026-11-07",
4
+ "amountFormat": "integer",
5
+ "sources": {
6
+ "dataTypes": {
7
+ "url": "https://docs.klarna.com/acquirer/klarna/get-started/integration-resilience/data-types/",
8
+ "quotes": [
9
+ "We express amounts in minor units according to the ISO 4217 standard. That means they are expressed in the smallest unit of currency. Examples are USD with 1000 representing USD GBP 10, with 500 representing GBP EUR 5, with 50 representing EUR 0.50 and SEK with 100 representing 1kr.",
10
+ "{\"order_amount\": 1000}"
11
+ ]
12
+ },
13
+ "countries": {
14
+ "url": "https://docs.klarna.com/klarna-payments/in-depth-knowledge/puchase-countries-currencies-locales/",
15
+ "quotes": [
16
+ "We only support the local currency of each country.",
17
+ "The following table shows the list of available countries, locales, and currencies for Klarna payments."
18
+ ]
19
+ },
20
+ "api": {
21
+ "url": "https://docs.klarna.com/acquirer/klarna/api/payments/",
22
+ "quotes": [
23
+ "order_amount: {\"type\": \"integer\", \"format\": \"int64\", \"example\": 2000, \"minimum\": 0} Total amount of the order including tax and any available discounts. The value should be in non-negative minor units. Eg: 25 Euros should be 2500.",
24
+ "order_lines[].total_amount: Total amount of the order line. Must be defined as minor units. Includes tax and discount. Eg: 2000=20 euros\nValue = (quantity x unit_price) - total_discount_amount. \n(max value: 200000000)",
25
+ "order_lines[].tax_rate: {\"type\": \"integer\", \"minimum\": 0, \"maximum\": 10000} Tax rate of the order line. Non-negative value. The percentage value is represented with two implicit decimals. I.e 2000 = 20%.",
26
+ "purchase_currency: The purchase currency of the order. Formatted according to ISO 4217 standard, e.g. USD, EUR, SEK, GBP, etc.",
27
+ "order_lines[].total_tax_amount: Total tax amount of the order line. Must be within ±1 of total_amount - total_amount 10000 / (10000 + tax_rate). Negative when type is discount.",
28
+ "order_lines[].unit_price: Price for a single unit of the order line. Must be defined as minor units and exclude any discount."
29
+ ]
30
+ }
31
+ },
32
+ "defaultExponent": "iso",
33
+ "currencies": [
34
+ "AUD",
35
+ "CAD",
36
+ "CHF",
37
+ "CZK",
38
+ "DKK",
39
+ "EUR",
40
+ "GBP",
41
+ "HUF",
42
+ "MXN",
43
+ "NOK",
44
+ "NZD",
45
+ "PLN",
46
+ "RON",
47
+ "SEK",
48
+ "USD"
49
+ ],
50
+ "countryCurrency": {
51
+ "AU": "AUD",
52
+ "AT": "EUR",
53
+ "BE": "EUR",
54
+ "CA": "CAD",
55
+ "CZ": "CZK",
56
+ "DK": "DKK",
57
+ "FI": "EUR",
58
+ "FR": "EUR",
59
+ "DE": "EUR",
60
+ "GR": "EUR",
61
+ "HU": "HUF",
62
+ "IE": "EUR",
63
+ "IT": "EUR",
64
+ "MX": "MXN",
65
+ "NL": "EUR",
66
+ "NZ": "NZD",
67
+ "NO": "NOK",
68
+ "PL": "PLN",
69
+ "PT": "EUR",
70
+ "RO": "RON",
71
+ "SK": "EUR",
72
+ "ES": "EUR",
73
+ "SE": "SEK",
74
+ "CH": "CHF",
75
+ "GB": "GBP",
76
+ "US": "USD"
77
+ },
78
+ "notes": [
79
+ "Amounts are integers in ISO 4217 minor units for every supported currency; all 15 are two-decimal in ISO, so HUF is in fillér (1000 HUF = 100000), unlike PayPal (HUF takes no decimals).",
80
+ "The data-types sentence is quoted as published; its examples read: USD 1000 = USD 10, GBP 500 = GBP 5, EUR 50 = EUR 0.50, SEK 100 = 1 kr.",
81
+ "Each purchase country has exactly one currency; the pairing is not checked by ducat.",
82
+ "Limits (order_amount >= 0; an order line's total_amount at most 200000000) are not enforced by ducat.",
83
+ "Signs: order_amount, order_tax_amount and total_discount_amount have minimum 0; order-line unit_price and total_amount have no minimum, and total_tax_amount is negative for discount lines. toKlarna therefore passes negative amounts through."
84
+ ],
85
+ "unverified": [
86
+ {
87
+ "claim": "HUF is sent in fillér (2 decimals, per the ISO 4217 statement); no Klarna page gives a HUF example.",
88
+ "verified": false
89
+ },
90
+ {
91
+ "claim": "Captures and refunds (Order Management API) use the same integer minor units (the reference page renders its schema client-side; only the Payments schema was read).",
92
+ "verified": false
93
+ }
94
+ ]
95
+ }
@@ -0,0 +1,65 @@
1
+ {
2
+ "processor": "PayPal",
3
+ "retrieved": "2026-11-07",
4
+ "amountFormat": "decimal-string",
5
+ "sources": {
6
+ "currencies": {
7
+ "url": "https://developer.paypal.com/api/rest/reference/currency-codes/",
8
+ "lastUpdated": "2026-08-17",
9
+ "quotes": [
10
+ "This currency does not support decimals. If you pass a decimal amount, an error occurs.",
11
+ "This currency is supported as a payment currency and a currency balance for in-country PayPal accounts only. If the receiver of funds is not from Brazil, then PayPal converts funds into the primary holding currency of the account with the applicable currency conversion rate. The currency conversion rate includes PayPal's applicable spread or fee.",
12
+ "This currency is supported as a payment currency and a currency balance for in-country PayPal accounts only."
13
+ ]
14
+ },
15
+ "currencyReference": {
16
+ "url": "https://developer.paypal.com/reference/currency-codes/",
17
+ "lastUpdated": "2026-08-17",
18
+ "quotes": [
19
+ "Zero-digit currency — no decimal places or fractions",
20
+ "This currency is supported as a payment currency (buyer currency) or settlement currency (holding currency) only for in-country PayPal accounts. If the settlement account is based outside the country, PayPal converts money into the account's primary currency with the applicable currency conversion rate, which includes a spread or fee."
21
+ ]
22
+ },
23
+ "orders": {
24
+ "url": "https://developer.paypal.com/api/orders/v2/schema.yaml",
25
+ "quotes": [
26
+ "money.value: The value, which might be: An integer for currencies like `JPY` that are not typically fractional. A decimal fraction for currencies like `TND` that are subdivided into thousandths. For the required number of decimal places for a currency code, see Currency Codes.",
27
+ "money.value: {\"type\": \"string\", \"minLength\": 0, \"maxLength\": 32, \"pattern\": \"^((-?[0-9]+)|(-?([0-9]+)?[.][0-9]+))$\"}",
28
+ "The amount must be a positive number. The `amount.value` field supports up to 15 digits preceding the decimal.",
29
+ "Create Order - Minimal Request and Response: {\"currency_code\": \"USD\", \"value\": \"100.00\"}",
30
+ "amount {\"currency_code\": \"USD\", \"value\": \"230.00\"}, breakdown item_total \"220.00\", shipping \"10.00\"; items unit_amount \"20.00\" x quantity \"1\" and \"100.00\" x quantity \"2\""
31
+ ]
32
+ }
33
+ },
34
+ "defaultExponent": "iso",
35
+ "exponents": {
36
+ "HUF": 0,
37
+ "JPY": 0,
38
+ "TWD": 0
39
+ },
40
+ "currencies": [
41
+ "AUD", "BRL", "CAD", "CHF", "CNY", "CZK", "DKK", "EUR", "GBP", "HKD", "HUF", "ILS", "JPY",
42
+ "MXN", "MYR", "NOK", "NZD", "PHP", "PLN", "RUB", "SEK", "SGD", "THB", "TWD", "USD"
43
+ ],
44
+ "inCountryOnly": ["BRL", "CNY", "MYR"],
45
+ "notes": [
46
+ "The amount is a decimal string in major units. HUF and TWD (ISO 2 decimals) and JPY must be whole numbers; every other listed currency is two-decimal, as in ISO 4217.",
47
+ "The Orders schema mentions TND (three decimals) as an example, but TND is not on either currency page, so it is not accepted here.",
48
+ "The two currency pages disagree: the REST reference page (linked from the Orders schema) lists RUB; the general reference page does not.",
49
+ "The schema pattern allows a leading minus and a bare fraction such as \".5\"; the text says the amount must be positive. ducat emits a leading 0 and does not enforce the sign."
50
+ ],
51
+ "unverified": [
52
+ {
53
+ "claim": "A zero fraction such as \"100.00\" for JPY, HUF or TWD is rejected (the page says only that a decimal amount is an error). toPayPal always sends whole numbers for these.",
54
+ "verified": false
55
+ },
56
+ {
57
+ "claim": "RUB is still accepted (listed on the REST reference page only).",
58
+ "verified": false
59
+ },
60
+ {
61
+ "claim": "Payouts use the same currency rules (no Payouts-specific currency page was found).",
62
+ "verified": false
63
+ }
64
+ ]
65
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "source": "https://docs.stripe.com/api/balance_transactions/object",
3
+ "retrieved": "2026-11-07",
4
+ "quotes": {
5
+ "exchange_rate": "If applicable, this transaction uses an exchange rate. If money converts from currency A to currency B, then the `amount` in currency A, multiplied by the `exchange_rate`, equals the `amount` in currency B. For example, if you charge a customer 10.00 EUR, the PaymentIntent's `amount` is `1000` and `currency` is `eur`. If this converts to 12.34 USD in your Stripe account, the BalanceTransaction's `amount` is `1234`, its `currency` is `usd`, and the `exchange_rate` is `1.234`.",
6
+ "amount": "Gross amount of this transaction (in the smallest currency unit). A positive value represents funds charged to another party, and a negative value represents funds sent to another party.",
7
+ "currency": "Three-letter ISO currency code, in lowercase. Must be a supported currency.",
8
+ "created": "Time at which the object was created. Measured in seconds since the Unix epoch."
9
+ },
10
+ "notes": [
11
+ "exchange_rate is a nullable JSON number; null when no conversion happened.",
12
+ "No rounding rule for conversions is documented on this page or on https://docs.stripe.com/currencies/conversions."
13
+ ],
14
+ "vectors": [
15
+ { "charge": { "amount": 1000, "currency": "eur" }, "balanceTransaction": { "amount": 1234, "currency": "usd", "exchange_rate": 1.234 } }
16
+ ]
17
+ }
@@ -0,0 +1,285 @@
1
+ {
2
+ "source": "https://docs.stripe.com/currencies",
3
+ "retrieved": "2026-11-07",
4
+ "notes": [
5
+ "Currencies are two-decimal unless listed below (\"Currencies are two-decimal currencies unless otherwise specified.\").",
6
+ "Live page: \"This list contains zero-decimal currencies that have general API support.\" Same list as the embedded zero_decimal array. ISK is NOT in it (special case, two-decimal representation).",
7
+ "No three-decimal section on the live page; list from archived 2024 version (matches the five codes that the live embedded data offers only to AE accounts).",
8
+ "Stripe requires lowercase currency codes in API requests."
9
+ ],
10
+ "defaultExponent": 2,
11
+ "zeroDecimal": [
12
+ "BIF",
13
+ "CLP",
14
+ "DJF",
15
+ "GNF",
16
+ "JPY",
17
+ "KMF",
18
+ "KRW",
19
+ "MGA",
20
+ "PYG",
21
+ "RWF",
22
+ "UGX",
23
+ "VND",
24
+ "VUV",
25
+ "XAF",
26
+ "XOF",
27
+ "XPF"
28
+ ],
29
+ "threeDecimal": [
30
+ "BHD",
31
+ "JOD",
32
+ "KWD",
33
+ "OMR",
34
+ "TND"
35
+ ],
36
+ "specialCases": {
37
+ "ISK": {
38
+ "apiExponent": 2,
39
+ "rule": "Charges: amount in hundredths, decimal part always 00 (amount % 100 == 0). No fractional ISK.",
40
+ "quote": "ISK transitioned to a zero-decimal currency, but backward compatibility requires you to represent it as a two-decimal value, where the decimal amount is always 00. For example, to charge 5 ISK, provide an amount value of 500. You can’t charge fractions of ISK."
41
+ },
42
+ "HUF": {
43
+ "apiExponent": 2,
44
+ "rule": "Charges may use two decimals; manual payouts must be integer amounts evenly divisible by 100 (whole forints).",
45
+ "quote": "Stripe treats HUF as a zero-decimal currency for payouts, even though you can charge two-decimal amounts. When you create a manual payout in HUF, you must provide integer amounts that are evenly divisible by 100. For example, if you have an available balance of HUF 10.45, you can pay out HUF 10 by submitting 1000 for the amount value. You can’t submit a payout for the full balance, HUF 10.45, because the amount value of 1045 isn’t evenly divisible by 100."
46
+ },
47
+ "TWD": {
48
+ "apiExponent": 2,
49
+ "rule": "Charges may use two decimals; manual payouts must be integer amounts evenly divisible by 100 (whole dollars).",
50
+ "quote": "Stripe treats TWD as a zero-decimal currency for payouts, even though you can charge two-decimal amounts. When you create a manual payout in TWD, you must provide integer amounts that are evenly divisible by 100. For example, if you have an available balance of TWD 800.45, you can pay out TWD 800 by submitting 80000 for the amount value. You can’t submit a payout for the full balance, TWD 800.45, because the amount value of 80045 isn’t evenly divisible by 100."
51
+ },
52
+ "UGX": {
53
+ "apiExponent": 2,
54
+ "rule": "Amount in hundredths, decimal part always 00 (amount % 100 == 0); invoices with fractional amounts are rounded to nearest multiple of 100 and the difference goes to the customer balance.",
55
+ "quote": "UGX transitioned to a zero-decimal currency, but backwards compatibility requires you to represent it as a two-decimal value, where the decimal amount is always 00. For example, to charge 5 UGX, provide an amount value of 500. You can’t charge fractions of UGX. For invoices where the amount is fractional after prorations, coupons, or taxes, Stripe automatically rounds that amount to the nearest number evenly divisible by 100. We credit or debit any difference from rounding to the customer balance.",
56
+ "note": "Contradiction on the live page: UGX is listed under \"Zero-decimal currencies\" (and in the embedded zero_decimal array), yet the Special cases row says it must be sent as a two-decimal value ending in 00 (5 UGX -> 500). The special-case text is the more specific instruction; confirm against the live API before relying on either.",
57
+ "unverified": true
58
+ },
59
+ "BHD": {
60
+ "apiExponent": 3,
61
+ "rule": "Three-decimal; last digit of amount must be 0 (amount % 10 == 0) for Payment Intents, Refunds, Disputes.",
62
+ "quote": "The API supports three-decimal currencies for the standard payment flows, including Payment Intents, Refunds, and Disputes. However, to ensure compatibility with Stripe’s payments partners, these API calls require the least-significant (last) digit to be 0. Your integration must round amounts to the nearest ten. For example, 5.124 KWD must be rounded to 5120 or 5130. Three-decimal currencies: BHD JOD KWD OMR TND",
63
+ "quoteSource": "https://web.archive.org/web/20240620024311/https://docs.stripe.com/currencies (section \"Three-decimal currencies\")",
64
+ "note": "The live page (fetched 2026-11-07) no longer has a \"Three-decimal currencies\" section; its meta description still says \"including zero-decimal and three-decimal currency support\", and the embedded presentment data lists BHD/JOD/KWD/OMR/TND only for UAE (AE) accounts. Rule quoted from the June 2024 archived version.",
65
+ "unverified": true
66
+ },
67
+ "JOD": {
68
+ "apiExponent": 3,
69
+ "rule": "Three-decimal; last digit of amount must be 0 (amount % 10 == 0) for Payment Intents, Refunds, Disputes.",
70
+ "quote": "The API supports three-decimal currencies for the standard payment flows, including Payment Intents, Refunds, and Disputes. However, to ensure compatibility with Stripe’s payments partners, these API calls require the least-significant (last) digit to be 0. Your integration must round amounts to the nearest ten. For example, 5.124 KWD must be rounded to 5120 or 5130. Three-decimal currencies: BHD JOD KWD OMR TND",
71
+ "quoteSource": "https://web.archive.org/web/20240620024311/https://docs.stripe.com/currencies (section \"Three-decimal currencies\")",
72
+ "note": "The live page (fetched 2026-11-07) no longer has a \"Three-decimal currencies\" section; its meta description still says \"including zero-decimal and three-decimal currency support\", and the embedded presentment data lists BHD/JOD/KWD/OMR/TND only for UAE (AE) accounts. Rule quoted from the June 2024 archived version.",
73
+ "unverified": true
74
+ },
75
+ "KWD": {
76
+ "apiExponent": 3,
77
+ "rule": "Three-decimal; last digit of amount must be 0 (amount % 10 == 0) for Payment Intents, Refunds, Disputes.",
78
+ "quote": "The API supports three-decimal currencies for the standard payment flows, including Payment Intents, Refunds, and Disputes. However, to ensure compatibility with Stripe’s payments partners, these API calls require the least-significant (last) digit to be 0. Your integration must round amounts to the nearest ten. For example, 5.124 KWD must be rounded to 5120 or 5130. Three-decimal currencies: BHD JOD KWD OMR TND",
79
+ "quoteSource": "https://web.archive.org/web/20240620024311/https://docs.stripe.com/currencies (section \"Three-decimal currencies\")",
80
+ "note": "The live page (fetched 2026-11-07) no longer has a \"Three-decimal currencies\" section; its meta description still says \"including zero-decimal and three-decimal currency support\", and the embedded presentment data lists BHD/JOD/KWD/OMR/TND only for UAE (AE) accounts. Rule quoted from the June 2024 archived version.",
81
+ "unverified": true
82
+ },
83
+ "OMR": {
84
+ "apiExponent": 3,
85
+ "rule": "Three-decimal; last digit of amount must be 0 (amount % 10 == 0) for Payment Intents, Refunds, Disputes.",
86
+ "quote": "The API supports three-decimal currencies for the standard payment flows, including Payment Intents, Refunds, and Disputes. However, to ensure compatibility with Stripe’s payments partners, these API calls require the least-significant (last) digit to be 0. Your integration must round amounts to the nearest ten. For example, 5.124 KWD must be rounded to 5120 or 5130. Three-decimal currencies: BHD JOD KWD OMR TND",
87
+ "quoteSource": "https://web.archive.org/web/20240620024311/https://docs.stripe.com/currencies (section \"Three-decimal currencies\")",
88
+ "note": "The live page (fetched 2026-11-07) no longer has a \"Three-decimal currencies\" section; its meta description still says \"including zero-decimal and three-decimal currency support\", and the embedded presentment data lists BHD/JOD/KWD/OMR/TND only for UAE (AE) accounts. Rule quoted from the June 2024 archived version.",
89
+ "unverified": true
90
+ },
91
+ "TND": {
92
+ "apiExponent": 3,
93
+ "rule": "Three-decimal; last digit of amount must be 0 (amount % 10 == 0) for Payment Intents, Refunds, Disputes.",
94
+ "quote": "The API supports three-decimal currencies for the standard payment flows, including Payment Intents, Refunds, and Disputes. However, to ensure compatibility with Stripe’s payments partners, these API calls require the least-significant (last) digit to be 0. Your integration must round amounts to the nearest ten. For example, 5.124 KWD must be rounded to 5120 or 5130. Three-decimal currencies: BHD JOD KWD OMR TND",
95
+ "quoteSource": "https://web.archive.org/web/20240620024311/https://docs.stripe.com/currencies (section \"Three-decimal currencies\")",
96
+ "note": "The live page (fetched 2026-11-07) no longer has a \"Three-decimal currencies\" section; its meta description still says \"including zero-decimal and three-decimal currency support\", and the embedded presentment data lists BHD/JOD/KWD/OMR/TND only for UAE (AE) accounts. Rule quoted from the June 2024 archived version.",
97
+ "unverified": true
98
+ }
99
+ },
100
+ "presentment": [
101
+ "AED",
102
+ "AFN",
103
+ "ALL",
104
+ "AMD",
105
+ "ANG",
106
+ "AOA",
107
+ "ARS",
108
+ "AUD",
109
+ "AWG",
110
+ "AZN",
111
+ "BAM",
112
+ "BBD",
113
+ "BDT",
114
+ "BHD",
115
+ "BIF",
116
+ "BMD",
117
+ "BND",
118
+ "BOB",
119
+ "BRL",
120
+ "BSD",
121
+ "BWP",
122
+ "BYN",
123
+ "BZD",
124
+ "CAD",
125
+ "CDF",
126
+ "CHF",
127
+ "CLP",
128
+ "CNY",
129
+ "COP",
130
+ "CRC",
131
+ "CVE",
132
+ "CZK",
133
+ "DJF",
134
+ "DKK",
135
+ "DOP",
136
+ "DZD",
137
+ "EGP",
138
+ "ETB",
139
+ "EUR",
140
+ "FJD",
141
+ "FKP",
142
+ "GBP",
143
+ "GEL",
144
+ "GIP",
145
+ "GMD",
146
+ "GNF",
147
+ "GTQ",
148
+ "GYD",
149
+ "HKD",
150
+ "HNL",
151
+ "HTG",
152
+ "HUF",
153
+ "IDR",
154
+ "ILS",
155
+ "INR",
156
+ "ISK",
157
+ "JMD",
158
+ "JOD",
159
+ "JPY",
160
+ "KES",
161
+ "KGS",
162
+ "KHR",
163
+ "KMF",
164
+ "KRW",
165
+ "KWD",
166
+ "KYD",
167
+ "KZT",
168
+ "LAK",
169
+ "LBP",
170
+ "LKR",
171
+ "LRD",
172
+ "LSL",
173
+ "MAD",
174
+ "MDL",
175
+ "MGA",
176
+ "MKD",
177
+ "MMK",
178
+ "MNT",
179
+ "MOP",
180
+ "MUR",
181
+ "MVR",
182
+ "MWK",
183
+ "MXN",
184
+ "MYR",
185
+ "MZN",
186
+ "NAD",
187
+ "NGN",
188
+ "NIO",
189
+ "NOK",
190
+ "NPR",
191
+ "NZD",
192
+ "OMR",
193
+ "PAB",
194
+ "PEN",
195
+ "PGK",
196
+ "PHP",
197
+ "PKR",
198
+ "PLN",
199
+ "PYG",
200
+ "QAR",
201
+ "RON",
202
+ "RSD",
203
+ "RUB",
204
+ "RWF",
205
+ "SAR",
206
+ "SBD",
207
+ "SCR",
208
+ "SEK",
209
+ "SGD",
210
+ "SHP",
211
+ "SLE",
212
+ "SOS",
213
+ "SRD",
214
+ "STD",
215
+ "SZL",
216
+ "THB",
217
+ "TJS",
218
+ "TND",
219
+ "TOP",
220
+ "TRY",
221
+ "TTD",
222
+ "TWD",
223
+ "TZS",
224
+ "UAH",
225
+ "UGX",
226
+ "USD",
227
+ "UYU",
228
+ "UZS",
229
+ "VND",
230
+ "VUV",
231
+ "WST",
232
+ "XAF",
233
+ "XCD",
234
+ "XCG",
235
+ "XOF",
236
+ "XPF",
237
+ "YER",
238
+ "ZAR",
239
+ "ZMW"
240
+ ],
241
+ "presentmentNotes": {
242
+ "count": 139,
243
+ "union": "Union over all 45 account countries in the page's embedded SupportedPresentmentCurrencies data. 134 codes for every country except AE, which additionally has BHD, JOD, KWD, OMR, TND.",
244
+ "noAmexSupport": [
245
+ "AFN",
246
+ "AOA",
247
+ "ARS",
248
+ "BOB",
249
+ "BRL",
250
+ "CLP",
251
+ "COP",
252
+ "CRC",
253
+ "CVE",
254
+ "DJF",
255
+ "FKP",
256
+ "GNF",
257
+ "GTQ",
258
+ "HNL",
259
+ "LAK",
260
+ "MUR",
261
+ "NIO",
262
+ "PAB",
263
+ "PEN",
264
+ "PYG",
265
+ "SHP",
266
+ "SRD",
267
+ "STD",
268
+ "SVC",
269
+ "UYU",
270
+ "XOF",
271
+ "XPF"
272
+ ],
273
+ "noAmexSupportCountries": [
274
+ "AE",
275
+ "BR",
276
+ "MY",
277
+ "TH"
278
+ ],
279
+ "nonIsoOrWithdrawn": {
280
+ "ANG": "ISO withdrew ANG 2025-03 (Curaçao and Sint Maarten moved to XCG); Stripe lists both ANG and XCG.",
281
+ "STD": "ISO withdrew STD 2017-12 (replaced by STN); Stripe still lists STD, not STN."
282
+ },
283
+ "casing": "Stripe requires lowercase codes in API requests."
284
+ }
285
+ }
@@ -0,0 +1,25 @@
1
+ import { type Rate } from './rate.js';
2
+ /** Options for adyenRate. */
3
+ export interface AdyenRateOptions {
4
+ /**
5
+ * The account's IANA time zone ('Europe/Amsterdam'). When given, Creation Date is read in it,
6
+ * summer time included, and the TimeZone column is not used.
7
+ */
8
+ readonly timeZone?: string;
9
+ }
10
+ /** A settlement details report row, keyed by column name (as from a CSV parser with headers). */
11
+ export type AdyenSettlementRow = Readonly<Record<string, string | undefined>>;
12
+ /**
13
+ * The rate in a settlement details report row: "The exchange rate used for converting the gross
14
+ * amount into the net amount", Gross Currency → Net Currency (1 when they are the same). The
15
+ * decimal string is kept exactly. `asOf` comes from Creation Date, which Adyen gives in local time,
16
+ * with the zone in the TimeZone column. Pass `{ timeZone: 'Europe/Amsterdam' }` (the account's IANA
17
+ * zone) to read it correctly all year. Without it, an unambiguous abbreviation (CET, PST, ...) or
18
+ * offset (+01:00) is taken literally: Adyen's documentation doesn't say whether the column switches
19
+ * to CEST in summer, and if it doesn't, a literal CET is an hour off then. Any other label gives
20
+ * the local day, which can be a day off from UTC. `undefined` when the row has no rate. For
21
+ * externally settled payments Adyen lists its reference rate, not the acquirer's, so check those
22
+ * with impliedRate().
23
+ */
24
+ export declare function adyenRate(row: AdyenSettlementRow, options?: AdyenRateOptions): Rate | undefined;
25
+ //# sourceMappingURL=adyen-fx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adyen-fx.d.ts","sourceRoot":"","sources":["../src/adyen-fx.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,IAAI,EAAiB,MAAM,WAAW,CAAC;AAkInE,6BAA6B;AAC7B,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,iGAAiG;AACjG,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;AAE9E;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,CAmB/F"}
@@ -0,0 +1,140 @@
1
+ // Adyen exchange rates as exact Rates, from settlement details report rows.
2
+ import { exchangeRate } from './rate.js';
3
+ // UTC offsets, in minutes, of the zone abbreviations that name one offset. Ambiguous ones are left
4
+ // out on purpose: IST is India, Ireland or Israel; CST is US Central or China; BST is British or
5
+ // Bangladesh.
6
+ const ZONE_OFFSET_MINUTES = {
7
+ UTC: 0,
8
+ GMT: 0,
9
+ WET: 0,
10
+ WEST: 60,
11
+ CET: 60,
12
+ CEST: 120,
13
+ EET: 120,
14
+ EEST: 180,
15
+ MSK: 180,
16
+ SGT: 480,
17
+ HKT: 480,
18
+ JST: 540,
19
+ KST: 540,
20
+ AEST: 600,
21
+ AEDT: 660,
22
+ NZST: 720,
23
+ NZDT: 780,
24
+ EST: -300,
25
+ EDT: -240,
26
+ MST: -420,
27
+ MDT: -360,
28
+ PST: -480,
29
+ PDT: -420,
30
+ };
31
+ const LOCAL_TIME = /^(\d{4}-\d\d-\d\d)[ T](\d\d:\d\d(?::\d\d(?:\.\d+)?)?)$/;
32
+ const NUMERIC_OFFSET = /^(?:UTC|GMT)?\s*([+-])(\d{1,2})(?::?(\d\d))?$/;
33
+ // Real UTC offsets run from -12:00 to +14:00.
34
+ const MAX_OFFSET_MINUTES = 14 * 60;
35
+ /** The zone's offset in minutes, or undefined when it can't be read unambiguously. */
36
+ function offsetMinutes(zone) {
37
+ const named = ZONE_OFFSET_MINUTES[zone.toUpperCase()];
38
+ if (named !== undefined) {
39
+ return named;
40
+ }
41
+ const numeric = NUMERIC_OFFSET.exec(zone);
42
+ if (numeric === null) {
43
+ return undefined;
44
+ }
45
+ const hours = Number(numeric[2]);
46
+ const minutes = Number(numeric[3] ?? 0);
47
+ const total = hours * 60 + minutes;
48
+ if (minutes >= 60 || total > MAX_OFFSET_MINUTES) {
49
+ return undefined;
50
+ }
51
+ return numeric[1] === '-' ? -total : total;
52
+ }
53
+ // Building an Intl.DateTimeFormat is far slower than using one, and a report has thousands of rows
54
+ // in one zone, so keep one formatter per zone. The bound stops a stream of distinct zone names
55
+ // (case variants are accepted by Intl) from growing the cache without limit.
56
+ const MAX_CACHED_FORMATTERS = 32;
57
+ const formatters = new Map();
58
+ /** The cached wall-clock formatter for an IANA time zone. */
59
+ function wallClockFormatter(timeZone) {
60
+ let formatter = formatters.get(timeZone);
61
+ if (formatter !== undefined) {
62
+ return formatter;
63
+ }
64
+ formatter = new Intl.DateTimeFormat('en-US', {
65
+ timeZone,
66
+ hourCycle: 'h23',
67
+ year: 'numeric',
68
+ month: 'numeric',
69
+ day: 'numeric',
70
+ hour: 'numeric',
71
+ minute: 'numeric',
72
+ second: 'numeric',
73
+ });
74
+ if (formatters.size >= MAX_CACHED_FORMATTERS) {
75
+ formatters.clear();
76
+ }
77
+ formatters.set(timeZone, formatter);
78
+ return formatter;
79
+ }
80
+ /** The offset of an IANA time zone at a UTC instant, in minutes. */
81
+ function ianaOffsetMinutes(timeZone, utcMs) {
82
+ const parts = wallClockFormatter(timeZone).formatToParts(new Date(utcMs));
83
+ const field = (type) => Number(parts.find((part) => part.type === type).value);
84
+ const wallClockAsUtc = Date.UTC(field('year'), field('month') - 1, field('day'), field('hour'), field('minute'), field('second'));
85
+ return Math.round((wallClockAsUtc - Math.floor(utcMs / 1000) * 1000) / 60_000);
86
+ }
87
+ /** The UTC instant of a wall-clock time in an IANA zone, summer time included. */
88
+ function ianaToUtc(localAsUtcMs, timeZone) {
89
+ // The offset at the guess can differ from the offset at the answer across a clock change, so
90
+ // look it up again at the first answer.
91
+ const firstGuess = localAsUtcMs - ianaOffsetMinutes(timeZone, localAsUtcMs) * 60_000;
92
+ return localAsUtcMs - ianaOffsetMinutes(timeZone, firstGuess) * 60_000;
93
+ }
94
+ /** Creation Date as a UTC instant when its zone is known; otherwise its local day. */
95
+ function creationAsOf(created, label, timeZone) {
96
+ const local = LOCAL_TIME.exec(created.trim());
97
+ if (local === null) {
98
+ return /^\d{4}-\d\d-\d\d/.test(created) ? created.slice(0, 10) : undefined;
99
+ }
100
+ const localAsUtcMs = Date.parse(`${local[1]}T${local[2]}Z`);
101
+ if (timeZone !== undefined) {
102
+ return new Date(ianaToUtc(localAsUtcMs, timeZone)).toISOString();
103
+ }
104
+ const offset = label === undefined ? undefined : offsetMinutes(label.trim());
105
+ if (offset === undefined) {
106
+ return local[1];
107
+ }
108
+ return new Date(localAsUtcMs - offset * 60_000).toISOString();
109
+ }
110
+ /**
111
+ * The rate in a settlement details report row: "The exchange rate used for converting the gross
112
+ * amount into the net amount", Gross Currency → Net Currency (1 when they are the same). The
113
+ * decimal string is kept exactly. `asOf` comes from Creation Date, which Adyen gives in local time,
114
+ * with the zone in the TimeZone column. Pass `{ timeZone: 'Europe/Amsterdam' }` (the account's IANA
115
+ * zone) to read it correctly all year. Without it, an unambiguous abbreviation (CET, PST, ...) or
116
+ * offset (+01:00) is taken literally: Adyen's documentation doesn't say whether the column switches
117
+ * to CEST in summer, and if it doesn't, a literal CET is an hour off then. Any other label gives
118
+ * the local day, which can be a day off from UTC. `undefined` when the row has no rate. For
119
+ * externally settled payments Adyen lists its reference rate, not the acquirer's, so check those
120
+ * with impliedRate().
121
+ */
122
+ export function adyenRate(row, options) {
123
+ const gross = row['Gross Currency'];
124
+ const net = row['Net Currency'];
125
+ const rate = row['Exchange Rate']?.trim();
126
+ if (gross === undefined || gross === '' || net === undefined || net === '') {
127
+ return undefined;
128
+ }
129
+ if (rate === undefined || rate === '') {
130
+ return undefined;
131
+ }
132
+ const created = row['Creation Date'];
133
+ let info = { source: 'adyen' };
134
+ const asOf = created === undefined ? undefined : creationAsOf(created, row['TimeZone'], options?.timeZone);
135
+ if (asOf !== undefined) {
136
+ info = { source: 'adyen', asOf };
137
+ }
138
+ return exchangeRate(gross, net, rate, info);
139
+ }
140
+ //# sourceMappingURL=adyen-fx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adyen-fx.js","sourceRoot":"","sources":["../src/adyen-fx.ts"],"names":[],"mappings":"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"}