@openmrs/esm-billing-app 1.1.2-pre.9 → 1.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 (390) hide show
  1. package/.turbo/cache/31f1dfc7f71601df-meta.json +1 -0
  2. package/.turbo/cache/31f1dfc7f71601df.tar.zst +0 -0
  3. package/.turbo/turbo-build.log +13 -42
  4. package/__mocks__/bills.mock.ts +3 -2
  5. package/dist/1480.js +1 -0
  6. package/dist/1480.js.map +1 -0
  7. package/dist/1564.js +1 -0
  8. package/dist/1564.js.map +1 -0
  9. package/dist/1578.js +1 -0
  10. package/dist/1578.js.map +1 -0
  11. package/dist/1646.js +1 -0
  12. package/dist/1646.js.map +1 -0
  13. package/dist/1869.js +1 -0
  14. package/dist/1869.js.map +1 -0
  15. package/dist/1877.js +1 -0
  16. package/dist/1877.js.map +1 -0
  17. package/dist/1899.js +1 -0
  18. package/dist/1899.js.map +1 -0
  19. package/dist/196.js +2 -0
  20. package/dist/196.js.map +1 -0
  21. package/dist/2250.js +43 -0
  22. package/dist/2250.js.map +1 -0
  23. package/dist/2269.js +1 -0
  24. package/dist/2269.js.map +1 -0
  25. package/dist/2317.js +1 -0
  26. package/dist/2317.js.map +1 -0
  27. package/dist/2416.js +1 -0
  28. package/dist/2416.js.map +1 -0
  29. package/dist/2489.js +1 -0
  30. package/dist/2489.js.map +1 -0
  31. package/dist/282.js +1 -0
  32. package/dist/282.js.map +1 -0
  33. package/dist/2881.js +1 -0
  34. package/dist/2881.js.map +1 -0
  35. package/dist/2997.js +1 -0
  36. package/dist/2997.js.map +1 -0
  37. package/dist/3378.js +1 -0
  38. package/dist/3378.js.map +1 -0
  39. package/dist/3379.js +1 -0
  40. package/dist/3379.js.map +1 -0
  41. package/dist/3784.js +1 -0
  42. package/dist/3784.js.map +1 -0
  43. package/dist/3963.js +1 -0
  44. package/dist/3963.js.map +1 -0
  45. package/dist/4106.js +1 -0
  46. package/dist/4106.js.map +1 -0
  47. package/dist/4111.js +1 -0
  48. package/dist/4111.js.map +1 -0
  49. package/dist/434.js +1 -0
  50. package/dist/434.js.map +1 -0
  51. package/dist/4348.js +1 -0
  52. package/dist/4348.js.map +1 -0
  53. package/dist/4383.js +1 -0
  54. package/dist/4383.js.map +1 -0
  55. package/dist/4658.js +1 -0
  56. package/dist/4658.js.map +1 -0
  57. package/dist/4870.js +1 -0
  58. package/dist/4870.js.map +1 -0
  59. package/dist/4928.js +1 -0
  60. package/dist/4928.js.map +1 -0
  61. package/dist/5098.js +1 -0
  62. package/dist/5098.js.map +1 -0
  63. package/dist/5117.js +1 -0
  64. package/dist/5117.js.map +1 -0
  65. package/dist/5132.js +1 -0
  66. package/dist/5132.js.map +1 -0
  67. package/dist/5145.js +1 -0
  68. package/dist/5145.js.map +1 -0
  69. package/dist/5390.js +1 -0
  70. package/dist/5390.js.map +1 -0
  71. package/dist/5503.js +1 -0
  72. package/dist/5503.js.map +1 -0
  73. package/dist/556.js +1 -0
  74. package/dist/556.js.map +1 -0
  75. package/dist/5644.js +1 -0
  76. package/dist/5644.js.map +1 -0
  77. package/dist/5898.js +1 -0
  78. package/dist/5898.js.map +1 -0
  79. package/dist/5940.js +1 -0
  80. package/dist/5940.js.map +1 -0
  81. package/dist/6047.js +1 -0
  82. package/dist/6047.js.map +1 -0
  83. package/dist/6237.js +1 -0
  84. package/dist/6237.js.map +1 -0
  85. package/dist/6362.js +1 -0
  86. package/dist/6362.js.map +1 -0
  87. package/dist/6371.js +1 -0
  88. package/dist/6371.js.map +1 -0
  89. package/dist/6377.js +1 -0
  90. package/dist/6377.js.map +1 -0
  91. package/dist/6444.js +1 -0
  92. package/dist/6444.js.map +1 -0
  93. package/dist/6508.js +1 -0
  94. package/dist/6508.js.map +1 -0
  95. package/dist/6594.js +1 -0
  96. package/dist/6594.js.map +1 -0
  97. package/dist/6724.js +1 -0
  98. package/dist/6724.js.map +1 -0
  99. package/dist/6904.js +1 -0
  100. package/dist/6904.js.map +1 -0
  101. package/dist/7045.js +1 -0
  102. package/dist/7045.js.map +1 -0
  103. package/dist/7175.js +1 -0
  104. package/dist/7175.js.map +1 -0
  105. package/dist/7182.js +1 -0
  106. package/dist/7182.js.map +1 -0
  107. package/dist/7247.js +1 -0
  108. package/dist/7247.js.map +1 -0
  109. package/dist/7742.js +1 -0
  110. package/dist/7742.js.map +1 -0
  111. package/dist/7912.js +1 -0
  112. package/dist/7912.js.map +1 -0
  113. package/dist/8358.js +1 -0
  114. package/dist/8358.js.map +1 -0
  115. package/dist/8359.js +1 -0
  116. package/dist/8359.js.map +1 -0
  117. package/dist/8695.js +1 -0
  118. package/dist/8695.js.map +1 -0
  119. package/dist/903.js +1 -0
  120. package/dist/903.js.map +1 -0
  121. package/dist/9072.js +1 -0
  122. package/dist/9072.js.map +1 -0
  123. package/dist/9414.js +1 -0
  124. package/dist/9414.js.map +1 -0
  125. package/dist/9655.js +11 -0
  126. package/dist/9655.js.map +1 -0
  127. package/dist/9806.js +1 -0
  128. package/dist/9806.js.map +1 -0
  129. package/dist/990.js +1 -0
  130. package/dist/990.js.map +1 -0
  131. package/dist/main.js +17 -2
  132. package/dist/main.js.map +1 -1
  133. package/dist/openmrs-esm-billing-app.js +6 -1
  134. package/dist/openmrs-esm-billing-app.js.buildmanifest.json +643 -436
  135. package/dist/openmrs-esm-billing-app.js.map +1 -1
  136. package/dist/routes.json +1 -1
  137. package/e2e/commands/billing-operations.ts +21 -0
  138. package/e2e/commands/types.ts +9 -1
  139. package/e2e/pages/discounts-page.ts +75 -0
  140. package/e2e/pages/index.ts +1 -0
  141. package/e2e/pages/invoice-page.ts +7 -7
  142. package/e2e/specs/bill-discounts.spec.ts +255 -0
  143. package/e2e/specs/billing-dashboard.spec.ts +3 -3
  144. package/e2e/specs/billing-patient-chart.spec.ts +2 -2
  145. package/package.json +13 -22
  146. package/rspack.config.js +1 -0
  147. package/src/bill-history/bill-action-menu.component.tsx +20 -2
  148. package/src/bill-history/bill-history.test.tsx +23 -22
  149. package/src/bill-item-actions/edit-bill-item.modal.tsx +1 -1
  150. package/src/bill-item-actions/edit-bill-item.test.tsx +29 -27
  151. package/src/billable-services/billable-service-form/billable-service-form.test.tsx +74 -73
  152. package/src/billable-services/billable-services-home.component.tsx +4 -2
  153. package/src/billable-services/billable-services.test.tsx +8 -7
  154. package/src/billable-services/dashboard/dashboard.test.tsx +3 -2
  155. package/src/billable-services-admin-card-link.test.tsx +2 -1
  156. package/src/billing-dashboard/billing-dashboard.test.tsx +19 -3
  157. package/src/billing-form/billing-checkin-form.component.tsx +7 -3
  158. package/src/billing-form/billing-checkin-form.test.tsx +22 -21
  159. package/src/billing-form/billing-form.resource.test.ts +7 -6
  160. package/src/billing-form/billing-form.test.tsx +77 -40
  161. package/src/billing-form/billing-form.workspace.tsx +25 -6
  162. package/src/billing-form/visit-attributes/visit-attributes-form.component.tsx +6 -2
  163. package/src/billing.resource.test.ts +43 -41
  164. package/src/billing.resource.ts +65 -16
  165. package/src/bills-table/bills-table.component.tsx +15 -4
  166. package/src/bills-table/bills-table.test.tsx +72 -71
  167. package/src/config-schema.ts +0 -7
  168. package/src/discounts/admin/discount-requests-left-panel-link.component.tsx +43 -0
  169. package/src/discounts/admin/discount-requests.component.tsx +316 -0
  170. package/src/discounts/admin/discount-requests.scss +133 -0
  171. package/src/discounts/admin/discount-requests.test.tsx +104 -0
  172. package/src/discounts/admin/review-bill-discounts/bill-line-items-table/bill-line-items-table.component.tsx +42 -0
  173. package/src/discounts/admin/review-bill-discounts/bill-line-items-table/bill-line-items-table.scss +76 -0
  174. package/src/discounts/admin/review-bill-discounts/bill-payments-table/bill-payments-table.component.tsx +50 -0
  175. package/src/discounts/admin/review-bill-discounts/bill-payments-table/bill-payments-table.scss +63 -0
  176. package/src/discounts/admin/review-bill-discounts/bill-receipt-rail/bill-receipt-rail.component.tsx +73 -0
  177. package/src/discounts/admin/review-bill-discounts/bill-receipt-rail/bill-receipt-rail.scss +54 -0
  178. package/src/discounts/admin/review-bill-discounts/bill-totals-summary/bill-totals-summary.component.tsx +95 -0
  179. package/src/discounts/admin/review-bill-discounts/bill-totals-summary/bill-totals-summary.scss +128 -0
  180. package/src/discounts/admin/review-bill-discounts/discount-card/discount-card.component.tsx +158 -0
  181. package/src/discounts/admin/review-bill-discounts/discount-card/discount-card.scss +164 -0
  182. package/src/discounts/admin/review-bill-discounts/discount-review-stack/discount-review-stack.component.tsx +86 -0
  183. package/src/discounts/admin/review-bill-discounts/discount-review-stack/discount-review-stack.scss +40 -0
  184. package/src/discounts/admin/review-bill-discounts/review-bill-discounts.modal.scss +14 -0
  185. package/src/discounts/admin/review-bill-discounts/review-bill-discounts.modal.test.tsx +153 -0
  186. package/src/discounts/admin/review-bill-discounts/review-bill-discounts.modal.tsx +167 -0
  187. package/src/discounts/admin/review-bill-discounts/review-bill-discounts.utils.ts +42 -0
  188. package/src/discounts/discounts-table.component.tsx +109 -0
  189. package/src/discounts/discounts-table.scss +37 -0
  190. package/src/discounts/discounts-table.test.tsx +67 -0
  191. package/src/discounts/discounts.resource.ts +71 -0
  192. package/src/discounts/request-discount.modal.scss +88 -0
  193. package/src/discounts/request-discount.modal.test.tsx +161 -0
  194. package/src/discounts/request-discount.modal.tsx +253 -0
  195. package/src/index.ts +52 -21
  196. package/src/invoice/invoice-table.component.tsx +116 -18
  197. package/src/invoice/invoice-table.test.tsx +165 -13
  198. package/src/invoice/invoice.component.tsx +111 -7
  199. package/src/invoice/invoice.test.tsx +366 -66
  200. package/src/invoice/line-item-action-menu.component.tsx +31 -1
  201. package/src/invoice/payments/payment-form/payment-form.test.tsx +20 -19
  202. package/src/invoice/payments/payment-history/payment-history.test.tsx +13 -10
  203. package/src/invoice/payments/payments.component.tsx +20 -6
  204. package/src/invoice/payments/payments.test.tsx +88 -23
  205. package/src/invoice/printable-invoice/print-receipt.test.tsx +10 -28
  206. package/src/invoice/printable-invoice/printable-footer.test.tsx +5 -4
  207. package/src/invoice/printable-invoice/printable-invoice-header.component.tsx +3 -3
  208. package/src/invoice/printable-invoice/printable-invoice-header.test.tsx +26 -11
  209. package/src/invoice/printable-invoice/printable-invoice.component.tsx +38 -15
  210. package/src/left-panel-link.test.tsx +3 -3
  211. package/src/metrics-cards/metrics-cards.test.tsx +11 -10
  212. package/src/modal/delete-bill-confirmation.modal.test.tsx +134 -0
  213. package/src/modal/delete-bill-confirmation.modal.tsx +98 -0
  214. package/src/modal/delete-line-item-confirmation.modal.test.tsx +11 -9
  215. package/src/modal/finalize-bill-confirmation.modal.test.tsx +10 -8
  216. package/src/modal/require-payment-modal.test.tsx +12 -11
  217. package/src/payment-status-tag/payment-status-tag.component.tsx +50 -0
  218. package/src/payment-status-tag/payment-status-tag.scss +6 -0
  219. package/src/payment-status-tag/payment-status-tag.test.tsx +113 -0
  220. package/src/refunds/admin/refund-requests-left-panel-link.component.tsx +43 -0
  221. package/src/refunds/admin/refund-requests.component.tsx +324 -0
  222. package/src/refunds/admin/refund-requests.scss +133 -0
  223. package/src/refunds/admin/refund-requests.test.tsx +99 -0
  224. package/src/refunds/admin/review-bill-refunds/bill-line-items-table/bill-line-items-table.component.tsx +42 -0
  225. package/src/refunds/admin/review-bill-refunds/bill-line-items-table/bill-line-items-table.scss +76 -0
  226. package/src/refunds/admin/review-bill-refunds/bill-payments-table/bill-payments-table.component.tsx +50 -0
  227. package/src/refunds/admin/review-bill-refunds/bill-payments-table/bill-payments-table.scss +63 -0
  228. package/src/refunds/admin/review-bill-refunds/bill-receipt-rail/bill-receipt-rail.component.tsx +84 -0
  229. package/src/refunds/admin/review-bill-refunds/bill-receipt-rail/bill-receipt-rail.scss +54 -0
  230. package/src/refunds/admin/review-bill-refunds/bill-totals-summary/bill-totals-summary.component.tsx +83 -0
  231. package/src/refunds/admin/review-bill-refunds/bill-totals-summary/bill-totals-summary.scss +65 -0
  232. package/src/refunds/admin/review-bill-refunds/refund-card/refund-card.component.tsx +170 -0
  233. package/src/refunds/admin/review-bill-refunds/refund-card/refund-card.scss +155 -0
  234. package/src/refunds/admin/review-bill-refunds/refund-review-stack/refund-review-stack.component.tsx +86 -0
  235. package/src/refunds/admin/review-bill-refunds/refund-review-stack/refund-review-stack.scss +40 -0
  236. package/src/refunds/admin/review-bill-refunds/review-bill-refunds.modal.scss +14 -0
  237. package/src/refunds/admin/review-bill-refunds/review-bill-refunds.modal.test.tsx +313 -0
  238. package/src/refunds/admin/review-bill-refunds/review-bill-refunds.modal.tsx +188 -0
  239. package/src/refunds/admin/review-bill-refunds/review-bill-refunds.utils.ts +66 -0
  240. package/src/refunds/refunds-table.component.tsx +137 -0
  241. package/src/refunds/refunds-table.scss +37 -0
  242. package/src/refunds/refunds-table.test.tsx +105 -0
  243. package/src/refunds/refunds.resource.test.ts +44 -0
  244. package/src/refunds/refunds.resource.ts +42 -0
  245. package/src/refunds/refunds.types.test.ts +15 -0
  246. package/src/refunds/request-refund.modal.scss +84 -0
  247. package/src/refunds/request-refund.modal.test.tsx +204 -0
  248. package/src/refunds/request-refund.modal.tsx +218 -0
  249. package/src/routes.json +36 -2
  250. package/src/types/index.ts +116 -1
  251. package/src/visit-bills/visit-bills-panel.component.tsx +151 -0
  252. package/src/visit-bills/visit-bills-panel.scss +31 -0
  253. package/src/visit-bills/visit-bills-panel.test.tsx +113 -0
  254. package/tools/empty-module.ts +1 -0
  255. package/tools/setup-tests.ts +9 -9
  256. package/translations/am.json +154 -16
  257. package/translations/ar.json +154 -16
  258. package/translations/ar_SY.json +154 -16
  259. package/translations/bn.json +154 -16
  260. package/translations/cs.json +154 -16
  261. package/translations/de.json +154 -16
  262. package/translations/en.json +154 -16
  263. package/translations/en_US.json +154 -16
  264. package/translations/es.json +154 -16
  265. package/translations/es_MX.json +154 -16
  266. package/translations/fr.json +154 -16
  267. package/translations/he.json +154 -16
  268. package/translations/hi.json +154 -16
  269. package/translations/hi_IN.json +154 -16
  270. package/translations/id.json +154 -16
  271. package/translations/it.json +154 -16
  272. package/translations/ka.json +154 -16
  273. package/translations/km.json +154 -16
  274. package/translations/ku.json +154 -16
  275. package/translations/ky.json +154 -16
  276. package/translations/lg.json +154 -16
  277. package/translations/ne.json +154 -16
  278. package/translations/pl.json +154 -16
  279. package/translations/pt.json +154 -16
  280. package/translations/pt_BR.json +154 -16
  281. package/translations/qu.json +154 -16
  282. package/translations/ro_RO.json +154 -16
  283. package/translations/ru_RU.json +154 -16
  284. package/translations/si.json +154 -16
  285. package/translations/sq.json +154 -16
  286. package/translations/sw.json +154 -16
  287. package/translations/sw_KE.json +154 -16
  288. package/translations/tr.json +154 -16
  289. package/translations/tr_TR.json +154 -16
  290. package/translations/uk.json +154 -16
  291. package/translations/uz.json +154 -16
  292. package/translations/uz@Latn.json +154 -16
  293. package/translations/uz_UZ.json +154 -16
  294. package/translations/vi.json +154 -16
  295. package/translations/zh.json +154 -16
  296. package/translations/zh_CN.json +179 -41
  297. package/translations/zh_TW.json +154 -16
  298. package/tsconfig.json +3 -3
  299. package/vitest.config.js +28 -0
  300. package/.turbo/cache/4e30f71f570fc412-meta.json +0 -1
  301. package/.turbo/cache/4e30f71f570fc412.tar.zst +0 -0
  302. package/dist/1119.js +0 -1
  303. package/dist/1197.js +0 -1
  304. package/dist/1435.js +0 -1
  305. package/dist/1435.js.map +0 -1
  306. package/dist/1807.js +0 -1
  307. package/dist/1807.js.map +0 -1
  308. package/dist/2146.js +0 -1
  309. package/dist/2177.js +0 -2
  310. package/dist/2177.js.LICENSE.txt +0 -9
  311. package/dist/2177.js.map +0 -1
  312. package/dist/2690.js +0 -1
  313. package/dist/2704.js +0 -1
  314. package/dist/2704.js.map +0 -1
  315. package/dist/3002.js +0 -1
  316. package/dist/3002.js.map +0 -1
  317. package/dist/3041.js +0 -1
  318. package/dist/3041.js.map +0 -1
  319. package/dist/3099.js +0 -1
  320. package/dist/3184.js +0 -2
  321. package/dist/3184.js.LICENSE.txt +0 -14
  322. package/dist/3184.js.map +0 -1
  323. package/dist/3584.js +0 -1
  324. package/dist/4055.js +0 -1
  325. package/dist/4132.js +0 -1
  326. package/dist/4225.js +0 -1
  327. package/dist/4225.js.map +0 -1
  328. package/dist/4300.js +0 -1
  329. package/dist/4335.js +0 -1
  330. package/dist/439.js +0 -1
  331. package/dist/4618.js +0 -1
  332. package/dist/4652.js +0 -1
  333. package/dist/4944.js +0 -1
  334. package/dist/5173.js +0 -1
  335. package/dist/5241.js +0 -1
  336. package/dist/5422.js +0 -1
  337. package/dist/5422.js.map +0 -1
  338. package/dist/5442.js +0 -1
  339. package/dist/5661.js +0 -1
  340. package/dist/6022.js +0 -1
  341. package/dist/6404.js +0 -1
  342. package/dist/6404.js.map +0 -1
  343. package/dist/6468.js +0 -1
  344. package/dist/6540.js +0 -2
  345. package/dist/6540.js.LICENSE.txt +0 -9
  346. package/dist/6540.js.map +0 -1
  347. package/dist/6589.js +0 -1
  348. package/dist/6606.js +0 -1
  349. package/dist/6606.js.map +0 -1
  350. package/dist/6679.js +0 -1
  351. package/dist/6792.js +0 -1
  352. package/dist/6792.js.map +0 -1
  353. package/dist/6840.js +0 -1
  354. package/dist/6859.js +0 -1
  355. package/dist/7097.js +0 -1
  356. package/dist/7159.js +0 -1
  357. package/dist/723.js +0 -1
  358. package/dist/7255.js +0 -1
  359. package/dist/7255.js.map +0 -1
  360. package/dist/7617.js +0 -1
  361. package/dist/795.js +0 -1
  362. package/dist/8163.js +0 -1
  363. package/dist/8341.js +0 -2
  364. package/dist/8341.js.LICENSE.txt +0 -52
  365. package/dist/8341.js.map +0 -1
  366. package/dist/8349.js +0 -1
  367. package/dist/8371.js +0 -1
  368. package/dist/8421.js +0 -1
  369. package/dist/8421.js.map +0 -1
  370. package/dist/8618.js +0 -1
  371. package/dist/890.js +0 -1
  372. package/dist/9214.js +0 -1
  373. package/dist/9538.js +0 -1
  374. package/dist/9569.js +0 -1
  375. package/dist/961.js +0 -2
  376. package/dist/961.js.LICENSE.txt +0 -19
  377. package/dist/961.js.map +0 -1
  378. package/dist/986.js +0 -1
  379. package/dist/9879.js +0 -1
  380. package/dist/9895.js +0 -1
  381. package/dist/9900.js +0 -1
  382. package/dist/9913.js +0 -1
  383. package/dist/main.js.LICENSE.txt +0 -62
  384. package/src/billable-services/bill-waiver/bill-selection.component.tsx +0 -76
  385. package/src/billable-services/bill-waiver/bill-waiver-form.component.tsx +0 -107
  386. package/src/billable-services/bill-waiver/bill-waiver-form.scss +0 -34
  387. package/src/billable-services/bill-waiver/bill-waiver.component.tsx +0 -34
  388. package/src/billable-services/bill-waiver/bill-waiver.scss +0 -10
  389. package/src/billable-services/bill-waiver/patient-bills.component.tsx +0 -134
  390. package/webpack.config.js +0 -1
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { describe, expect, it, vi } from 'vitest';
2
3
  import userEvent from '@testing-library/user-event';
