@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
@@ -0,0 +1,255 @@
1
+ import { expect } from '@playwright/test';
2
+ import { test } from '../core/test';
3
+ import { deleteBill, ensureServiceHasPrices, extractNumericValue, waitForSuccessNotification } from '../commands';
4
+ import {
5
+ BillingDashboardPage,
6
+ BillingFormPage,
7
+ DiscountRequestModal,
8
+ DiscountRequestsAdminPage,
9
+ InvoicePage,
10
+ PaymentPage,
11
+ ReviewBillDiscountsModal,
12
+ } from '../pages';
13
+
14
+ test.describe('Bill discount workflow', () => {
15
+ test.describe.configure({ mode: 'serial' });
16
+
17
+ let testServiceName: string;
18
+ let expectedServicePrice: number;
19
+ const billsToCleanup = new Set<string>();
20
+
21
+ test.beforeAll(async ({ api }) => {
22
+ const serviceUuid = process.env.E2E_TEST_SERVICE_UUID;
23
+ if (!serviceUuid) {
24
+ throw new Error('E2E_TEST_SERVICE_UUID must be configured in .env file');
25
+ }
26
+
27
+ const service = await ensureServiceHasPrices(api, serviceUuid, 30.0);
28
+ testServiceName = service.name;
29
+
30
+ const cashPrice = service.servicePrices.find((sp) => sp.name === 'Cash');
31
+ if (!cashPrice) {
32
+ throw new Error('Cash price not found for test service');
33
+ }
34
+ expectedServicePrice = parseFloat(cashPrice.price);
35
+ });
36
+
37
+ test.afterEach(async ({ api }) => {
38
+ for (const billUuid of billsToCleanup) {
39
+ try {
40
+ await deleteBill(api, billUuid);
41
+ } catch (error) {
42
+ console.error(`Failed to delete bill ${billUuid}:`, error);
43
+ }
44
+ }
45
+ billsToCleanup.clear();
46
+ });
47
+
48
+ test('Approved line-item discount reduces the bill amount due and payment settles the bill', async ({
49
+ page,
50
+ api,
51
+ patient,
52
+ }) => {
53
+ const billingDashboardPage = new BillingDashboardPage(page);
54
+ const billingFormPage = new BillingFormPage(page);
55
+ const invoicePage = new InvoicePage(page);
56
+ const paymentPage = new PaymentPage(page);
57
+ const requestDiscountModal = new DiscountRequestModal(page);
58
+ const discountRequestsPage = new DiscountRequestsAdminPage(page);
59
+ const reviewModal = new ReviewBillDiscountsModal(page);
60
+
61
+ const patientUuid = patient.uuid;
62
+ const patientName = patient.person.display;
63
+ const discountPercentage = 10;
64
+ const expectedDiscountAmount = (expectedServicePrice * discountPercentage) / 100;
65
+ const expectedNetAmount = expectedServicePrice - expectedDiscountAmount;
66
+ const justification = `e2e line-item discount ${Date.now()}`;
67
+ let billUuid: string;
68
+ let lineItemUuid: string;
69
+
70
+ await test.step('Given a finalized (POSTED) bill exists for the patient', async () => {
71
+ await page.goto(`patient/${patientUuid}/chart/billing-history`);
72
+ await page.getByRole('button', { name: /launch bill form|add bill|create bill/i }).click();
73
+
74
+ await billingFormPage.searchAndSelectBillableService(testServiceName);
75
+ await billingFormPage.selectPaymentMethodIfVisible();
76
+ await billingFormPage.saveBill();
77
+ await waitForSuccessNotification(page, /bill processed successfully/i);
78
+
79
+ const billsResponse = await api.get(`billing/bill?patient=${patientUuid}&v=full`);
80
+ const billsData = await billsResponse.json();
81
+ billUuid = billsData.results[0].uuid;
82
+ lineItemUuid = billsData.results[0].lineItems[0].uuid;
83
+ billsToCleanup.add(billUuid);
84
+
85
+ await billingDashboardPage.goto();
86
+ await billingDashboardPage.waitForBillsTableToLoad();
87
+ await billingDashboardPage.selectFilter('Pending confirmation');
88
+ await billingDashboardPage.waitForBillsTableToLoad();
89
+ await billingDashboardPage.clickInvoiceNumberLink(patientName);
90
+ await invoicePage.waitForInvoiceToLoad();
91
+
92
+ await invoicePage.finalizeBill();
93
+ await waitForSuccessNotification(page, /bill finalized/i);
94
+ await expect.poll(async () => await invoicePage.getInvoiceStatus()).toBe('POSTED');
95
+ });
96
+
97
+ await test.step('When the cashier requests a 10% discount on the line item', async () => {
98
+ // Open the line-item overflow menu and click "Request discount".
99
+ // The test ids on these controls embed the line item uuid, which keeps
100
+ // the selector stable even if Carbon menu structure changes.
101
+ await page.getByTestId(`action-menu-${lineItemUuid}`).click();
102
+ await page.getByTestId(`request-discount-button-${lineItemUuid}`).click();
103
+
104
+ await requestDiscountModal.submitPercentageDiscount(discountPercentage, justification);
105
+ await waitForSuccessNotification(page, /discount request submitted/i);
106
+ await expect(requestDiscountModal.modal()).toBeHidden();
107
+ });
108
+
109
+ await test.step('Then the discount appears as PENDING via the API and does not yet affect amount due', async () => {
110
+ const discountsResponse = await api.get(`billing/billDiscount?bill=${billUuid}&v=default`);
111
+ const discountsData = await discountsResponse.json();
112
+ expect(discountsData.results).toHaveLength(1);
113
+ const [discount] = discountsData.results;
114
+ expect(discount.status).toBe('PENDING');
115
+ expect(discount.lineItemUuid).toBe(lineItemUuid);
116
+ expect(discount.discountAmount).toBeCloseTo(expectedDiscountAmount, 2);
117
+
118
+ // Bill totals should still reflect the original price until approval.
119
+ const billResponse = await api.get(`billing/bill/${billUuid}`);
120
+ const billData = await billResponse.json();
121
+ expect(billData.amountAfterDiscount ?? billData.total).toBeCloseTo(expectedServicePrice, 2);
122
+ });
123
+
124
+ await test.step('When the admin approves the discount from the discount requests dashboard', async () => {
125
+ await discountRequestsPage.goto();
126
+ await discountRequestsPage.waitForLoaded();
127
+ await discountRequestsPage.openReviewForPatient(patientName);
128
+
129
+ await reviewModal.waitForLoaded();
130
+ await reviewModal.approveFirstPending();
131
+ await waitForSuccessNotification(page, /discount approved/i);
132
+ });
133
+
134
+ await test.step('Then the discount is APPROVED and net amount drops by the discount', async () => {
135
+ await expect
136
+ .poll(async () => {
137
+ const res = await api.get(`billing/billDiscount?bill=${billUuid}&v=default`);
138
+ const data = await res.json();
139
+ return data.results[0]?.status;
140
+ })
141
+ .toBe('APPROVED');
142
+
143
+ const billResponse = await api.get(`billing/bill/${billUuid}`);
144
+ const billData = await billResponse.json();
145
+ expect(billData.amountAfterDiscount).toBeCloseTo(expectedNetAmount, 2);
146
+ });
147
+
148
+ await test.step('And the invoice page shows the discounted net amount and matching amount due', async () => {
149
+ await invoicePage.goto(patientUuid, billUuid);
150
+ await invoicePage.waitForInvoiceToLoad();
151
+
152
+ const amountDue = extractNumericValue(await invoicePage.getAmountDue());
153
+ expect(amountDue).toBeCloseTo(expectedNetAmount, 2);
154
+ });
155
+
156
+ await test.step('When the cashier processes a payment that matches the discounted amount due', async () => {
157
+ await paymentPage.waitForPaymentForm();
158
+ await paymentPage.addPayment('Cash', expectedNetAmount);
159
+ expect(await paymentPage.isProcessPaymentButtonEnabled()).toBe(true);
160
+ await paymentPage.processPayment();
161
+ await waitForSuccessNotification(page, /payment processed successfully/i);
162
+ });
163
+
164
+ await test.step('Then the bill is marked PAID with no outstanding balance', async () => {
165
+ await page.reload();
166
+ await invoicePage.waitForInvoiceToLoad();
167
+ await expect.poll(async () => await invoicePage.getInvoiceStatus()).toBe('PAID');
168
+ expect(extractNumericValue(await invoicePage.getAmountDue())).toBe(0);
169
+
170
+ const billResponse = await api.get(`billing/bill/${billUuid}`);
171
+ const billData = await billResponse.json();
172
+ expect(billData.status).toBe('PAID');
173
+ });
174
+ });
175
+
176
+ test('Rejected discount leaves the bill amount due unchanged', async ({ page, api, patient }) => {
177
+ const billingDashboardPage = new BillingDashboardPage(page);
178
+ const billingFormPage = new BillingFormPage(page);
179
+ const invoicePage = new InvoicePage(page);
180
+ const requestDiscountModal = new DiscountRequestModal(page);
181
+ const discountRequestsPage = new DiscountRequestsAdminPage(page);
182
+ const reviewModal = new ReviewBillDiscountsModal(page);
183
+
184
+ const patientUuid = patient.uuid;
185
+ const patientName = patient.person.display;
186
+ const justification = `e2e rejected discount ${Date.now()}`;
187
+ let billUuid: string;
188
+ let lineItemUuid: string;
189
+
190
+ await test.step('Given a finalized bill with a pending line-item discount request', async () => {
191
+ await page.goto(`patient/${patientUuid}/chart/billing-history`);
192
+ await page.getByRole('button', { name: /launch bill form|add bill|create bill/i }).click();
193
+
194
+ await billingFormPage.searchAndSelectBillableService(testServiceName);
195
+ await billingFormPage.selectPaymentMethodIfVisible();
196
+ await billingFormPage.saveBill();
197
+ await waitForSuccessNotification(page, /bill processed successfully/i);
198
+
199
+ const billsResponse = await api.get(`billing/bill?patient=${patientUuid}&v=full`);
200
+ const billsData = await billsResponse.json();
201
+ billUuid = billsData.results[0].uuid;
202
+ lineItemUuid = billsData.results[0].lineItems[0].uuid;
203
+ billsToCleanup.add(billUuid);
204
+
205
+ await billingDashboardPage.goto();
206
+ await billingDashboardPage.waitForBillsTableToLoad();
207
+ await billingDashboardPage.selectFilter('Pending confirmation');
208
+ await billingDashboardPage.waitForBillsTableToLoad();
209
+ await billingDashboardPage.clickInvoiceNumberLink(patientName);
210
+ await invoicePage.waitForInvoiceToLoad();
211
+ await invoicePage.finalizeBill();
212
+ await waitForSuccessNotification(page, /bill finalized/i);
213
+ await expect.poll(async () => await invoicePage.getInvoiceStatus()).toBe('POSTED');
214
+
215
+ await page.getByTestId(`action-menu-${lineItemUuid}`).click();
216
+ await page.getByTestId(`request-discount-button-${lineItemUuid}`).click();
217
+ await requestDiscountModal.submitPercentageDiscount(15, justification);
218
+ await waitForSuccessNotification(page, /discount request submitted/i);
219
+ });
220
+
221
+ await test.step('When the admin rejects the discount request', async () => {
222
+ await discountRequestsPage.goto();
223
+ await discountRequestsPage.waitForLoaded();
224
+ await discountRequestsPage.openReviewForPatient(patientName);
225
+
226
+ await reviewModal.waitForLoaded();
227
+ await reviewModal.rejectFirstPending();
228
+ await waitForSuccessNotification(page, /discount rejected/i);
229
+ });
230
+
231
+ await test.step('Then the discount is REJECTED and the bill total is unchanged', async () => {
232
+ await expect
233
+ .poll(async () => {
234
+ const res = await api.get(`billing/billDiscount?bill=${billUuid}&v=default`);
235
+ const data = await res.json();
236
+ return data.results[0]?.status;
237
+ })
238
+ .toBe('REJECTED');
239
+
240
+ const billResponse = await api.get(`billing/bill/${billUuid}`);
241
+ const billData = await billResponse.json();
242
+ // Net amount equals the original total when no discount is approved.
243
+ expect(billData.amountAfterDiscount ?? billData.total).toBeCloseTo(expectedServicePrice, 2);
244
+ });
245
+
246
+ await test.step('And the rejected request is no longer in the pending queue', async () => {
247
+ await discountRequestsPage.goto();
248
+ await discountRequestsPage.waitForLoaded();
249
+ await discountRequestsPage.searchInput().fill(patientName);
250
+ await expect(
251
+ discountRequestsPage.requestsTable().locator('tbody tr').filter({ hasText: patientName }),
252
+ ).toHaveCount(0);
253
+ });
254
+ });
255
+ });
@@ -175,11 +175,11 @@ test.describe('Billing Dashboard workflow', () => {
175
175
  expect(lineItem.status).toBe('PAID');
176
176
  });
