@openmrs/esm-billing-app 1.0.2-pre.613 → 1.0.2-pre.619

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 (55) hide show
  1. package/README.md +12 -6
  2. package/__mocks__/react-i18next.js +6 -5
  3. package/dist/2352.js +1 -1
  4. package/dist/2352.js.map +1 -1
  5. package/dist/4300.js +1 -1
  6. package/dist/4739.js +1 -1
  7. package/dist/4739.js.map +1 -1
  8. package/dist/7239.js +1 -1
  9. package/dist/7239.js.map +1 -1
  10. package/dist/8638.js +1 -1
  11. package/dist/8638.js.map +1 -1
  12. package/dist/main.js +1 -1
  13. package/dist/main.js.map +1 -1
  14. package/dist/openmrs-esm-billing-app.js +1 -1
  15. package/dist/openmrs-esm-billing-app.js.buildmanifest.json +19 -19
  16. package/dist/routes.json +1 -1
  17. package/e2e/README.md +19 -18
  18. package/package.json +2 -2
  19. package/src/bill-history/bill-history.test.tsx +37 -77
  20. package/src/bill-item-actions/edit-bill-item.component.tsx +7 -3
  21. package/src/bill-item-actions/edit-bill-item.test.tsx +17 -19
  22. package/src/billable-services/bill-waiver/patient-bills.component.tsx +3 -3
  23. package/src/billable-services/billable-service.resource.ts +4 -3
  24. package/src/billable-services/billable-services.component.tsx +5 -4
  25. package/src/billable-services/billable-services.test.tsx +3 -44
  26. package/src/billable-services/cash-point/cash-point-configuration.component.tsx +2 -2
  27. package/src/billable-services/create-edit/add-billable-service.component.tsx +2 -2
  28. package/src/billable-services/create-edit/add-billable-service.test.tsx +6 -6
  29. package/src/billable-services/payyment-modes/payment-modes-config.component.tsx +1 -1
  30. package/src/billing-form/billing-checkin-form.component.tsx +1 -2
  31. package/src/billing-form/billing-checkin-form.test.tsx +0 -2
  32. package/src/billing-form/billing-form.component.tsx +8 -4
  33. package/src/billing.resource.ts +13 -9
  34. package/src/bills-table/bills-table.test.tsx +97 -53
  35. package/src/config-schema.ts +52 -18
  36. package/src/invoice/invoice-table.component.tsx +9 -9
  37. package/src/invoice/invoice-table.scss +1 -5
  38. package/src/invoice/invoice-table.test.tsx +24 -39
  39. package/src/invoice/invoice.component.tsx +8 -6
  40. package/src/invoice/invoice.scss +7 -4
  41. package/src/invoice/invoice.test.tsx +12 -47
  42. package/src/invoice/payments/payment-form/payment-form.test.tsx +8 -10
  43. package/src/invoice/payments/payment-history/payment-history.component.tsx +6 -4
  44. package/src/invoice/payments/payment-history/payment-history.test.tsx +9 -14
  45. package/src/invoice/payments/payments.component.test.tsx +20 -6
  46. package/src/invoice/printable-invoice/print-receipt.component.tsx +1 -1
  47. package/src/invoice/printable-invoice/print-receipt.test.tsx +14 -25
  48. package/src/invoice/printable-invoice/printable-footer.component.tsx +2 -2
  49. package/src/invoice/printable-invoice/printable-footer.test.tsx +4 -13
  50. package/src/invoice/printable-invoice/printable-invoice-header.component.tsx +5 -4
  51. package/src/invoice/printable-invoice/printable-invoice-header.test.tsx +11 -11
  52. package/src/invoice/printable-invoice/printable-invoice.component.tsx +11 -11
  53. package/src/metrics-cards/metrics-cards.test.tsx +18 -5
  54. package/src/modal/require-payment-modal.test.tsx +24 -19
  55. package/translations/en.json +18 -0