3
4
  import { render, screen } from '@testing-library/react';
4
5
  import { FormProvider, useForm } from 'react-hook-form';
@@ -6,11 +7,11 @@ import type { PaymentFormValue } from '../payments.component';
6
7
  import { usePaymentModes } from '../payment.resource';
7
8
  import PaymentForm from './payment-form.component';
8
9
 
9
- jest.mock('../payment.resource', () => ({
10
- usePaymentModes: jest.fn(),
10
+ vi.mock('../payment.resource', () => ({
11
+ usePaymentModes: vi.fn(),
11
12
  }));
12
13
 
13
- const mockUsePaymentModes = jest.mocked(usePaymentModes);
14
+ const mockUsePaymentModes = vi.mocked(usePaymentModes);
14
15
 
15
16
  type WrapperProps = {
16
17
  children: React.ReactNode;
@@ -26,12 +27,12 @@ const Wrapper: React.FC<WrapperProps> = ({ children, defaultValues }) => {
26
27
  };
27
28
 
28
29
  describe('PaymentForm Component', () => {
29
- test('should render skeleton while loading payment modes', () => {
30
+ it('should render skeleton while loading payment modes', () => {
30
31
  mockUsePaymentModes.mockReturnValue({
31
32
  paymentModes: [],
32
33
  isLoading: true,
33
34
  error: null,
34
- mutate: jest.fn(),
35
+ mutate: vi.fn(),
35
36
  });
36
37
 
37
38
  render(
@@ -45,12 +46,12 @@ describe('PaymentForm Component', () => {
45
46
  expect(screen.queryByPlaceholderText(/enter amount/i)).not.toBeInTheDocument();
46
47
  });
47
48
 
48
- test('should render error message when payment modes fail to load', () => {
49
+ it('should render error message when payment modes fail to load', () => {
49
50
  mockUsePaymentModes.mockReturnValue({
50
51
  paymentModes: [],
51
52
  isLoading: false,
52
53
  error: new Error('Failed to load payment modes'),
53
- mutate: jest.fn(),
54
+ mutate: vi.fn(),
54
55
  });
55
56
 
56
57
  render(
@@ -62,12 +63,12 @@ describe('PaymentForm Component', () => {
62
63
  expect(screen.getByText(/error state/i)).toBeInTheDocument();
63
64
  });
64
65
 
65
- test('should render payment form with method, amount and reference fields when not disabled', () => {
66
+ it('should render payment form with method, amount and reference fields when not disabled', () => {
66
67
  mockUsePaymentModes.mockReturnValue({
67
68
  paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
68
69
  isLoading: false,
69
70
  error: null,
70
- mutate: jest.fn(),
71
+ mutate: vi.fn(),
71
72
  });
72
73
 
73
74
  render(
@@ -81,12 +82,12 @@ describe('PaymentForm Component', () => {
81
82
  expect(screen.getByText(/select payment method/i)).toBeInTheDocument();
82
83
  });
83
84
 
84
- test('should not render form when disablePayment is true', () => {
85
+ it('should not render form when disablePayment is true', () => {
85
86
  mockUsePaymentModes.mockReturnValue({
86
87
  paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
87
88
  isLoading: false,
88
89
  error: null,
89
- mutate: jest.fn(),
90
+ mutate: vi.fn(),
90
91
  });
91
92
 
92
93
  render(
@@ -99,12 +100,12 @@ describe('PaymentForm Component', () => {
99
100
  expect(screen.queryByText(/add payment method/i)).not.toBeInTheDocument();
100
101
  });
101
102
 
102
- test('should render amount input without leading zero', () => {
103
+ it('should render amount input without leading zero', () => {
103
104
  mockUsePaymentModes.mockReturnValue({
104
105
  paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
105
106
  isLoading: false,
106
107
  error: null,
107
- mutate: jest.fn(),
108
+ mutate: vi.fn(),
108
109
  });
109
110
 
110
111
  render(
@@ -117,13 +118,13 @@ describe('PaymentForm Component', () => {
117
118
  expect(amountInput.value).toBe('');
118
119
  });
119
120
 
120
- test('should allow user to clear amount input without reverting to zero', async () => {
121
+ it('should allow user to clear amount input without reverting to zero', async () => {
121
122
  const user = userEvent.setup();
122
123
  mockUsePaymentModes.mockReturnValue({
123
124
  paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
124
125
  isLoading: false,
125
126
  error: null,
126
- mutate: jest.fn(),
127
+ mutate: vi.fn(),
127
128
  });
128
129
 
129
130
  render(
@@ -141,13 +142,13 @@ describe('PaymentForm Component', () => {
141
142
  expect(amountInput.value).toBe('');
142
143
  });
143
144
 
144
- test('should handle amount input with decimal values', async () => {
145
+ it('should handle amount input with decimal values', async () => {
145
146
  const user = userEvent.setup();
146
147
  mockUsePaymentModes.mockReturnValue({
147
148
  paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
148
149
  isLoading: false,
149
150
  error: null,
150
- mutate: jest.fn(),
151
+ mutate: vi.fn(),
151
152
  });
152
153
 
153
154
  render(
@@ -162,12 +163,12 @@ describe('PaymentForm Component', () => {
162
163
  expect(amountInput.value).toBe('10.5');
163
164
  });
164
165
 
165
- test('should not auto-focus reference number input on mount', () => {
166
+ it('should not auto-focus reference number input on mount', () => {
166
167
  mockUsePaymentModes.mockReturnValue({
167
168
  paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
168
169
  isLoading: false,
169
170
  error: null,
170
- mutate: jest.fn(),
171
+ mutate: vi.fn(),
171
172
  });
172
173
 
173
174
  render(
@@ -1,15 +1,16 @@
1
1
  import React from 'react';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
3
  import { render, screen } from '@testing-library/react';
3
4
  import { getDefaultsFromConfigSchema, useConfig } from '@openmrs/esm-framework';
4
5
  import { type BillingConfig, configSchema } from '../../../config-schema';
5
6
  import { type MappedBill } from '../../../types';
6
7
  import PaymentHistory from './payment-history.component';
7
8
 
8
- jest.mock('../../../helpers', () => ({
9
- convertToCurrency: jest.fn((amount, currency) => `${currency} ${amount.toFixed(2)}`),
9
+ vi.mock('../../../helpers', () => ({
10
+ convertToCurrency: vi.fn((amount, currency) => `${currency} ${amount.toFixed(2)}`),
10
11
  }));
11
12
 
12
- const mockUseConfig = jest.mocked(useConfig<BillingConfig>);
13
+ const mockUseConfig = vi.mocked(useConfig<BillingConfig>);
13
14
 
14
15
  describe('PaymentHistory Component', () => {
15
16
  beforeEach(() => {
@@ -73,6 +74,7 @@ describe('PaymentHistory Component', () => {
73
74
  dateCreated: '2023-09-01T12:00:00Z',
74
75
  lineItems: [],
75
76
  billingService: 'Billing Service',
77
+ netAmount: 0,
76
78
  };
77
79
 
78
80
  const emptyBill: MappedBill = {
@@ -101,13 +103,14 @@ describe('PaymentHistory Component', () => {
101
103
  dateCreated: '2023-09-02T10:00:00Z',
102
104
  lineItems: [],
103
105
  billingService: 'Billing Service',
106
+ netAmount: 0,
104
107
  };
105
108
 
106
- test('renders without crashing', () => {
109
+ it('renders without crashing', () => {
107
110
  render(<PaymentHistory bill={mockBill} />);
108
111
  });
109
112
 
110
- test('renders correct table headers', () => {
113
+ it('renders correct table headers', () => {
111
114
  render(<PaymentHistory bill={mockBill} />);
112
115
  expect(screen.getByText('Date of payment')).toBeInTheDocument();
113
116
  expect(screen.getByText('Bill amount')).toBeInTheDocument();
@@ -115,13 +118,13 @@ describe('PaymentHistory Component', () => {
115
118
  expect(screen.getByText('Payment method')).toBeInTheDocument();
116
119
  });
117
120
 
118
- test('renders the correct number of rows', () => {
121
+ it('renders the correct number of rows', () => {
119
122
  render(<PaymentHistory bill={mockBill} />);
120
123
  const rows = screen.getAllByRole('row');
121
124
  expect(rows).toHaveLength(3);
122
125
  });
123
126
 
124
- test('renders correct data in the rows', () => {
127
+ it('renders correct data in the rows', () => {
125
128
  render(<PaymentHistory bill={mockBill} />);
126
129
 
127
130
  expect(screen.getByText('01-Sept-2023')).toBeInTheDocument();
@@ -135,17 +138,17 @@ describe('PaymentHistory Component', () => {
135
138
  expect(screen.getByText('Cash')).toBeInTheDocument();
136
139
  });
137
140
 
138
- test('handles empty payments gracefully', () => {
141
+ it('handles empty payments gracefully', () => {
139
142
  render(<PaymentHistory bill={emptyBill} />);
140
143
  expect(screen.queryByRole('table')).not.toBeInTheDocument();
141
144
  });
142
145
 
143
- test('does not render when bill is undefined', () => {
146
+ it('does not render when bill is undefined', () => {
144
147
  render(<PaymentHistory bill={undefined} />);
145
148
  expect(screen.queryByRole('table')).not.toBeInTheDocument();
146
149
  });
147
150
 
148
- test('formats dates and converts amounts correctly', () => {
151
+ it('formats dates and converts amounts correctly', () => {
149
152
  render(<PaymentHistory bill={mockBill} />);
150
153
 
151
154
  expect(screen.getByText('01-Sept-2023')).toBeInTheDocument();
@@ -8,10 +8,11 @@ import { CardHeader, navigate, showSnackbar, useConfig, useVisit } from '@openmr
8
8
  import { InvoiceBreakDown } from './invoice-breakdown/invoice-breakdown.component';
9
9
  import PaymentForm from './payment-form/payment-form.component';
10
10
  import PaymentHistory from './payment-history/payment-history.component';
11
- import { processBillPayment } from '../../billing.resource';
11
+ import { useSWRConfig } from 'swr';
12
+ import { processBillPayment, patientPaymentStatusCacheKey } from '../../billing.resource';
12
13
  import { updateBillVisitAttribute } from './payment.resource';
13
14
  import { convertToCurrency } from '../../helpers';
14
- import { BillStatus, type MappedBill } from '../../types';
15
+ import { BillStatus, RefundStatus, type MappedBill } from '../../types';
15
16
  import styles from './payments.scss';
16
17
 
17
18
  type PaymentProps = {
@@ -27,6 +28,7 @@ export type PaymentFormValue = {
27
28
 
28
29
  const Payments: React.FC<PaymentProps> = ({ bill, mutate }) => {
29
30
  const { t } = useTranslation();
31
+ const { mutate: swrMutate } = useSWRConfig();
30
32
  const paymentSchema = z.object({
31
33
  method: z.string().refine((value) => !!value, 'Payment method is required'),
32
34
  amount: z
@@ -35,7 +37,7 @@ const Payments: React.FC<PaymentProps> = ({ bill, mutate }) => {
35
37
  invalid_type_error: t('amountRequired', 'Amount is required'),
36
38
  })
37
39
  .positive({ message: t('amountMustBePositive', 'Amount must be greater than 0') })
38
- .max(bill?.totalAmount - bill?.tenderedAmount, {
40
+ .max((bill?.netAmount ?? 0) - (bill?.tenderedAmount ?? 0), {
39
41
  message: t('paymentAmountCannotExceedAmountDue', 'Payment amount cannot exceed amount due'),
40
42
  }),
41
43
  referenceCode: z.union([z.number(), z.string()]).optional(),
@@ -69,7 +71,11 @@ const Payments: React.FC<PaymentProps> = ({ bill, mutate }) => {
69
71
  return null;
70
72
  }
71
73
 
72
- const amountDue = (bill.totalAmount ?? 0) - (bill.tenderedAmount ?? 0);
74
+ const refundTotal = (bill.refunds ?? [])
75
+ .filter((r) => r.status === RefundStatus.COMPLETED)
76
+ .reduce((sum, r) => sum + r.refundAmount, 0);
77
+
78
+ const amountDue = (bill.netAmount ?? 0) - (bill.tenderedAmount ?? 0);
73
79
 
74
80
  const handleProcessPayment = async () => {
75
81
  if (!formValues?.method || formValues.amount == null) {
@@ -95,6 +101,7 @@ const Payments: React.FC<PaymentProps> = ({ bill, mutate }) => {
95
101
  }
96
102
  methods.reset(defaultPaymentValues);
97
103
  mutate();
104
+ swrMutate(patientPaymentStatusCacheKey(bill.patientUuid));
98
105
  } catch (error) {
99
106
  showSnackbar({
100
107
  title: t('errorProcessingPayment', 'Error processing payment'),
@@ -126,11 +133,18 @@ const Payments: React.FC<PaymentProps> = ({ bill, mutate }) => {
126
133
  label={t('totalTendered', 'Total tendered')}
127
134
  value={convertToCurrency(bill.tenderedAmount ?? 0, defaultCurrency)}
128
135
  />
129
- <InvoiceBreakDown label={t('discount', 'Discount')} value={'--'} />
136
+ <InvoiceBreakDown
137
+ label={t('discount', 'Discount')}
138
+ value={`- ${convertToCurrency((bill.totalAmount ?? 0) - (bill.netAmount ?? 0), defaultCurrency)}`}
139
+ />
140
+ <InvoiceBreakDown
141
+ label={t('refunds', 'Refunds')}
142
+ value={`- ${convertToCurrency(refundTotal, defaultCurrency)}`}
143
+ />
130
144
  <InvoiceBreakDown
131
145
  hasBalance={amountDue < 0}
132
146
  label={t('amountDue', 'Amount due')}
133
- value={convertToCurrency(amountDue < 0 ? -amountDue : amountDue, defaultCurrency)}
147
+ value={convertToCurrency(amountDue, defaultCurrency)}
134
148
  />
135
149
  <div className={styles.processPayments}>
136
150
  <Button onClick={handleNavigateToBillingDashboard} kind="secondary">
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
3
  import userEvent from '@testing-library/user-event';
3
4
  import { render, screen } from '@testing-library/react';
4
5
  import {
@@ -9,18 +10,19 @@ import {
9
10
  type VisitReturnType,
10
11
  } from '@openmrs/esm-framework';
11
12
  import { useBillableServices } from '../../billable-services/billable-service.resource';
13
+ import { processBillPayment } from '../../billing.resource';
12
14
  import { BillStatus, type MappedBill } from '../../types';
13
15
  import { configSchema, type BillingConfig } from '../../config-schema';
14
16
  import { usePaymentModes } from './payment.resource';
15
17
  import Payments from './payments.component';
16
18
 
17
- const mockUseVisit = jest.mocked(useVisit);
18
- const mockUseConfig = jest.mocked(useConfig<BillingConfig>);
19
- const mockUseBillableServices = jest.mocked(useBillableServices);
20
- const mockUsePaymentModes = jest.mocked(usePaymentModes);
21
- const mockFormatToParts = jest.fn().mockReturnValue([{ type: 'integer', value: '1000' }]);
22
- const mockFormat = jest.fn().mockReturnValue('$1000.00');
23
- const mockResolvedOptions = jest.fn().mockReturnValue({
19
+ const mockUseVisit = vi.mocked(useVisit);
20
+ const mockUseConfig = vi.mocked(useConfig<BillingConfig>);
21
+ const mockUseBillableServices = vi.mocked(useBillableServices);
22
+ const mockUsePaymentModes = vi.mocked(usePaymentModes);
23
+ const mockFormatToParts = vi.fn().mockReturnValue([{ type: 'integer', value: '1000' }]);
24
+ const mockFormat = vi.fn().mockReturnValue('$1000.00');
25
+ const mockResolvedOptions = vi.fn().mockReturnValue({
24
26
  locale: 'en-US',
25
27
  numberingSystem: 'latn',
26
28
  style: 'currency',
@@ -29,24 +31,24 @@ const mockResolvedOptions = jest.fn().mockReturnValue({
29
31
  maximumFractionDigits: 2,
30
32
  });
31
33
 
32
- global.Intl.NumberFormat.supportedLocalesOf = jest.fn().mockReturnValue(['en-US']);
33
- global.Intl.NumberFormat = jest.fn().mockImplementation(() => ({
34
- formatToParts: mockFormatToParts,
35
- format: mockFormat,
36
- resolvedOptions: mockResolvedOptions,
37
- })) as any;
34
+ global.Intl.NumberFormat = vi.fn().mockImplementation(function () {
35
+ this.formatToParts = mockFormatToParts;
36
+ this.format = mockFormat;
37
+ this.resolvedOptions = mockResolvedOptions;
38
+ }) as any;
39
+ global.Intl.NumberFormat.supportedLocalesOf = vi.fn().mockReturnValue(['en-US']);
38
40
 
39
- jest.mock('../../billing.resource', () => ({
40
- processBillPayment: jest.fn(),
41
+ vi.mock('../../billing.resource', () => ({
42
+ processBillPayment: vi.fn(),
41
43
  }));
42
44
 
43
- jest.mock('./payment.resource', () => ({
44
- updateBillVisitAttribute: jest.fn(),
45
- usePaymentModes: jest.fn(),
45
+ vi.mock('./payment.resource', () => ({
46
+ updateBillVisitAttribute: vi.fn(),
47
+ usePaymentModes: vi.fn(),
46
48
  }));
47
49
 
48
- jest.mock('../../billable-services/billable-service.resource', () => ({
49
- useBillableServices: jest.fn(),
50
+ vi.mock('../../billable-services/billable-service.resource', () => ({
51
+ useBillableServices: vi.fn(),
50
52
  }));
51
53
 
52
54
  describe('Payments', () => {
@@ -107,9 +109,10 @@ describe('Payments', () => {
107
109
  dateCreated: '2023-09-01T12:00:00Z',
108
110
  lineItems: [],
109
111
  billingService: 'Billing Service',
112
+ netAmount: 0,
110
113
  };
111
114
 
112
- const mockMutate = jest.fn();
115
+ const mockMutate = vi.fn();
113
116
 
114
117
  beforeEach(() => {
115
118
  mockUseVisit.mockReturnValue({ currentVisit: null } as unknown as VisitReturnType);
@@ -119,7 +122,7 @@ describe('Payments', () => {
119
122
  isLoading: false,
120
123
  isValidating: false,
121
124
  error: null,
122
- mutate: jest.fn(),
125
+ mutate: vi.fn(),
123
126
  });
124
127
  mockUsePaymentModes.mockReturnValue({
125
128
  paymentModes: [
@@ -128,7 +131,7 @@ describe('Payments', () => {
128
131
  ],
129
132
  isLoading: false,
130
133
  error: null,
131
- mutate: jest.fn(),
134
+ mutate: vi.fn(),
132
135
  });
133
136
  });
134
137
 
@@ -243,6 +246,7 @@ describe('Payments', () => {
243
246
  ...mockBill,
244
247
  status: BillStatus.POSTED,
245
248
  totalAmount: 100,
249
+ netAmount: 100,
246
250
  tenderedAmount: 0,
247
251
  };
248
252
 
@@ -262,6 +266,7 @@ describe('Payments', () => {
262
266
  ...mockBill,
263
267
  status: BillStatus.POSTED,
264
268
  totalAmount: 100,
269
+ netAmount: 100,
265
270
  tenderedAmount: 0,
266
271
  lineItems: [],
267
272
  };
@@ -272,6 +277,66 @@ describe('Payments', () => {
272
277
  expect(screen.getByText(/select payment method/i)).toBeInTheDocument();
273
278
  });
274
279
 
280
+ it('blocks payment greater than (netAmount - tendered) on a discounted bill', async () => {
281
+ const user = userEvent.setup();
282
+ const mockProcessBillPayment = vi.mocked(processBillPayment);
283
+ mockProcessBillPayment.mockResolvedValue({} as any);
284
+
285
+ const billWithDiscount: MappedBill = {
286
+ ...mockBill,
287
+ status: BillStatus.POSTED,
288
+ totalAmount: 500,
289
+ netAmount: 400,
290
+ tenderedAmount: 0,
291
+ payments: [],
292
+ lineItems: [],
293
+ };
294
+
295
+ render(<Payments bill={billWithDiscount} mutate={mockMutate} />);
296
+
297
+ const methodDropdown = await screen.findByRole('combobox', { name: /payment method/i });
298
+ await user.click(methodDropdown);
299
+ await user.click(screen.getByText('Cash'));
300
+
301
+ // 450 > netAmount (400). If the schema bound regressed to totalAmount (500) this would pass.
302
+ await user.type(screen.getByPlaceholderText(/enter amount/i), '450');
303
+
304
+ expect(screen.getByText('Process Payment')).toBeDisabled();
305
+ expect(mockProcessBillPayment).not.toHaveBeenCalled();
306
+ });
307
+
308
+ it('sends a non-null amount in the payment payload when processing a discounted bill', async () => {
309
+ const user = userEvent.setup();
310
+ const mockProcessBillPayment = vi.mocked(processBillPayment);
311
+ mockProcessBillPayment.mockResolvedValue({} as any);
312
+
313
+ const billWithDiscount: MappedBill = {
314
+ ...mockBill,
315
+ status: BillStatus.POSTED,
316
+ totalAmount: 500,
317
+ netAmount: 400,
318
+ tenderedAmount: 0,
319
+ payments: [],
320
+ lineItems: [],
321
+ };
322
+
323
+ render(<Payments bill={billWithDiscount} mutate={mockMutate} />);
324
+
325
+ const methodDropdown = await screen.findByRole('combobox', { name: /payment method/i });
326
+ await user.click(methodDropdown);
327
+ await user.click(screen.getByText('Cash'));
328
+
329
+ await user.type(screen.getByPlaceholderText(/enter amount/i), '100');
330
+
331
+ await user.click(screen.getByText('Process Payment'));
332
+
333
+ expect(mockProcessBillPayment).toHaveBeenCalledTimes(1);
334
+ const [payload] = mockProcessBillPayment.mock.calls[0];
335
+ expect(payload.amount).toBeTypeOf('number');
336
+ expect(payload.amount).not.toBeNaN();
337
+ expect(payload.amountTendered).toBe(100);
338
+ });
339
+
275
340
  it('should display process payment button', () => {
276
341
  const billWithAmountDue: MappedBill = {
277
342
  ...mockBill,
@@ -1,4 +1,5 @@
1
- import React, { act } from 'react';
1
+ import React from 'react';
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
3
  import userEvent from '@testing-library/user-event';
3
4
  import { render, screen, waitFor } from '@testing-library/react';
4
5
  import PrintReceipt from './print-receipt.component';
@@ -20,10 +21,10 @@ describe('PrintReceipt', () => {
20
21
  });
21
22
 
22
23
  mockLink = document.createElement('a');
23
- jest.spyOn(mockLink, 'click').mockImplementation(() => {});
24
+ vi.spyOn(mockLink, 'click').mockImplementation(() => {});
24
25
 
25
26
  const originalCreateElement = document.createElement.bind(document);
26
- jest.spyOn(document, 'createElement').mockImplementation((tagName: string) => {
27
+ vi.spyOn(document, 'createElement').mockImplementation((tagName: string) => {
27
28
  if (tagName === 'a') {
28
29
  mockLink.href = '';
29
30
  mockLink.download = '';
@@ -31,13 +32,10 @@ describe('PrintReceipt', () => {
31
32
  }
32
33
  return originalCreateElement(tagName);
33
34
  });
34
-
35
- jest.useFakeTimers();
36
35
  });
37
36
 
38
37
  afterEach(() => {
39
- jest.restoreAllMocks();
40
- jest.useRealTimers();
38
+ vi.restoreAllMocks();
41
39
  Object.defineProperty(window, 'location', {
42
40
  value: originalLocation,
43
41
  writable: true,
@@ -54,7 +52,7 @@ describe('PrintReceipt', () => {
54
52
  });
55
53
 
56
54
  it('shows loading state and disables button during download', async () => {
57
- const user = userEvent.setup({ delay: null });
55
+ const user = userEvent.setup();
58
56
  render(<PrintReceipt billUuid={TEST_BILL_UUID} />);
59
57
 
60
58
  const button = screen.getByRole('button', { name: /print receipt/i });
@@ -66,16 +64,12 @@ describe('PrintReceipt', () => {
66
64
  });
67
65
 
68
66
  it('initiates download when button is clicked', async () => {
69
- const user = userEvent.setup({ delay: null });
67
+ const user = userEvent.setup();
70
68
  render(<PrintReceipt billUuid={TEST_BILL_UUID} />);
71
69
 
72
70
  const button = screen.getByRole('button', { name: /print receipt/i });
73
71
  await user.click(button);
74
72
 
75
- act(() => {
76
- jest.advanceTimersByTime(1000);
77
- });
78
-
79
73
  await waitFor(() => {
80
74
  expect(mockLink.click).toHaveBeenCalled();
81
75
  });
@@ -85,7 +79,7 @@ describe('PrintReceipt', () => {
85
79
  });
86
80
 
87
81
  it('re-enables button after download completes', async () => {
88
- const user = userEvent.setup({ delay: null });
82
+ const user = userEvent.setup();
89
83
  render(<PrintReceipt billUuid={TEST_BILL_UUID} />);
90
84
 
91
85
  const button = screen.getByRole('button', { name: /print receipt/i });
@@ -93,10 +87,6 @@ describe('PrintReceipt', () => {
93
87
 
94
88
  expect(button).toBeDisabled();
95
89
 
96
- act(() => {
97
- jest.advanceTimersByTime(1000);
98
- });
99
-
100
90
  await waitFor(() => {
101
91
  expect(button).toBeEnabled();
102
92
  });
@@ -106,7 +96,7 @@ describe('PrintReceipt', () => {
106
96
  });
107
97
 
108
98
  it('prevents multiple simultaneous downloads', async () => {
109
- const user = userEvent.setup({ delay: null });
99
+ const user = userEvent.setup();
110
100
  render(<PrintReceipt billUuid={TEST_BILL_UUID} />);
111
101
 
112
102
  const button = screen.getByRole('button', { name: /print receipt/i });
@@ -117,10 +107,6 @@ describe('PrintReceipt', () => {
117
107
 
118
108
  expect(button).toBeDisabled();
119
109
 
120
- act(() => {
121
- jest.advanceTimersByTime(1000);
122
- });
123
-
124
110
  await waitFor(() => {
125
111
  expect(button).toBeEnabled();
126
112
  });
@@ -134,16 +120,12 @@ describe('PrintReceipt', () => {
134
120
  });
135
121
 
136
122
  it('handles empty bill UUID', async () => {
137
- const user = userEvent.setup({ delay: null });
123
+ const user = userEvent.setup();
138
124
  render(<PrintReceipt billUuid="" />);
139
125
 
140
126
  const button = screen.getByRole('button', { name: /print receipt/i });
141
127
  await user.click(button);
142
128
 
143
- act(() => {
144
- jest.advanceTimersByTime(1000);
145
- });
146
-
147
129
  await waitFor(() => {
148
130
  expect(mockLink.click).toHaveBeenCalled();
149
131
  });
@@ -1,16 +1,17 @@
1
1
  import React from 'react';
2
+ import { describe, expect, it, vi } from 'vitest';
2
3
  import { screen, render } from '@testing-library/react';
3
4
  import { useDefaultFacility } from '../../billing.resource';
4
5
  import PrintableFooter from './printable-footer.component';
5
6
 
6
- const mockUseDefaultFacility = jest.mocked<typeof useDefaultFacility>(useDefaultFacility);
7
+ const mockUseDefaultFacility = vi.mocked<typeof useDefaultFacility>(useDefaultFacility);
7
8
 
8
- jest.mock('../../billing.resource', () => ({
9
- useDefaultFacility: jest.fn(),
9
+ vi.mock('../../billing.resource', () => ({
10
+ useDefaultFacility: vi.fn(),
10
11
  }));
11
12
 
12
13
  describe('PrintableFooter', () => {
13
- test('should render PrintableFooter component', () => {
14
+ it('should render PrintableFooter component', () => {
14
15
  mockUseDefaultFacility.mockReturnValue({
15
16
  data: { display: 'MTRH', uuid: 'mtrh-uuid', links: [] },
16
17
  });
@@ -17,13 +17,13 @@ const PrintableInvoiceHeader: React.FC<PrintableInvoiceHeaderProps> = ({ patient
17
17
  const { logo, country, defaultCurrency } = useConfig<BillingConfig>();
18
18
 
19
19
  const invoiceDetails = {
20
- [t('invoiceNumber', 'Invoice #')]: bill?.receiptNumber,
20
+ [t('invoiceNo', 'Invoice #')]: bill?.receiptNumber,
21
21
  [t('invoiceDate', 'Invoice date')]: bill?.dateCreated
22
22
  ? formatDate(parseDate(bill.dateCreated), { mode: 'wide', noToday: true, time: false })
23
23
  : '--',
24
- [t('totalAmount', 'Total Amount')]: `${defaultCurrency} ${bill?.totalAmount}`,
24
+ [t('totalAmount', 'Total amount')]: `${defaultCurrency} ${bill?.totalAmount}`,
25
25
  [t('totalPaid', 'Total paid')]: `${defaultCurrency} ${bill?.tenderedAmount}`,
26
- [t('amountBalance', 'Amount balance')]: `${defaultCurrency} ${bill?.totalAmount - bill?.tenderedAmount}`,
26
+ [t('amountBalance', 'Amount balance')]: `${defaultCurrency} ${bill?.netAmount - bill?.tenderedAmount}`,
27
27
  ...(bill?.status && { [t('invoiceStatus', 'Invoice status')]: bill.status }),
28
28
  };
29
29