177
177
 
178
- // Also verify backend line items have paymentStatus set to PAID
178
+ // Also verify backend line items have status set to PAID
179
179
  const billResponse = await api.get(`billing/bill/${billUuid}`);
180
180
  const billData = await billResponse.json();
181
- billData.lineItems.forEach((lineItem: { paymentStatus: string }) => {
182
- expect(lineItem.paymentStatus).toBe('PAID');
181
+ billData.lineItems.forEach((lineItem: { status: string }) => {
182
+ expect(lineItem.status).toBe('PAID');
183
183
  });
184
184
  });
185
185
 
@@ -535,8 +535,8 @@ test.describe('Billing: Patient Chart workflow', () => {
535
535
  // Verify backend state
536
536
  const billResponse = await api.get(`billing/bill/${billUuid}?v=full`);
537
537
  const billData = await billResponse.json();
538
- billData.lineItems.forEach((lineItem: { paymentStatus: string }) => {
539
- expect(lineItem.paymentStatus).toBe('PAID');
538
+ billData.lineItems.forEach((lineItem: { status: string }) => {
539
+ expect(lineItem.status).toBe('PAID');
540
540
  });
541
541
  });
542
542
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-billing-app",
3
- "version": "1.1.2-pre.9",
3
+ "version": "1.2.0",
4
4
  "description": "O3 frontend module for handling billing concerns in healthcare settings",
5
5
  "browser": "dist/openmrs-esm-billing-app.js",
6
6
  "main": "src/index.ts",
@@ -9,18 +9,18 @@
9
9
  "homepage": "https://github.com/openmrs/openmrs-esm-billing-app#readme",
10
10
  "scripts": {
11
11
  "start": "openmrs develop",
12
- "analyze": "webpack --mode=production --env.analyze=true",
13
- "build": "webpack --mode production",
14
- "coverage": "yarn test --coverage",
12
+ "analyze": "rspack --mode=production --env.analyze=true",
13
+ "build": "rspack --mode production",
15
14
  "debug": "npm run serve",
16
15
  "extract-translations": "i18next 'src/**/*.component.tsx' 'src/**/*.workspace.tsx' 'src/**/*.modal.tsx' 'src/index.ts' --config ./tools/i18next-parser.config.js",
17
16
  "lint": "eslint src --ext ts,tsx --max-warnings=0",
18
17
  "postinstall": "husky install",
19
18
  "prettier": "prettier --config prettier.config.js --write \"src/**/*.{ts,tsx,css,scss}\" \"e2e/**/*.ts\"",
20
- "serve": "webpack serve --mode=development",
19
+ "serve": "rspack serve --mode=development",
21
20
  "test-e2e": "playwright test",
22
- "test": "cross-env TZ=UTC jest --config jest.config.js --verbose false --passWithNoTests",
23
- "test:watch": "cross-env TZ=UTC jest --watch --config jest.config.js",
21
+ "test": "cross-env TZ=UTC vitest run --passWithNoTests",
22
+ "test:watch": "cross-env TZ=UTC vitest watch",
23
+ "coverage": "cross-env TZ=UTC vitest run --coverage --passWithNoTests",
24
24
  "typescript": "tsc",
25
25
  "verify": "turbo lint && turbo typescript && turbo test --color --concurrency=5"
26
26
  },
@@ -51,7 +51,7 @@
51
51
  "zod": "^3.22.4"
52
52
  },
53
53
  "peerDependencies": {
54
- "@openmrs/esm-framework": "9.x",
54
+ "@openmrs/esm-framework": "10.x",
55
55
  "react": "18.x",
56
56
  "react-dom": "18.x",
57
57
  "react-i18next": "16.x",
@@ -61,21 +61,17 @@
61
61
  "devDependencies": {
62
62
  "@openmrs/esm-framework": "next",
63
63
  "@playwright/test": "^1.53.2",
64
- "@swc/cli": "^0.3.2",
65
- "@swc/core": "^1.3.106",
66
- "@swc/jest": "^0.2.31",
67
64
  "@testing-library/dom": "^9.3.4",
68
65
  "@testing-library/jest-dom": "^6.3.0",
69
66
  "@testing-library/react": "14.3.1",
70
67
  "@testing-library/user-event": "^14.5.2",
71
- "@types/jest": "^29.5.11",
72
68
  "@types/lodash-es": "^4.17.12",
73
69
  "@types/react": "^18.3.21",
74
70
  "@types/react-dom": "^18.3.0",
75
71
  "@types/webpack-env": "^1.18.4",
76
72
  "@typescript-eslint/eslint-plugin": "^8.0.0",
77
73
  "@typescript-eslint/parser": "^8.0.0",
78
- "babel-preset-minify": "^0.5.2",
74
+ "@vitest/coverage-v8": "^4.0.18",
79
75
  "concurrently": "^8.2.2",
80
76
  "cross-env": "^7.0.3",
81
77
  "d3-selection": "^3.0.0",
@@ -91,29 +87,24 @@
91
87
  "i18next": "^25.0.0",
92
88
  "i18next-parser": "^9.3.0",
93
89
  "identity-obj-proxy": "^3.0.0",
94
- "jest": "^29.7.0",
95
- "jest-cli": "^29.7.0",
96
- "jest-environment-jsdom": "^29.7.0",
90
+ "jsdom": "^29.0.2",
97
91
  "lint-staged": "^15.2.10",
98
92
  "lodash": "^4.17.21",
99
93
  "openmrs": "next",
100
- "pinst": "^3.0.0",
101
94
  "prettier": "^3.2.4",
102
95
  "react": "^18.3.1",
103
96
  "react-dom": "^18.3.1",
104
97
  "react-i18next": "^16.0.0",
105
98
  "react-router-dom": "^6.21.3",
106
99
  "rxjs": "^6.6.7",
107
- "sass": "^1.70.0",
108
- "swr": "^2.2.4",
100
+ "swr": "2.2.5",
109
101
  "turbo": "^2.5.2",
110
102
  "typescript": "^5.0.0",
111
- "webpack-dev-server": "^5.2.1"
103
+ "vitest": "^4.0.18"
112
104
  },
113
105
  "lint-staged": {
114
106
  "*.{ts,tsx}": "eslint --cache --fix --max-warnings 0",
115
107
  "*.{css,scss,ts,tsx}": "prettier --write --list-different"
116
108
  },
117
- "packageManager": "yarn@4.10.3",
118
- "stableVersion": "1.1.1"
109
+ "packageManager": "yarn@4.10.3"
119
110
  }
@@ -0,0 +1 @@
1
+ module.exports = require('openmrs/default-rspack-config');
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
2
  import { Layer, OverflowMenu, OverflowMenuItem } from '@carbon/react';
3
- import { isDesktop, launchWorkspace2, useLayoutType } from '@openmrs/esm-framework';
3
+ import { isDesktop, launchWorkspace2, showModal, useLayoutType } from '@openmrs/esm-framework';
4
4
  import { useTranslation } from 'react-i18next';
5
- import type { MappedBill } from '../types';
5
+ import { BillStatus, type MappedBill } from '../types';
6
6
  import styles from './bill-action-menu.scss';
7
7
 
8
8
  type BillActionMenuProps = {
@@ -14,6 +14,15 @@ type BillActionMenuProps = {
14
14
  const BillActionMenu: React.FC<BillActionMenuProps> = ({ bill, patientUuid, onMutate }) => {
15
15
  const { t } = useTranslation();
16
16
  const layout = useLayoutType();
17
+ const isPending = bill?.status === BillStatus.PENDING;
18
+
19
+ const handleDeleteBill = () => {
20
+ const dispose = showModal('delete-bill-confirmation-modal', {
21
+ bill,
22
+ onSuccess: onMutate,
23
+ closeModal: () => dispose(),
24
+ });
25
+ };
17
26
 
18
27
  return (
19
28
  <Layer>
@@ -33,6 +42,15 @@ const BillActionMenu: React.FC<BillActionMenuProps> = ({ bill, patientUuid, onMu
33
42
  })
34
43
  }
35
44
  />
45
+ {isPending && (
46
+ <OverflowMenuItem
47
+ className={styles.menuItem}
48
+ hasDivider
49
+ isDelete
50
+ itemText={t('deleteBill', 'Delete bill')}
51
+ onClick={handleDeleteBill}
52
+ />
53
+ )}
36
54
  </OverflowMenu>
37
55
  </Layer>
38
56
  );
@@ -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 { getDefaultsFromConfigSchema, launchWorkspace2, useConfig } from '@openmrs/esm-framework';
@@ -6,11 +7,11 @@ import { configSchema, type BillingConfig } from '../config-schema';
6
7
  import { useBills } from '../billing.resource';
7
8
  import BillHistory from './bill-history.component';
8
9
 
9
- const mockUseConfig = jest.mocked(useConfig<BillingConfig>);
10
- const mockUseBills = jest.mocked<typeof useBills>(useBills);
10
+ const mockUseConfig = vi.mocked(useConfig<BillingConfig>);
11
+ const mockUseBills = vi.mocked<typeof useBills>(useBills);
11
12
 
12
- jest.mock('../billing.resource', () => ({
13
- useBills: jest.fn(() => ({
13
+ vi.mock('../billing.resource', () => ({
14
+ useBills: vi.fn(() => ({
14
15
  bills: mockBillData,
15
16
  isLoading: false,
16
17
  isValidating: false,
@@ -46,13 +47,13 @@ describe('BillHistory', () => {
46
47
  mockUseConfig.mockReturnValue({ ...getDefaultsFromConfigSchema(configSchema), defaultCurrency: 'USD' });
47
48
  });
48
49
 
49
- test('should render loading datatable skeleton', () => {
50
+ it('should render loading datatable skeleton', () => {
50
51
  mockUseBills.mockReturnValueOnce({
51
52
  isLoading: true,
52
53
  isValidating: false,
53
54
  error: null,
54
55
  bills: [],
55
- mutate: jest.fn(),
56
+ mutate: vi.fn(),
56
57
  });
57
58
  render(<BillHistory {...testProps} />);
58
59
  const loadingSkeleton = screen.getByRole('table');
@@ -60,27 +61,27 @@ describe('BillHistory', () => {
60
61
  expect(loadingSkeleton).toHaveClass('cds--skeleton cds--data-table cds--data-table--zebra');
61
62
  });
62
63
 
63
- test('should render error state when API call fails', () => {
64
+ it('should render error state when API call fails', () => {
64
65
  mockUseBills.mockReturnValueOnce({
65
66
  isLoading: false,
66
67
  isValidating: false,
67
68
  error: new Error('some error'),
68
69
  bills: [],
69
- mutate: jest.fn(),
70
+ mutate: vi.fn(),
70
71
  });
71
72
  render(<BillHistory {...testProps} />);
72
73
  const errorState = screen.getByText(/Error/);
73
74
  expect(errorState).toBeInTheDocument();
74
75
  });
75
76
 
76
- test('should render bills table', async () => {
77
+ it('should render bills table', async () => {
77
78
  const user = userEvent.setup();
78
79
  mockUseBills.mockReturnValueOnce({
79
80
  isLoading: false,
80
81
  isValidating: false,
81
82
  error: null,
82
83
  bills: mockBillData as any,
83
- mutate: jest.fn(),
84
+ mutate: vi.fn(),
84
85
  });
85
86
  render(<BillHistory {...testProps} />);
86
87
 
@@ -108,34 +109,34 @@ describe('BillHistory', () => {
108
109
  await user.click(expandAllRowButton);
109
110
  });
110
111
 
111
- test('should render empty state view when there are no bills', () => {
112
+ it('should render empty state view when there are no bills', () => {
112
113
  mockUseBills.mockReturnValueOnce({
113
114
  isLoading: false,
114
115
  isValidating: false,
115
116
  error: null,
116
117
  bills: [],
117
- mutate: jest.fn(),
118
+ mutate: vi.fn(),
118
119
  });
119
120
  render(<BillHistory {...testProps} />);
120
121
  const emptyState = screen.getByText(/There are no bills to display./);
121
122
  expect(emptyState).toBeInTheDocument();
122
123
  });
123
124
 
124
- test('should show overflow menu with "Add items to bill" for PENDING bills', async () => {
125
+ it('should show overflow menu with "Add items to bill" for PENDING bills', async () => {
125
126
  const user = userEvent.setup();
126
127
  const pendingBill = {
127
128
  ...mockBillData[0],
128
129
  status: 'PENDING',
129
130
  dateCreated: '2024-01-01',
130
131
  receiptNumber: 'REC-001',
131
- lineItems: [{ uuid: 'item-1', item: 'Test', quantity: 1, price: 100, paymentStatus: 'PENDING' }],
132
+ lineItems: [{ uuid: 'item-1', item: 'Test', quantity: 1, price: 100, status: 'PENDING' }],
132
133
  };
133
134
  mockUseBills.mockReturnValueOnce({
134
135
  isLoading: false,
135
136
  isValidating: false,
136
137
  error: null,
137
138
  bills: [pendingBill] as any,
138
- mutate: jest.fn(),
139
+ mutate: vi.fn(),
139
140
  });
140
141
  render(<BillHistory {...testProps} />);
141
142
 
@@ -145,36 +146,36 @@ describe('BillHistory', () => {
145
146
  expect(screen.getByText(/add items to bill/i)).toBeInTheDocument();
146
147
  });
147
148
 
148
- test('should not show overflow menu for PAID bills', () => {
149
+ it('should not show overflow menu for PAID bills', () => {
149
150
  const paidBill = {
150
151
  ...mockBillData[0],
151
152
  status: 'PAID',
152
153
  dateCreated: '2024-01-01',
153
154
  receiptNumber: 'REC-001',
154
- lineItems: [{ uuid: 'item-1', item: 'Test', quantity: 1, price: 100, paymentStatus: 'PAID' }],
155
+ lineItems: [{ uuid: 'item-1', item: 'Test', quantity: 1, price: 100, status: 'PAID' }],
155
156
  };
156
157
  mockUseBills.mockReturnValueOnce({
157
158
  isLoading: false,
158
159
  isValidating: false,
159
160
  error: null,
160
161
  bills: [paidBill] as any,
161
- mutate: jest.fn(),
162
+ mutate: vi.fn(),
162
163
  });
163
164
  render(<BillHistory {...testProps} />);
164
165
 
165
166
  expect(screen.queryByTestId('action-menu-1')).not.toBeInTheDocument();
166
167
  });
167
168
 
168
- test('should launch workspace with billUuid when "Add items to bill" is clicked', async () => {
169
+ it('should launch workspace with billUuid when "Add items to bill" is clicked', async () => {
169
170
  const user = userEvent.setup();
170
- const mockMutate = jest.fn();
171
- const mockLaunchWorkspace2 = jest.mocked(launchWorkspace2);
171
+ const mockMutate = vi.fn();
172
+ const mockLaunchWorkspace2 = vi.mocked(launchWorkspace2);
172
173
  const pendingBill = {
173
174
  ...mockBillData[0],
174
175
  status: 'PENDING',
175
176
  dateCreated: '2024-01-01',
176
177
  receiptNumber: 'REC-001',
177
- lineItems: [{ uuid: 'item-1', item: 'Test', quantity: 1, price: 100, paymentStatus: 'PENDING' }],
178
+ lineItems: [{ uuid: 'item-1', item: 'Test', quantity: 1, price: 100, status: 'PENDING' }],
178
179
  };
179
180
  mockUseBills.mockReturnValueOnce({
180
181
  isLoading: false,
@@ -161,7 +161,7 @@ const EditBillLineItemModal: React.FC<EditBillLineItemModalProps> = ({ bill, clo
161
161
  {t('currentPrice', 'Current price')}: {convertToCurrency(item?.price, defaultCurrency)}
162
162
  </p>
163
163
  <p className={styles.label}>
164
- {t('serviceStatus', 'Service status')}: {item?.paymentStatus}
164
+ {t('serviceStatus', 'Service status')}: {item?.status}
165
165
  </p>
166
166
  <Controller
167
167
  name="quantity"