@@ -1 +1 @@
1
- var _openmrs_esm_billing_app;(()=>{"use strict";var e,r,t,n,o,a,i,l,s,u,f,p,c,d,h,m,v,g,b,y,w,_={45120:(e,r,t)=>{var n={"./start":()=>Promise.all([t.e(2177),t.e(2747),t.e(1146),t.e(7239),t.e(6072),t.e(3006),t.e(8638)]).then((()=>()=>t(88638)))},o=(e,r)=>(t.R=r,r=t.o(n,e)?n[e]():Promise.resolve().then((()=>{throw new Error('Module "'+e+'" does not exist in container.')})),t.R=void 0,r),a=(e,r)=>{if(t.S){var n="default",o=t.S[n];if(o&&o!==e)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return t.S[n]=e,t.I(n,r)}};t.d(r,{get:()=>o,init:()=>a})}},P={};function S(e){var r=P[e];if(void 0!==r)return r.exports;var t=P[e]={id:e,exports:{}};return _[e].call(t.exports,t,t.exports,S),t.exports}S.m=_,S.c=P,S.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return S.d(r,{a:r}),r},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,S.t=function(t,n){if(1&n&&(t=this(t)),8&n)return t;if("object"==typeof t&&t){if(4&n&&t.__esModule)return t;if(16&n&&"function"==typeof t.then)return t}var o=Object.create(null);S.r(o);var a={};e=e||[null,r({}),r([]),r(r)];for(var i=2&n&&t;"object"==typeof i&&!~e.indexOf(i);i=r(i))Object.getOwnPropertyNames(i).forEach((e=>a[e]=()=>t[e]));return a.default=()=>t,S.d(o,a),o},S.d=(e,r)=>{for(var t in r)S.o(r,t)&&!S.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},S.f={},S.e=e=>Promise.all(Object.keys(S.f).reduce(((r,t)=>(S.f[t](e,r),r)),[])),S.u=e=>e+".js",S.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),S.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t={},n="@openmrs/esm-billing-app:",S.l=(e,r,o,a)=>{if(t[e])t[e].push(r);else{var i,l;if(void 0!==o)for(var s=document.getElementsByTagName("script"),u=0;u<s.length;u++){var f=s[u];if(f.getAttribute("src")==e||f.getAttribute("data-webpack")==n+o){i=f;break}}i||(l=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,S.nc&&i.setAttribute("nonce",S.nc),i.setAttribute("data-webpack",n+o),i.src=e),t[e]=[r];var p=(r,n)=>{i.onerror=i.onload=null,clearTimeout(c);var o=t[e];if(delete t[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach((e=>e(n))),r)return r(n)},c=setTimeout(p.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),l&&document.head.appendChild(i)}},S.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{S.S={};var e={},r={};S.I=(t,n)=>{n||(n=[]);var o=r[t];if(o||(o=r[t]={}),!(n.indexOf(o)>=0)){if(n.push(o),e[t])return e[t];S.o(S.S,t)||(S.S[t]={});var a=S.S[t],i="@openmrs/esm-billing-app",l=(e,r,t,n)=>{var o=a[e]=a[e]||{},l=o[r];(!l||!l.loaded&&(!n!=!l.eager?n:i>l.from))&&(o[r]={get:t,from:i,eager:!!n})},s=[];return"default"===t&&(l("@openmrs/esm-framework","8.0.1-pre.3308",(()=>Promise.all([S.e(2177),S.e(590),S.e(2747),S.e(7935),S.e(6072),S.e(1997),S.e(3006)]).then((()=>()=>S(87935))))),l("@openmrs/esm-patient-common-lib","11.3.1-pre.8816",(()=>Promise.all([S.e(2177),S.e(590),S.e(2747),S.e(7692),S.e(1146),S.e(6072),S.e(1997),S.e(3006)]).then((()=>()=>S(87692))))),l("react-dom","18.2.0",(()=>Promise.all([S.e(961),S.e(6072)]).then((()=>()=>S(40961))))),l("react-i18next","14.0.1",(()=>Promise.all([S.e(7255),S.e(6072)]).then((()=>()=>S(77255))))),l("react","18.2.0",(()=>S.e(6540).then((()=>()=>S(96540))))),l("rxjs","6.6.7",(()=>S.e(3184).then((()=>()=>S(63184))))),l("swr/immutable","2.3.3",(()=>Promise.all([S.e(2177),S.e(6072),S.e(4225)]).then((()=>()=>S(54225))))),l("swr/infinite","2.3.3",(()=>Promise.all([S.e(2177),S.e(6072),S.e(3041)]).then((()=>()=>S(23041)))))),e[t]=s.length?Promise.all(s).then((()=>e[t]=1)):1}}})(),(()=>{var e;S.g.importScripts&&(e=S.g.location+"");var r=S.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),S.p=e})(),o=e=>{var r=e=>e.split(".").map((e=>+e==e?+e:e)),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),n=t[1]?r(t[1]):[];return t[2]&&(n.length++,n.push.apply(n,r(t[2]))),t[3]&&(n.push([]),n.push.apply(n,r(t[3]))),n},a=(e,r)=>{e=o(e),r=o(r);for(var t=0;;){if(t>=e.length)return t<r.length&&"u"!=(typeof r[t])[0];var n=e[t],a=(typeof n)[0];if(t>=r.length)return"u"==a;var i=r[t],l=(typeof i)[0];if(a!=l)return"o"==a&&"n"==l||"s"==l||"u"==a;if("o"!=a&&"u"!=a&&n!=i)return n<i;t++}},i=e=>{var r=e[0],t="";if(1===e.length)return"*";if(r+.5){t+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var n=1,o=1;o<e.length;o++)n--,t+="u"==(typeof(l=e[o]))[0]?"-":(n>0?".":"")+(n=2,l);return t}var a=[];for(o=1;o<e.length;o++){var l=e[o];a.push(0===l?"not("+s()+")":1===l?"("+s()+" || "+s()+")":2===l?a.pop()+" "+a.pop():i(l))}return s();function s(){return a.pop().replace(/^\((.+)\)$/,"$1")}},l=(e,r)=>{if(0 in e){r=o(r);var t=e[0],n=t<0;n&&(t=-t-1);for(var a=0,i=1,s=!0;;i++,a++){var u,f,p=i<e.length?(typeof e[i])[0]:"";if(a>=r.length||"o"==(f=(typeof(u=r[a]))[0]))return!s||("u"==p?i>t&&!n:""==p!=n);if("u"==f){if(!s||"u"!=p)return!1}else if(s)if(p==f)if(i<=t){if(u!=e[i])return!1}else{if(n?u>e[i]:u<e[i])return!1;u!=e[i]&&(s=!1)}else if("s"!=p&&"n"!=p){if(n||i<=t)return!1;s=!1,i--}else{if(i<=t||f<p!=n)return!1;s=!1}else"s"!=p&&"n"!=p&&(s=!1,i--)}}var c=[],d=c.pop.bind(c);for(a=1;a<e.length;a++){var h=e[a];c.push(1==h?d()|d():2==h?d()&d():h?l(h,r):!d())}return!!d()},s=(e,r)=>e&&S.o(e,r),u=e=>(e.loaded=1,e.get()),f=e=>Object.keys(e).reduce(((r,t)=>(e[t].eager&&(r[t]=e[t]),r)),{}),p=(e,r,t)=>{var n=t?f(e[r]):e[r];return Object.keys(n).reduce(((e,r)=>!e||!n[e].loaded&&a(e,r)?r:e),0)},c=(e,r,t,n)=>"Unsatisfied version "+t+" from "+(t&&e[r][t].from)+" of shared singleton module "+r+" (required "+i(n)+")",d=e=>{throw new Error(e)},h=e=>{"undefined"!=typeof console&&console.warn&&console.warn(e)},m=(e,r,t)=>t?t():((e,r)=>d("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),v=(e=>function(r,t,n,o,a){var i=S.I(r);return i&&i.then&&!n?i.then(e.bind(e,r,S.S[r],t,!1,o,a)):e(r,S.S[r],t,n,o,a)})(((e,r,t,n,o,a)=>{if(!s(r,t))return m(e,t,a);var i=p(r,t,n);return l(o,i)||h(c(r,t,i,o)),u(r[t][i])})),g={},b={16072:()=>v("default","react",!1,[1,18],(()=>S.e(6540).then((()=>()=>S(96540))))),44209:()=>v("default","swr/immutable",!1,[1,2],(()=>S.e(6606).then((()=>()=>S(54225))))),53083:()=>v("default","rxjs",!1,[1,6],(()=>S.e(3184).then((()=>()=>S(63184))))),56339:()=>v("default","swr/infinite",!1,[1,2],(()=>S.e(5422).then((()=>()=>S(23041))))),15847:()=>v("default","@openmrs/esm-framework",!1,[1,8],(()=>Promise.all([S.e(590),S.e(7935),S.e(1997)]).then((()=>()=>S(87935))))),53941:()=>v("default","react-i18next",!1,[1,11],(()=>S.e(7255).then((()=>()=>S(77255))))),92646:()=>v("default","react-dom",!1,[1,18],(()=>S.e(961).then((()=>()=>S(40961))))),80879:()=>v("default","@openmrs/esm-patient-common-lib",!1,[1,10],(()=>Promise.all([S.e(590),S.e(7692),S.e(1997)]).then((()=>()=>S(87692)))))},y={1997:[44209,53083,56339],3006:[15847,53941,92646],6072:[16072],8638:[80879]},w={},S.f.consumes=(e,r)=>{S.o(y,e)&&y[e].forEach((e=>{if(S.o(g,e))return r.push(g[e]);if(!w[e]){var t=r=>{g[e]=0,S.m[e]=t=>{delete S.c[e],t.exports=r()}};w[e]=!0;var n=r=>{delete g[e],S.m[e]=t=>{throw delete S.c[e],r}};try{var o=b[e]();o.then?r.push(g[e]=o.then(t).catch(n)):t(o)}catch(e){n(e)}}}))},(()=>{var e={6803:0};S.f.j=(r,t)=>{var n=S.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else if(/^(1997|3006|6072)$/.test(r))e[r]=0;else{var o=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=o);var a=S.p+S.u(r),i=new Error;S.l(a,(t=>{if(S.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var o=t&&("load"===t.type?"missing":t.type),a=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+o+": "+a+")",i.name="ChunkLoadError",i.type=o,i.request=a,n[1](i)}}),"chunk-"+r,r)}};var r=(r,t)=>{var n,o,[a,i,l]=t,s=0;if(a.some((r=>0!==e[r]))){for(n in i)S.o(i,n)&&(S.m[n]=i[n]);l&&l(S)}for(r&&r(t);s<a.length;s++)o=a[s],S.o(e,o)&&e[o]&&e[o][0](),e[o]=0},t=globalThis.webpackChunk_openmrs_esm_billing_app=globalThis.webpackChunk_openmrs_esm_billing_app||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),S.nc=void 0;var j=S(45120);_openmrs_esm_billing_app=j})();
1
+ var _openmrs_esm_billing_app;(()=>{"use strict";var e,r,t,n,o,a,i,l,s,u,f,p,c,d,h,m,v,g,b,y,w,_={45120:(e,r,t)=>{var n={"./start":()=>Promise.all([t.e(2177),t.e(2747),t.e(1146),t.e(7239),t.e(6072),t.e(3006),t.e(8638)]).then((()=>()=>t(88638)))},o=(e,r)=>(t.R=r,r=t.o(n,e)?n[e]():Promise.resolve().then((()=>{throw new Error('Module "'+e+'" does not exist in container.')})),t.R=void 0,r),a=(e,r)=>{if(t.S){var n="default",o=t.S[n];if(o&&o!==e)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return t.S[n]=e,t.I(n,r)}};t.d(r,{get:()=>o,init:()=>a})}},P={};function S(e){var r=P[e];if(void 0!==r)return r.exports;var t=P[e]={id:e,exports:{}};return _[e].call(t.exports,t,t.exports,S),t.exports}S.m=_,S.c=P,S.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return S.d(r,{a:r}),r},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,S.t=function(t,n){if(1&n&&(t=this(t)),8&n)return t;if("object"==typeof t&&t){if(4&n&&t.__esModule)return t;if(16&n&&"function"==typeof t.then)return t}var o=Object.create(null);S.r(o);var a={};e=e||[null,r({}),r([]),r(r)];for(var i=2&n&&t;"object"==typeof i&&!~e.indexOf(i);i=r(i))Object.getOwnPropertyNames(i).forEach((e=>a[e]=()=>t[e]));return a.default=()=>t,S.d(o,a),o},S.d=(e,r)=>{for(var t in r)S.o(r,t)&&!S.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},S.f={},S.e=e=>Promise.all(Object.keys(S.f).reduce(((r,t)=>(S.f[t](e,r),r)),[])),S.u=e=>e+".js",S.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),S.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t={},n="@openmrs/esm-billing-app:",S.l=(e,r,o,a)=>{if(t[e])t[e].push(r);else{var i,l;if(void 0!==o)for(var s=document.getElementsByTagName("script"),u=0;u<s.length;u++){var f=s[u];if(f.getAttribute("src")==e||f.getAttribute("data-webpack")==n+o){i=f;break}}i||(l=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,S.nc&&i.setAttribute("nonce",S.nc),i.setAttribute("data-webpack",n+o),i.src=e),t[e]=[r];var p=(r,n)=>{i.onerror=i.onload=null,clearTimeout(c);var o=t[e];if(delete t[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach((e=>e(n))),r)return r(n)},c=setTimeout(p.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),l&&document.head.appendChild(i)}},S.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{S.S={};var e={},r={};S.I=(t,n)=>{n||(n=[]);var o=r[t];if(o||(o=r[t]={}),!(n.indexOf(o)>=0)){if(n.push(o),e[t])return e[t];S.o(S.S,t)||(S.S[t]={});var a=S.S[t],i="@openmrs/esm-billing-app",l=(e,r,t,n)=>{var o=a[e]=a[e]||{},l=o[r];(!l||!l.loaded&&(!n!=!l.eager?n:i>l.from))&&(o[r]={get:t,from:i,eager:!!n})},s=[];return"default"===t&&(l("@openmrs/esm-framework","8.0.1-pre.3308",(()=>Promise.all([S.e(2177),S.e(590),S.e(2747),S.e(7935),S.e(6072),S.e(1997),S.e(3006)]).then((()=>()=>S(87935))))),l("@openmrs/esm-patient-common-lib","11.3.1-pre.8819",(()=>Promise.all([S.e(2177),S.e(590),S.e(2747),S.e(7692),S.e(1146),S.e(6072),S.e(1997),S.e(3006)]).then((()=>()=>S(87692))))),l("react-dom","18.2.0",(()=>Promise.all([S.e(961),S.e(6072)]).then((()=>()=>S(40961))))),l("react-i18next","14.0.1",(()=>Promise.all([S.e(7255),S.e(6072)]).then((()=>()=>S(77255))))),l("react","18.2.0",(()=>S.e(6540).then((()=>()=>S(96540))))),l("rxjs","6.6.7",(()=>S.e(3184).then((()=>()=>S(63184))))),l("swr/immutable","2.3.3",(()=>Promise.all([S.e(2177),S.e(6072),S.e(4225)]).then((()=>()=>S(54225))))),l("swr/infinite","2.3.3",(()=>Promise.all([S.e(2177),S.e(6072),S.e(3041)]).then((()=>()=>S(23041)))))),e[t]=s.length?Promise.all(s).then((()=>e[t]=1)):1}}})(),(()=>{var e;S.g.importScripts&&(e=S.g.location+"");var r=S.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),S.p=e})(),o=e=>{var r=e=>e.split(".").map((e=>+e==e?+e:e)),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),n=t[1]?r(t[1]):[];return t[2]&&(n.length++,n.push.apply(n,r(t[2]))),t[3]&&(n.push([]),n.push.apply(n,r(t[3]))),n},a=(e,r)=>{e=o(e),r=o(r);for(var t=0;;){if(t>=e.length)return t<r.length&&"u"!=(typeof r[t])[0];var n=e[t],a=(typeof n)[0];if(t>=r.length)return"u"==a;var i=r[t],l=(typeof i)[0];if(a!=l)return"o"==a&&"n"==l||"s"==l||"u"==a;if("o"!=a&&"u"!=a&&n!=i)return n<i;t++}},i=e=>{var r=e[0],t="";if(1===e.length)return"*";if(r+.5){t+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var n=1,o=1;o<e.length;o++)n--,t+="u"==(typeof(l=e[o]))[0]?"-":(n>0?".":"")+(n=2,l);return t}var a=[];for(o=1;o<e.length;o++){var l=e[o];a.push(0===l?"not("+s()+")":1===l?"("+s()+" || "+s()+")":2===l?a.pop()+" "+a.pop():i(l))}return s();function s(){return a.pop().replace(/^\((.+)\)$/,"$1")}},l=(e,r)=>{if(0 in e){r=o(r);var t=e[0],n=t<0;n&&(t=-t-1);for(var a=0,i=1,s=!0;;i++,a++){var u,f,p=i<e.length?(typeof e[i])[0]:"";if(a>=r.length||"o"==(f=(typeof(u=r[a]))[0]))return!s||("u"==p?i>t&&!n:""==p!=n);if("u"==f){if(!s||"u"!=p)return!1}else if(s)if(p==f)if(i<=t){if(u!=e[i])return!1}else{if(n?u>e[i]:u<e[i])return!1;u!=e[i]&&(s=!1)}else if("s"!=p&&"n"!=p){if(n||i<=t)return!1;s=!1,i--}else{if(i<=t||f<p!=n)return!1;s=!1}else"s"!=p&&"n"!=p&&(s=!1,i--)}}var c=[],d=c.pop.bind(c);for(a=1;a<e.length;a++){var h=e[a];c.push(1==h?d()|d():2==h?d()&d():h?l(h,r):!d())}return!!d()},s=(e,r)=>e&&S.o(e,r),u=e=>(e.loaded=1,e.get()),f=e=>Object.keys(e).reduce(((r,t)=>(e[t].eager&&(r[t]=e[t]),r)),{}),p=(e,r,t)=>{var n=t?f(e[r]):e[r];return Object.keys(n).reduce(((e,r)=>!e||!n[e].loaded&&a(e,r)?r:e),0)},c=(e,r,t,n)=>"Unsatisfied version "+t+" from "+(t&&e[r][t].from)+" of shared singleton module "+r+" (required "+i(n)+")",d=e=>{throw new Error(e)},h=e=>{"undefined"!=typeof console&&console.warn&&console.warn(e)},m=(e,r,t)=>t?t():((e,r)=>d("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),v=(e=>function(r,t,n,o,a){var i=S.I(r);return i&&i.then&&!n?i.then(e.bind(e,r,S.S[r],t,!1,o,a)):e(r,S.S[r],t,n,o,a)})(((e,r,t,n,o,a)=>{if(!s(r,t))return m(e,t,a);var i=p(r,t,n);return l(o,i)||h(c(r,t,i,o)),u(r[t][i])})),g={},b={16072:()=>v("default","react",!1,[1,18],(()=>S.e(6540).then((()=>()=>S(96540))))),44209:()=>v("default","swr/immutable",!1,[1,2],(()=>S.e(6606).then((()=>()=>S(54225))))),53083:()=>v("default","rxjs",!1,[1,6],(()=>S.e(3184).then((()=>()=>S(63184))))),56339:()=>v("default","swr/infinite",!1,[1,2],(()=>S.e(5422).then((()=>()=>S(23041))))),15847:()=>v("default","@openmrs/esm-framework",!1,[1,8],(()=>Promise.all([S.e(590),S.e(7935),S.e(1997)]).then((()=>()=>S(87935))))),53941:()=>v("default","react-i18next",!1,[1,11],(()=>S.e(7255).then((()=>()=>S(77255))))),92646:()=>v("default","react-dom",!1,[1,18],(()=>S.e(961).then((()=>()=>S(40961))))),80879:()=>v("default","@openmrs/esm-patient-common-lib",!1,[1,10],(()=>Promise.all([S.e(590),S.e(7692),S.e(1997)]).then((()=>()=>S(87692)))))},y={1997:[44209,53083,56339],3006:[15847,53941,92646],6072:[16072],8638:[80879]},w={},S.f.consumes=(e,r)=>{S.o(y,e)&&y[e].forEach((e=>{if(S.o(g,e))return r.push(g[e]);if(!w[e]){var t=r=>{g[e]=0,S.m[e]=t=>{delete S.c[e],t.exports=r()}};w[e]=!0;var n=r=>{delete g[e],S.m[e]=t=>{throw delete S.c[e],r}};try{var o=b[e]();o.then?r.push(g[e]=o.then(t).catch(n)):t(o)}catch(e){n(e)}}}))},(()=>{var e={6803:0};S.f.j=(r,t)=>{var n=S.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else if(/^(1997|3006|6072)$/.test(r))e[r]=0;else{var o=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=o);var a=S.p+S.u(r),i=new Error;S.l(a,(t=>{if(S.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var o=t&&("load"===t.type?"missing":t.type),a=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+o+": "+a+")",i.name="ChunkLoadError",i.type=o,i.request=a,n[1](i)}}),"chunk-"+r,r)}};var r=(r,t)=>{var n,o,[a,i,l]=t,s=0;if(a.some((r=>0!==e[r]))){for(n in i)S.o(i,n)&&(S.m[n]=i[n]);l&&l(S)}for(r&&r(t);s<a.length;s++)o=a[s],S.o(e,o)&&e[o]&&e[o][0](),e[o]=0},t=globalThis.webpackChunk_openmrs_esm_billing_app=globalThis.webpackChunk_openmrs_esm_billing_app||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),S.nc=void 0;var j=S(45120);_openmrs_esm_billing_app=j})();
@@ -288,9 +288,9 @@
288
288
  "initial": false,
289
289
  "entry": false,
290
290
  "recorded": false,
291
- "size": 54091,
291
+ "size": 54144,
292
292
  "sizes": {
293
- "javascript": 54091
293
+ "javascript": 54144
294
294
  },
295
295
  "names": [],
296
296
  "idHints": [],
@@ -304,7 +304,7 @@
304
304
  "auxiliaryFiles": [
305
305
  "2352.js.map"
306
306
  ],
307
- "hash": "228b452941a44feb",
307
+ "hash": "efb884001d4b67ef",
308
308
  "childrenByOrder": {}
309
309
  },
