@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.
- package/README.md +12 -6
- package/__mocks__/react-i18next.js +6 -5
- package/dist/2352.js +1 -1
- package/dist/2352.js.map +1 -1
- package/dist/4300.js +1 -1
- package/dist/4739.js +1 -1
- package/dist/4739.js.map +1 -1
- package/dist/7239.js +1 -1
- package/dist/7239.js.map +1 -1
- package/dist/8638.js +1 -1
- package/dist/8638.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-billing-app.js +1 -1
- package/dist/openmrs-esm-billing-app.js.buildmanifest.json +19 -19
- package/dist/routes.json +1 -1
- package/e2e/README.md +19 -18
- package/package.json +2 -2
- package/src/bill-history/bill-history.test.tsx +37 -77
- package/src/bill-item-actions/edit-bill-item.component.tsx +7 -3
- package/src/bill-item-actions/edit-bill-item.test.tsx +17 -19
- package/src/billable-services/bill-waiver/patient-bills.component.tsx +3 -3
- package/src/billable-services/billable-service.resource.ts +4 -3
- package/src/billable-services/billable-services.component.tsx +5 -4
- package/src/billable-services/billable-services.test.tsx +3 -44
- package/src/billable-services/cash-point/cash-point-configuration.component.tsx +2 -2
- package/src/billable-services/create-edit/add-billable-service.component.tsx +2 -2
- package/src/billable-services/create-edit/add-billable-service.test.tsx +6 -6
- package/src/billable-services/payyment-modes/payment-modes-config.component.tsx +1 -1
- package/src/billing-form/billing-checkin-form.component.tsx +1 -2
- package/src/billing-form/billing-checkin-form.test.tsx +0 -2
- package/src/billing-form/billing-form.component.tsx +8 -4
- package/src/billing.resource.ts +13 -9
- package/src/bills-table/bills-table.test.tsx +97 -53
- package/src/config-schema.ts +52 -18
- package/src/invoice/invoice-table.component.tsx +9 -9
- package/src/invoice/invoice-table.scss +1 -5
- package/src/invoice/invoice-table.test.tsx +24 -39
- package/src/invoice/invoice.component.tsx +8 -6
- package/src/invoice/invoice.scss +7 -4
- package/src/invoice/invoice.test.tsx +12 -47
- package/src/invoice/payments/payment-form/payment-form.test.tsx +8 -10
- package/src/invoice/payments/payment-history/payment-history.component.tsx +6 -4
- package/src/invoice/payments/payment-history/payment-history.test.tsx +9 -14
- package/src/invoice/payments/payments.component.test.tsx +20 -6
- package/src/invoice/printable-invoice/print-receipt.component.tsx +1 -1
- package/src/invoice/printable-invoice/print-receipt.test.tsx +14 -25
- package/src/invoice/printable-invoice/printable-footer.component.tsx +2 -2
- package/src/invoice/printable-invoice/printable-footer.test.tsx +4 -13
- package/src/invoice/printable-invoice/printable-invoice-header.component.tsx +5 -4
- package/src/invoice/printable-invoice/printable-invoice-header.test.tsx +11 -11
- package/src/invoice/printable-invoice/printable-invoice.component.tsx +11 -11
- package/src/metrics-cards/metrics-cards.test.tsx +18 -5
- package/src/modal/require-payment-modal.test.tsx +24 -19
- 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.
|
|
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":
|
|
291
|
+
"size": 54144,
|
|
292
292
|
"sizes": {
|
|
293
|
-
"javascript":
|
|
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": "
|
|
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":
|
|
548
|
+
"size": 7220,
|
|
549
549
|
"sizes": {
|
|
550
|
-
"javascript":
|
|
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": "
|
|
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":
|
|
636
|
+
"size": 30413,
|
|
637
637
|
"sizes": {
|
|
638
|
-
"javascript":
|
|
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": "
|
|
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": "
|
|
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":
|
|
1045
|
+
"size": 532423,
|
|
1046
1046
|
"sizes": {
|
|
1047
|
-
"javascript":
|
|
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": "
|
|
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":
|
|
1239
|
+
"size": 1096899,
|
|
1240
1240
|
"sizes": {
|
|
1241
|
-
"javascript":
|
|
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": "
|
|
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":
|
|
1263
|
+
"size": 5092452,
|
|
1264
1264
|
"sizes": {
|
|
1265
1265
|
"consume-shared": 210,
|
|
1266
|
-
"javascript":
|
|
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": "
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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": "^
|
|
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
|
-
|
|
8
|
-
jest.
|
|
9
|
-
|
|
10
|
-
|
|
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
|
|
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
|
-
|
|
98
|
-
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
mockUseConfig.mockReturnValue({ ...getDefaultsFromConfigSchema(configSchema), defaultCurrency: 'USD' });
|
|
99
47
|
});
|
|
100
48
|
|
|
101
49
|
test('should render loading datatable skeleton', () => {
|
|
102
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
78
|
+
mockUseBills.mockReturnValueOnce({
|
|
125
79
|
isLoading: false,
|
|
126
80
|
isValidating: false,
|
|
127
81
|
error: null,
|
|
128
|
-
bills:
|
|
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('
|
|
135
|
-
expect(screen.getByText('
|
|
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: /
|
|
142
|
-
const prevPageButton = screen.getByRole('button', { name: /
|
|
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
|
-
|
|
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('
|
|
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({
|
|
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
|
|
3
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
105
|
+
await user.click(screen.getByText(/Save/));
|
|
109
106
|
|
|
110
107
|
await waitFor(() => {
|
|
111
|
-
expect(
|
|
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
|
-
|
|
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
|
-
|
|
125
|
+
await user.click(screen.getByText(/Save/));
|
|
128
126
|
|
|
129
127
|
await waitFor(() => {
|
|
130
|
-
expect(
|
|
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
|
|
26
|
-
const serviceConceptUuid =
|
|
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
|
|
51
|
+
export const createBillableService = (payload: any) => {
|
|
51
52
|
const url = `${apiBasePath}api/billable-service`;
|
|
52
53
|
return openmrsFetch(url, {
|
|
53
54
|
method: 'POST',
|