310
310
  {
@@ -545,9 +545,9 @@
545
545
  "initial": false,
546
546
  "entry": false,
547
547
  "recorded": false,
548
- "size": 6629,
548
+ "size": 7220,
549
549
  "sizes": {
550
- "javascript": 6629
550
+ "javascript": 7220
551
551
  },
552
552
  "names": [],
553
553
  "idHints": [],
@@ -559,7 +559,7 @@
559
559
  "4300.js"
560
560
  ],
561
561
  "auxiliaryFiles": [],
562
- "hash": "20a747c2c8b51ede",
562
+ "hash": "732ad7bfb7e8e080",
563
563
  "childrenByOrder": {}
564
564
  },
565
565
  {
@@ -633,9 +633,9 @@
633
633
  "initial": false,
634
634
  "entry": false,
635
635
  "recorded": false,
636
- "size": 30361,
636
+ "size": 30413,
637
637
  "sizes": {
638
- "javascript": 30361
638
+ "javascript": 30413
639
639
  },
640
640
  "names": [],
641
641
  "idHints": [],
@@ -649,7 +649,7 @@
649
649
  "auxiliaryFiles": [
650
650
  "4739.js.map"
651
651
  ],
652
- "hash": "b7886654e8f73ef7",
652
+ "hash": "442e36091b68bbb9",
653
653
  "childrenByOrder": {}
654
654
  },
655
655
  {
@@ -945,7 +945,7 @@
945
945
  "auxiliaryFiles": [
946
946
  "openmrs-esm-billing-app.js.map"
947
947
  ],
948
- "hash": "34ab597441df9f5c",
948
+ "hash": "8d5cf77fbcafd122",
949
949
  "childrenByOrder": {}
950
950
  },
951
951
  {
@@ -1042,9 +1042,9 @@
1042
1042
  "entry": false,
1043
1043
  "recorded": false,
1044
1044
  "reason": "split chunk (cache group: defaultVendors)",
1045
- "size": 543655,
1045
+ "size": 532423,
1046
1046
  "sizes": {
1047
- "javascript": 543655
1047
+ "javascript": 532423
1048
1048
  },
1049
1049
  "names": [],
1050
1050
  "idHints": [
@@ -1059,7 +1059,7 @@
1059
1059
  "auxiliaryFiles": [
1060
1060
  "7239.js.map"
1061
1061
  ],
1062
- "hash": "d1850553f426b2ae",
1062
+ "hash": "91da4c23fb362f60",
1063
1063
  "childrenByOrder": {}
1064
1064
  },
1065
1065
  {
@@ -1236,9 +1236,9 @@
1236
1236
  "initial": false,
1237
1237
  "entry": false,
1238
1238
  "recorded": false,
1239
- "size": 1096271,
1239
+ "size": 1096899,
1240
1240
  "sizes": {
1241
- "javascript": 1096229,
1241
+ "javascript": 1096857,
1242
1242
  "consume-shared": 42
1243
1243
  },
1244
1244
  "names": [],
@@ -1252,7 +1252,7 @@
1252
1252
  "auxiliaryFiles": [
1253
1253
  "8638.js.map"
1254
1254
  ],
1255
- "hash": "4ad039bd571bfe07",
1255
+ "hash": "d2a02724e8b58df4",
1256
1256
  "childrenByOrder": {}
1257
1257
  },
1258
1258
  {
@@ -1260,10 +1260,10 @@
1260
1260
  "initial": true,
1261
1261
  "entry": true,
1262
1262
  "recorded": false,
1263
- "size": 5103056,
1263
+ "size": 5092452,
1264
1264
  "sizes": {
1265
1265
  "consume-shared": 210,
1266
- "javascript": 5080527,
1266
+ "javascript": 5069923,
1267
1267
  "share-init": 336,
1268
1268
  "runtime": 21983
1269
1269
  },
@@ -1280,7 +1280,7 @@
1280
1280
  "auxiliaryFiles": [
1281
1281
  "main.js.map"
1282
1282
  ],
1283
- "hash": "b05adb85abc41e33",
1283
+ "hash": "26a57469b2e748ef",
1284
1284
  "childrenByOrder": {}
1285
1285
  },
1286
1286
  {
package/dist/routes.json CHANGED
@@ -1 +1 @@
1
- {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":">=2.24.0","fhir2":">=1.2"},"pages":[{"component":"billableServicesHome","route":"billable-services"}],"extensions":[{"component":"billingDashboardLink","name":"billing-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"billing","title":"billing","slot":"billing-dashboard-slot"},"featureFlag":"billing"},{"component":"root","name":"billing-dashboard-root","slot":"billing-dashboard-slot"},{"name":"billing-patient-summary","component":"billingPatientSummary","slot":"patient-chart-billing-dashboard-slot","order":10,"meta":{"columnSpan":4}},{"name":"billing-summary-dashboard-link","component":"billingSummaryDashboardLink","slot":"patient-chart-dashboard-slot","order":11,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-billing-dashboard-slot","path":"Billing history"},"featureFlag":"billing"},{"name":"billable-services-app-menu-item","component":"billableServicesAppMenuItem","slot":"app-menu-item-slot","meta":{"name":"Billable Services"}},{"name":"billing-checkin-form","slot":"extra-visit-attribute-slot","component":"billingCheckInForm","featureFlag":"billing"},{"slot":"system-admin-page-card-link-slot","component":"billableServicesCardLink","name":"billable-services-admin-card-link"},{"name":"patient-banner-billing-tags","component":"visitAttributeTags","slot":"patient-banner-tags-slot","order":2},{"name":"billing-home-tiles-ext","slot":"billing-home-tiles-slot","component":"serviceMetrics"},{"name":"edit-bill-line-item-dialog","component":"editBillLineItemDialog","online":true,"offline":true}],"modals":[{"name":"require-billing-modal","component":"requirePaymentModal"}],"workspaces":[{"name":"billing-form-workspace","title":"billingForm","component":"billingFormWorkspace","type":"form"}],"featureFlags":[{"flagName":"billing","label":"Billing module","description":"This feature introduces navigation links on the patient chart and home page to allow accessing the billing module features"}],"version":"1.0.2-pre.613"}
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":">=2.24.0","fhir2":">=1.2"},"pages":[{"component":"billableServicesHome","route":"billable-services"}],"extensions":[{"component":"billingDashboardLink","name":"billing-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"billing","title":"billing","slot":"billing-dashboard-slot"},"featureFlag":"billing"},{"component":"root","name":"billing-dashboard-root","slot":"billing-dashboard-slot"},{"name":"billing-patient-summary","component":"billingPatientSummary","slot":"patient-chart-billing-dashboard-slot","order":10,"meta":{"columnSpan":4}},{"name":"billing-summary-dashboard-link","component":"billingSummaryDashboardLink","slot":"patient-chart-dashboard-slot","order":11,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-billing-dashboard-slot","path":"Billing history"},"featureFlag":"billing"},{"name":"billable-services-app-menu-item","component":"billableServicesAppMenuItem","slot":"app-menu-item-slot","meta":{"name":"Billable Services"}},{"name":"billing-checkin-form","slot":"extra-visit-attribute-slot","component":"billingCheckInForm","featureFlag":"billing"},{"slot":"system-admin-page-card-link-slot","component":"billableServicesCardLink","name":"billable-services-admin-card-link"},{"name":"patient-banner-billing-tags","component":"visitAttributeTags","slot":"patient-banner-tags-slot","order":2},{"name":"billing-home-tiles-ext","slot":"billing-home-tiles-slot","component":"serviceMetrics"},{"name":"edit-bill-line-item-dialog","component":"editBillLineItemDialog","online":true,"offline":true}],"modals":[{"name":"require-billing-modal","component":"requirePaymentModal"}],"workspaces":[{"name":"billing-form-workspace","title":"billingForm","component":"billingFormWorkspace","type":"form"}],"featureFlags":[{"flagName":"billing","label":"Billing module","description":"This feature introduces navigation links on the patient chart and home page to allow accessing the billing module features"}],"version":"1.0.2-pre.619"}
package/e2e/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # E2E Tests
2
2
 
3
- This directory contains an E2E test suite using the [Playwright](https://playwright.dev)
4
- framework.
3
+ This directory contains an E2E test suite using the [Playwright](https://playwright.dev) framework.
5
4
 
6
5
  ## Getting Started
7
6
 
@@ -12,13 +11,14 @@ Once everything is set up, make sure the dev server is running by using:
12
11
  ```sh
13
12
  yarn start --sources 'packages/esm-*-app/'
14
13
  ```
14
+
15
15
  Then, in a separate terminal, run:
16
16
 
17
17
  ```sh
18
18
  yarn test-e2e --headed
19
19
  ```
20
20
 
21
- By default, the test suite will run against the http://localhost:8080.
21
+ By default, the test suite will run against the dev server at http://localhost:8080.
22
22
  You can override this by exporting `E2E_BASE_URL` environment variables beforehand:
23
23
 
24
24
  ```sh
@@ -28,15 +28,16 @@ export E2E_BASE_URL=https://dev3.openmrs.org/openmrs
28
28
  # Run all e2e tests:
29
29
  yarn test-e2e --headed
30
30
  ```
31
+
31
32
  To run a specific test by title:
33
+
32
34
  ```sh
33
35
  yarn test-e2e --headed -g "title of the test"
34
36
  ```
35
- Check [this documentation](https://playwright.dev/docs/running-tests#command-line) for more running options.
36
37
 
37
- It is also highly recommended to install the companion VS Code extension:
38
- https://playwright.dev/docs/getting-started-vscode
38
+ Check [this documentation](https://playwright.dev/docs/running-tests#command-line) for more running options.
39
39
 
40
+ It is also highly recommended to install the companion VS Code extension: [Playwright](https://playwright.dev/docs/getting-started-vscode)
40
41
 
41
42
  ## Writing New Tests
42
43
 
@@ -44,7 +45,7 @@ In general, it is recommended to read through the official [Playwright docs](htt
44
45
  before writing new test cases. The project uses the official Playwright test runner and,
45
46
  generally, follows a very simple project structure:
46
47
 
47
- ```
48
+ ```sh
48
49
  e2e
49
50
  |__ commands
50
51
  | ^ Contains "commands" (simple reusable functions) that can be used in test cases/specs,
@@ -75,11 +76,11 @@ To download the report from the GitHub action/Bamboo plan, follow these steps:
75
76
 
76
77
  1. Go to the artifact section of the action/plan and locate the report file.
77
78
  2. Download the report file and unzip it using a tool of your choice.
78
- 3. Open the index.html file in a web browser to view the report.
79
+ 3. Open the index.html file in a web browser to view the report.
79
80
 
80
- The report will show you a full summary of your tests, including information on which
81
- tests passed, failed, were skipped, or were flaky. You can filter the report by browser
82
- and explore the details of individual tests, including any errors or failures, video
81
+ The report will show you a full summary of your tests, including information on which
82
+ tests passed, failed, were skipped, or were flaky. You can filter the report by browser
83
+ and explore the details of individual tests, including any errors or failures, video
83
84
  recordings, and the steps involved in each test. Simply click on a test to view its details.
84
85
 
85
86
  ## Debugging Tests
@@ -92,19 +93,19 @@ This is very much underdeveloped/WIP. At the moment, there exists a (git-shared)
92
93
  file which can be used for configuring certain test attributes. This is most likely
93
94
  about to change in the future. Stay tuned for updates!
94
95
 
95
-
96
96
  ## Github Action integration
97
+
97
98
  The e2e.yml workflow is made up of two jobs: one for running on pull requests (PRs) and
98
99
  one for running on commits.
99
100
 
100
- 1. When running on PRs, the workflow will start the dev server, use dev3.openmrs.org as the backend,
101
- and run tests only on chromium. This is done in order to quickly provide feedback to the developer.
102
- The tests are designed to generate their own data and clean up after themselves once they are finished.
103
- This ensures that the tests will have minimum effect from changes made to dev3 by other developers.
104
- In the future, we plan to use a docker container to run the tests in an isolated environment once we
101
+ 1. When running on PRs, the workflow will start the dev server, use dev3.openmrs.org as the backend,
102
+ and run tests only on chromium. This is done in order to quickly provide feedback to the developer.
103
+ The tests are designed to generate their own data and clean up after themselves once they are finished.
104
+ This ensures that the tests will have minimum effect from changes made to dev3 by other developers.
105
+ In the future, we plan to use a docker container to run the tests in an isolated environment once we
105
106
  figure out a way to spin up the container within a small amount of time.
106
107
  2. When running on commits, the workflow will spin up a docker container and run the dev server against
107
- it in order to provide a known and isolated environment. In addition, tests will be run on multiple
108
+ it in order to provide a known and isolated environment. In addition, tests will be run on multiple
108
109
  browsers (chromium, firefox, and WebKit) to ensure compatibility.
109
110
 
110
111
  ## Troubleshooting tips
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-billing-app",
3
- "version": "1.0.2-pre.613",
3
+ "version": "1.0.2-pre.619",
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",
@@ -47,7 +47,7 @@
47
47
  "fuzzy": "^0.1.3",
48
48
  "lodash-es": "^4.17.21",
49
49
  "react-hook-form": "^7.49.3",
50
- "react-to-print": "^2.14.15",
50
+ "react-to-print": "^3.1.1",
51
51
  "zod": "^3.22.4"
52
52
  },
53
53
  "peerDependencies": {
@@ -1,17 +1,23 @@
1
1
  import React from 'react';
2
2
  import userEvent from '@testing-library/user-event';
3
3
  import { render, screen } from '@testing-library/react';
4
+ import { getDefaultsFromConfigSchema, useConfig } from '@openmrs/esm-framework';
5
+ import { configSchema, type BillingConfig } from '../config-schema';
4
6
  import { useBills } from '../billing.resource';
5
7
  import BillHistory from './bill-history.component';
6
8
 
7
- // Mock i18next
8
- jest.mock('react-i18next', () => ({
9
- useTranslation: () => ({
10
- t: (key: string) => key,
11
- }),
9
+ const mockUseConfig = jest.mocked(useConfig<BillingConfig>);
10
+ const mockUseBills = jest.mocked(useBills);
11
+
12
+ jest.mock('../billing.resource', () => ({
13
+ useBills: jest.fn(() => ({
14
+ bills: mockBillData,
15
+ isLoading: false,
16
+ isValidating: false,
17
+ error: null,
18
+ })),
12
19
  }));
13
20
 
14
- // Mock window.i18next
15
21
  window.i18next = {
16
22
  language: 'en-US',
17
23
  } as any;
@@ -20,9 +26,7 @@ const testProps = {
20
26
  patientUuid: 'some-uuid',
21
27
  };
22
28
 
23
- const mockbills = useBills as jest.MockedFunction<typeof useBills>;
24
-
25
- const mockBillsData = [
29
+ const mockBillData = [
26
30
  { uuid: '1', patientName: 'John Doe', identifier: '12345678', billingService: 'Checkup', totalAmount: 500 },
27
31
  { uuid: '2', patientName: 'John Doe', identifier: '12345678', billingService: 'Consulatation', totalAmount: 600 },
28
32
  { uuid: '3', patientName: 'John Doe', identifier: '12345678', billingService: 'Child services', totalAmount: 700 },
@@ -37,69 +41,19 @@ const mockBillsData = [
37
41
  { uuid: '12', patientName: 'John Doe', identifier: '12345678', billingService: 'MCH', totalAmount: 1300 },
38
42
  ];
39
43
 
40
- // Mock the invoice table component
41
- jest.mock('../invoice/invoice-table.component', () => jest.fn(() => <div>Invoice table</div>));
42
-
43
- // Mock the billing resource
44
- jest.mock('../billing.resource', () => ({
45
- useBills: jest.fn(() => ({
46
- bills: mockBillsData,
47
- isLoading: false,
48
- isValidating: false,
49
- error: null,
50
- })),
51
- }));
52
-
53
- // Mock esm-patient-common-lib
54
- jest.mock('@openmrs/esm-patient-common-lib', () => ({
55
- CardHeader: jest.fn(({ children }) => <div>{children}</div>),
56
- EmptyDataIllustration: jest.fn(() => <div>Empty state illustration</div>),
57
- ErrorState: jest.fn(({ error }) => <div>Error: {error?.message}</div>),
58
- usePaginationInfo: jest.fn(() => ({
59
- pageSizes: [10, 20, 30],
60
- currentPage: 1,
61
- })),
62
- }));
63
-
64
- // Mock esm-framework
65
- jest.mock('@openmrs/esm-framework', () => ({
66
- useLayoutType: jest.fn(() => 'small-desktop'),
67
- isDesktop: jest.fn(() => true),
68
- usePagination: jest.fn().mockImplementation((data) => ({
69
- currentPage: 1,
70
- goTo: jest.fn(),
71
- results: data,
72
- paginated: true,
73
- })),
74
- showToast: jest.fn(),
75
- showNotification: jest.fn(),
76
- createErrorHandler: jest.fn(),
77
- createGlobalStore: jest.fn(),
78
- getGlobalStore: jest.fn(() => ({
79
- subscribe: jest.fn(),
80
- getState: jest.fn(),
81
- setState: jest.fn(),
82
- })),
83
- useConfig: jest.fn(() => ({
84
- pageSize: 10,
85
- defaultCurrency: 'USD',
86
- })),
87
- useSession: jest.fn(() => ({
88
- sessionLocation: { uuid: 'some-uuid', display: 'Location' },
89
- })),
90
- formatDate: jest.fn((date) => date?.toString() ?? ''),
91
- formatDatetime: jest.fn((date) => date?.toString() ?? ''),
92
- parseDate: jest.fn((dateString) => new Date(dateString)),
93
- ExtensionSlot: jest.fn(({ children }) => <>{children}</>),
94
- }));
95
-
96
44
  describe('BillHistory', () => {
97
- afterEach(() => {
98
- jest.clearAllMocks();
45
+ beforeEach(() => {
46
+ mockUseConfig.mockReturnValue({ ...getDefaultsFromConfigSchema(configSchema), defaultCurrency: 'USD' });
99
47
  });
100
48
 
101
49
  test('should render loading datatable skeleton', () => {
102
- mockbills.mockReturnValueOnce({ isLoading: true, isValidating: false, error: null, bills: [], mutate: jest.fn() });
50
+ mockUseBills.mockReturnValueOnce({
51
+ isLoading: true,
52
+ isValidating: false,
53
+ error: null,
54
+ bills: [],
55
+ mutate: jest.fn(),
56
+ });
103
57
  render(<BillHistory {...testProps} />);
104
58
  const loadingSkeleton = screen.getByRole('table');
105
59
  expect(loadingSkeleton).toBeInTheDocument();
@@ -107,7 +61,7 @@ describe('BillHistory', () => {
107
61
  });
108
62
 
109
63
  test('should render error state when API call fails', () => {
110
- mockbills.mockReturnValueOnce({
64
+ mockUseBills.mockReturnValueOnce({
111
65
  isLoading: false,
112
66
  isValidating: false,
113
67
  error: new Error('some error'),
@@ -115,31 +69,31 @@ describe('BillHistory', () => {
115
69
  mutate: jest.fn(),
116
70
  });
117
71
  render(<BillHistory {...testProps} />);
118
- const errorState = screen.getByText('Error: some error');
72
+ const errorState = screen.getByText(/Error/);
119
73
  expect(errorState).toBeInTheDocument();
120
74
  });
121
75
 
122
76
  test('should render bills table', async () => {
123
77
  const user = userEvent.setup();
124
- mockbills.mockReturnValueOnce({
78
+ mockUseBills.mockReturnValueOnce({
125
79
  isLoading: false,
126
80
  isValidating: false,
127
81
  error: null,
128
- bills: mockBillsData as any,
82
+ bills: mockBillData as any,
129
83
  mutate: jest.fn(),
130
84
  });
131
85
  render(<BillHistory {...testProps} />);
132
86
 
133
87
  // Verify headers
134
- expect(screen.getByText('visitTime')).toBeInTheDocument();
135
- expect(screen.getByText('identifier')).toBeInTheDocument();
88
+ expect(screen.getByText('Visit time')).toBeInTheDocument();
89
+ expect(screen.getByText('Identifier')).toBeInTheDocument();
136
90
 
137
91
  const tableRowGroup = screen.getAllByRole('rowgroup');
138
92
  expect(tableRowGroup).toHaveLength(2);
139
93
 
140
94
  // Page navigation should work as expected
141
- const nextPageButton = screen.getByRole('button', { name: /nextPage/ });
142
- const prevPageButton = screen.getByRole('button', { name: /previousPage/ });
95
+ const nextPageButton = screen.getByRole('button', { name: /Next page/ });
96
+ const prevPageButton = screen.getByRole('button', { name: /Previous page/ });
143
97
 
144
98
  expect(nextPageButton).toBeInTheDocument();
145
99
  expect(prevPageButton).toBeInTheDocument();
@@ -155,7 +109,13 @@ describe('BillHistory', () => {
155
109
  });
156
110
 
157
111
  test('should render empty state view when there are no bills', () => {
158
- mockbills.mockReturnValueOnce({ isLoading: false, isValidating: false, error: null, bills: [], mutate: jest.fn() });
112
+ mockUseBills.mockReturnValueOnce({
113
+ isLoading: false,
114
+ isValidating: false,
115
+ error: null,
116
+ bills: [],
117
+ mutate: jest.fn(),
118
+ });
159
119
  render(<BillHistory {...testProps} />);
160
120
  const emptyState = screen.getByText(/There are no bills to display./);
161
121
  expect(emptyState).toBeInTheDocument();
@@ -105,15 +105,19 @@ const ChangeStatus: React.FC<BillLineItemProps> = ({ bill, item, closeModal }) =
105
105
  (res) => {
106
106
  mutate((key) => typeof key === 'string' && key.startsWith(url), undefined, { revalidate: true });
107
107
  showSnackbar({
108
- title: t('billItems', 'Save Bill'),
109
- subtitle: 'Bill processing has been successful',
108
+ title: t('saveBill', 'Save Bill'),
109
+ subtitle: t('billProcessingSuccess', 'Bill processing has been successful'),
110
110
  kind: 'success',
111
111
  timeoutInMs: 3000,
112
112
  });
113
113
  closeModal();
114
114
  },
115
115
  (error) => {
116
- showSnackbar({ title: 'Bill processing error', kind: 'error', subtitle: error?.message });
116
+ showSnackbar({
117
+ title: t('billProcessingError', 'Bill processing error'),
118
+ kind: 'error',
119
+ subtitle: error?.message,
120
+ });
117
121
  },
118
122
  );
119
123
  };
@@ -1,19 +1,18 @@
1
1
  import React from 'react';
2
- import { render, screen, fireEvent, waitFor } from '@testing-library/react';
3
- import { showSnackbar } from '@openmrs/esm-framework';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { render, screen, waitFor } from '@testing-library/react';
4
+ import { type FetchResponse, showSnackbar } from '@openmrs/esm-framework';
4
5
  import { type MappedBill } from '../types';
5
6
  import { updateBillItems } from '../billing.resource';
6
7
  import ChangeStatus from './edit-bill-item.component';
7
8
 
8
- // Mock external dependencies
9
+ const mockUpdateBillItems = jest.mocked(updateBillItems);
10
+ const mockShowSnackbar = jest.mocked(showSnackbar);
11
+
9
12
  jest.mock('../billing.resource', () => ({
10
13
  updateBillItems: jest.fn(() => Promise.resolve({})),
11
14
  }));
12
15
 
13
- jest.mock('@openmrs/esm-framework', () => ({
14
- showSnackbar: jest.fn(),
15
- }));
16
-
17
16
  jest.mock('../billable-services/billable-service.resource', () => ({
18
17
  useBillableServices: jest.fn(() => ({
19
18
  billableServices: [],
@@ -77,10 +76,6 @@ const mockItem = {
77
76
  describe('ChangeStatus component', () => {
78
77
  const closeModalMock = jest.fn();
79
78
 
80
- beforeEach(() => {
81
- jest.clearAllMocks();
82
- });
83
-
84
79
  test('renders the form with correct fields and default values', () => {
85
80
  render(<ChangeStatus bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
86
81
 
@@ -91,24 +86,26 @@ describe('ChangeStatus component', () => {
91
86
  expect(screen.getByText(/Total/)).toHaveTextContent('200');
92
87
  });
93
88
 
94
- test('updates total when quantity is changed', () => {
89
+ test('updates total when quantity is changed', async () => {
90
+ const user = userEvent.setup();
95
91
  render(<ChangeStatus bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
96
92
 
97
93
  const quantityInput = screen.getByRole('spinbutton', { name: /Quantity/ });
98
- fireEvent.change(quantityInput, { target: { value: 3 } });
94
+ await user.type(quantityInput, '3');
99
95
 
100
96
  expect(screen.getByText(/Total/)).toHaveTextContent('300');
101
97
  });
102
98
 
103
99
  test('submits the form and shows a success notification', async () => {
104
- (updateBillItems as jest.Mock).mockResolvedValueOnce({});
100
+ const user = userEvent.setup();
101
+ mockUpdateBillItems.mockResolvedValueOnce({} as FetchResponse<any>);
105
102
 
106
103
  render(<ChangeStatus bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
107
104
 
108
- fireEvent.click(screen.getByText(/Save/));
105
+ await user.click(screen.getByText(/Save/));
109
106
 
110
107
  await waitFor(() => {
111
- expect(updateBillItems).toHaveBeenCalled();
108
+ expect(mockUpdateBillItems).toHaveBeenCalled();
112
109
  expect(showSnackbar).toHaveBeenCalledWith({
113
110
  title: 'Save Bill',
114
111
  subtitle: 'Bill processing has been successful',
@@ -120,14 +117,15 @@ describe('ChangeStatus component', () => {
120
117
  });
121
118
 
122
119
  test('shows error notification when submission fails', async () => {
123
- (updateBillItems as jest.Mock).mockRejectedValueOnce({ message: 'Error occurred' });
120
+ const user = userEvent.setup();
121
+ mockUpdateBillItems.mockRejectedValueOnce({ message: 'Error occurred' });
124
122
 
125
123
  render(<ChangeStatus bill={mockBill} item={mockItem} closeModal={closeModalMock} />);
126
124
 
127
- fireEvent.click(screen.getByText(/Save/));
125
+ await user.click(screen.getByText(/Save/));
128
126
 
129
127
  await waitFor(() => {
130
- expect(showSnackbar).toHaveBeenCalledWith({
128
+ expect(mockShowSnackbar).toHaveBeenCalledWith({
131
129
  title: 'Bill processing error',
132
130
  kind: 'error',
133
131
  subtitle: 'Error occurred',
@@ -37,9 +37,9 @@ const PatientBills: React.FC<PatientBillsProps> = ({ patientUuid, bills, setPati
37
37
  }
38
38
 
39
39
  const tableHeaders = [
40
- { header: 'Date', key: 'date' },
41
- { header: 'Billable Service', key: 'billableService' },
42
- { header: 'Total Amount', key: 'totalAmount' },
40
+ { header: t('date', 'Date'), key: 'date' },
41
+ { header: t('billableService', 'Billable Service'), key: 'billableService' },
42
+ { header: t('totalAmount', 'Total Amount'), key: 'totalAmount' },
43
43
  ];
44
44
 
45
45
  const tableRows = bills.map((bill) => ({
@@ -3,6 +3,7 @@ import { type OpenmrsResource, openmrsFetch, restBaseUrl, useOpenmrsFetchAll, us
3
3
  import { type ServiceConcept } from '../types';
4
4
  import { apiBasePath } from '../constants';
5
5
  import { type BillableService } from '../types/index';
6
+ import type { BillingConfig } from '../config-schema';
6
7
 
7
8
  type ResponseObject = {
8
9
  results: Array<OpenmrsResource>;
@@ -22,8 +23,8 @@ export const useBillableServices = () => {
22
23
  };
23
24
 
24
25
  export function useServiceTypes() {
25
- const config = useConfig();
26
- const serviceConceptUuid = config.serviceTypes.billableService;
26
+ const { serviceTypes } = useConfig<BillingConfig>();
27
+ const serviceConceptUuid = serviceTypes.billableService;
27
28
  const url = `${restBaseUrl}/concept/${serviceConceptUuid}?v=custom:(setMembers:(uuid,display))`;
28
29
 
29
30
  const { data, error, isLoading } = useSWR<{ data }>(url, openmrsFetch);
@@ -47,7 +48,7 @@ export const usePaymentModes = () => {
47
48
  };
48
49
  };
49
50
 
50
- export const createBillableSerice = (payload: any) => {
51
+ export const createBillableService = (payload: any) => {
51
52
  const url = `${apiBasePath}api/billable-service`;
52
53
  return openmrsFetch(url, {
53
54
  method: 'POST',