@openmrs/esm-billing-app 1.0.2-pre.753 → 1.0.2-pre.759
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/dist/4300.js +1 -1
- package/dist/4724.js +1 -1
- package/dist/4724.js.map +1 -1
- package/dist/942.js +1 -1
- package/dist/942.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 +14 -14
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/invoice/payments/payment-form/payment-form.component.tsx +27 -20
- package/src/invoice/payments/payment-form/payment-form.scss +5 -6
- package/src/invoice/payments/payment-form/payment-form.test.tsx +204 -24
- package/src/invoice/payments/payments.component.tsx +46 -46
- package/src/invoice/payments/payments.test.tsx +155 -8
- package/src/invoice/payments/utils.ts +1 -1
- package/translations/en.json +13 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
var _openmrs_esm_billing_app;(()=>{"use strict";var e,r,t,n,o,a,i,l,s,u,f,p,d,c,h,m,v,g,b,y,w,_={45120:(e,r,t)=>{var n={"./start":()=>Promise.all([t.e(2177),t.e(8930),t.e(1146),t.e(2524),t.e(6072),t.e(3006),t.e(942)]).then((()=>()=>t(80942)))},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,loaded:!1,exports:{}};return _[e].call(t.exports,t,t.exports,S),t.loaded=!0,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(d);var o=t[e];if(delete t[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach((e=>e(n))),r)return r(n)},d=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.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{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.3415",(()=>Promise.all([S.e(2177),S.e(7452),S.e(8930),S.e(1856),S.e(6072),S.e(1997),S.e(3006)]).then((()=>()=>S(41856))))),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,d,c,h,m,v,g,b,y,w,_={45120:(e,r,t)=>{var n={"./start":()=>Promise.all([t.e(2177),t.e(8930),t.e(1146),t.e(2524),t.e(6072),t.e(3006),t.e(942)]).then((()=>()=>t(80942)))},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,loaded:!1,exports:{}};return _[e].call(t.exports,t,t.exports,S),t.loaded=!0,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(d);var o=t[e];if(delete t[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach((e=>e(n))),r)return r(n)},d=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.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{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.3415",(()=>Promise.all([S.e(2177),S.e(7452),S.e(8930),S.e(1856),S.e(6072),S.e(1997),S.e(3006)]).then((()=>()=>S(41856))))),l("@openmrs/esm-patient-common-lib","11.3.1-pre.8999",(()=>Promise.all([S.e(2177),S.e(7452),S.e(8930),S.e(4724),S.e(1146),S.e(6072),S.e(1997),S.e(3006)]).then((()=>()=>S(94724))))),l("react-dom","18.3.1",(()=>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.3.1",(()=>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 d=[],c=d.pop.bind(d);for(a=1;a<e.length;a++){var h=e[a];d.push(1==h?c()|c():2==h?c()&c():h?l(h,r):!c())}return!!c()},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)},d=(e,r,t,n)=>"Unsatisfied version "+t+" from "+(t&&e[r][t].from)+" of shared singleton module "+r+" (required "+i(n)+")",c=e=>{throw new Error(e)},h=e=>{"undefined"!=typeof console&&console.warn&&console.warn(e)},m=(e,r,t)=>t?t():((e,r)=>c("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(d(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(7452),S.e(1856),S.e(1997)]).then((()=>()=>S(41856))))),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))))),35332:()=>v("default","@openmrs/esm-patient-common-lib",!1,[1,11],(()=>Promise.all([S.e(7452),S.e(4724),S.e(1997)]).then((()=>()=>S(94724)))))},y={942:[35332],1997:[44209,53083,56339],3006:[15847,53941,92646],6072:[16072]},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})();
|
|
@@ -71,9 +71,9 @@
|
|
|
71
71
|
"initial": false,
|
|
72
72
|
"entry": false,
|
|
73
73
|
"recorded": false,
|
|
74
|
-
"size":
|
|
74
|
+
"size": 1173797,
|
|
75
75
|
"sizes": {
|
|
76
|
-
"javascript":
|
|
76
|
+
"javascript": 1173755,
|
|
77
77
|
"consume-shared": 42
|
|
78
78
|
},
|
|
79
79
|
"names": [],
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"auxiliaryFiles": [
|
|
88
88
|
"942.js.map"
|
|
89
89
|
],
|
|
90
|
-
"hash": "
|
|
90
|
+
"hash": "b2a09f0b545f908f",
|
|
91
91
|
"childrenByOrder": {}
|
|
92
92
|
},
|
|
93
93
|
{
|
|
@@ -544,9 +544,9 @@
|
|
|
544
544
|
"initial": false,
|
|
545
545
|
"entry": false,
|
|
546
546
|
"recorded": false,
|
|
547
|
-
"size":
|
|
547
|
+
"size": 8366,
|
|
548
548
|
"sizes": {
|
|
549
|
-
"javascript":
|
|
549
|
+
"javascript": 8366
|
|
550
550
|
},
|
|
551
551
|
"names": [],
|
|
552
552
|
"idHints": [],
|
|
@@ -558,7 +558,7 @@
|
|
|
558
558
|
"4300.js"
|
|
559
559
|
],
|
|
560
560
|
"auxiliaryFiles": [],
|
|
561
|
-
"hash": "
|
|
561
|
+
"hash": "d784eb407ac35b80",
|
|
562
562
|
"childrenByOrder": {}
|
|
563
563
|
},
|
|
564
564
|
{
|
|
@@ -633,9 +633,9 @@
|
|
|
633
633
|
"entry": false,
|
|
634
634
|
"recorded": false,
|
|
635
635
|
"reason": "split chunk (cache group: defaultVendors)",
|
|
636
|
-
"size":
|
|
636
|
+
"size": 237612,
|
|
637
637
|
"sizes": {
|
|
638
|
-
"javascript":
|
|
638
|
+
"javascript": 237612
|
|
639
639
|
},
|
|
640
640
|
"names": [],
|
|
641
641
|
"idHints": [
|
|
@@ -651,7 +651,7 @@
|
|
|
651
651
|
"auxiliaryFiles": [
|
|
652
652
|
"4724.js.map"
|
|
653
653
|
],
|
|
654
|
-
"hash": "
|
|
654
|
+
"hash": "e2aa66c60df99690",
|
|
655
655
|
"childrenByOrder": {}
|
|
656
656
|
},
|
|
657
657
|
{
|
|
@@ -675,7 +675,7 @@
|
|
|
675
675
|
"auxiliaryFiles": [
|
|
676
676
|
"4739.js.map"
|
|
677
677
|
],
|
|
678
|
-
"hash": "
|
|
678
|
+
"hash": "d8550eea199ed339",
|
|
679
679
|
"childrenByOrder": {}
|
|
680
680
|
},
|
|
681
681
|
{
|
|
@@ -971,7 +971,7 @@
|
|
|
971
971
|
"auxiliaryFiles": [
|
|
972
972
|
"openmrs-esm-billing-app.js.map"
|
|
973
973
|
],
|
|
974
|
-
"hash": "
|
|
974
|
+
"hash": "ff97f86ed6e0021d",
|
|
975
975
|
"childrenByOrder": {}
|
|
976
976
|
},
|
|
977
977
|
{
|
|
@@ -1209,10 +1209,10 @@
|
|
|
1209
1209
|
"initial": true,
|
|
1210
1210
|
"entry": true,
|
|
1211
1211
|
"recorded": false,
|
|
1212
|
-
"size":
|
|
1212
|
+
"size": 5471627,
|
|
1213
1213
|
"sizes": {
|
|
1214
1214
|
"consume-shared": 210,
|
|
1215
|
-
"javascript":
|
|
1215
|
+
"javascript": 5448972,
|
|
1216
1216
|
"share-init": 336,
|
|
1217
1217
|
"runtime": 22109
|
|
1218
1218
|
},
|
|
@@ -1229,7 +1229,7 @@
|
|
|
1229
1229
|
"auxiliaryFiles": [
|
|
1230
1230
|
"main.js.map"
|
|
1231
1231
|
],
|
|
1232
|
-
"hash": "
|
|
1232
|
+
"hash": "ad8b773c28c2eaeb",
|
|
1233
1233
|
"childrenByOrder": {}
|
|
1234
1234
|
},
|
|
1235
1235
|
{
|
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":"editBillLineItemModal","online":true,"offline":true}],"modals":[{"name":"add-cash-point-modal","component":"addCashPointModal"},{"name":"add-payment-mode-modal","component":"addPaymentModeModal"},{"name":"delete-payment-mode-modal","component":"deletePaymentModeModal"},{"name":"edit-bill-item-modal","component":"editBillLineItemModal"},{"name":"edit-billable-service-modal","component":"editBillableServiceModal"},{"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":"editBillLineItemModal","online":true,"offline":true}],"modals":[{"name":"add-cash-point-modal","component":"addCashPointModal"},{"name":"add-payment-mode-modal","component":"addPaymentModeModal"},{"name":"delete-payment-mode-modal","component":"deletePaymentModeModal"},{"name":"edit-bill-item-modal","component":"editBillLineItemModal"},{"name":"edit-billable-service-modal","component":"editBillableServiceModal"},{"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.759"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@ import React, { useCallback, useState, useEffect } from 'react';
|
|
|
2
2
|
import { Controller, useFieldArray, useFormContext } from 'react-hook-form';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import { TrashCan, Add } from '@carbon/react/icons';
|
|
5
|
-
import { Button, Dropdown, NumberInputSkeleton, TextInput, NumberInput } from '@carbon/react';
|
|
5
|
+
import { Button, IconButton, Dropdown, NumberInputSkeleton, TextInput, NumberInput } from '@carbon/react';
|
|
6
6
|
import { ErrorState } from '@openmrs/esm-patient-common-lib';
|
|
7
7
|
import { type PaymentFormValue } from '../payments.component';
|
|
8
8
|
import { usePaymentModes } from '../payment.resource';
|
|
@@ -13,7 +13,7 @@ type PaymentFormProps = {
|
|
|
13
13
|
isSingleLineItem: boolean;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
const DEFAULT_PAYMENT = { method: '', amount:
|
|
16
|
+
const DEFAULT_PAYMENT = { method: '', amount: undefined, referenceCode: '' };
|
|
17
17
|
|
|
18
18
|
const PaymentForm: React.FC<PaymentFormProps> = ({ disablePayment, isSingleLineItem }) => {
|
|
19
19
|
const { t } = useTranslation();
|
|
@@ -22,7 +22,7 @@ const PaymentForm: React.FC<PaymentFormProps> = ({ disablePayment, isSingleLineI
|
|
|
22
22
|
formState: { errors },
|
|
23
23
|
} = useFormContext<PaymentFormValue>();
|
|
24
24
|
const { paymentModes, isLoading, error } = usePaymentModes();
|
|
25
|
-
const { fields, remove, append } = useFieldArray({ name: 'payment', control
|
|
25
|
+
const { fields, remove, append } = useFieldArray({ name: 'payment', control });
|
|
26
26
|
const [isFormVisible, setIsFormVisible] = useState(isSingleLineItem);
|
|
27
27
|
|
|
28
28
|
useEffect(() => {
|
|
@@ -38,10 +38,11 @@ const PaymentForm: React.FC<PaymentFormProps> = ({ disablePayment, isSingleLineI
|
|
|
38
38
|
setIsFormVisible(true);
|
|
39
39
|
append(DEFAULT_PAYMENT);
|
|
40
40
|
}, [append]);
|
|
41
|
-
|
|
41
|
+
|
|
42
|
+
const handleRemovePaymentMode = useCallback((index: number) => remove(index), [remove]);
|
|
42
43
|
|
|
43
44
|
if (isLoading) {
|
|
44
|
-
return <NumberInputSkeleton
|
|
45
|
+
return <NumberInputSkeleton />;
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
if (error) {
|
|
@@ -55,8 +56,8 @@ const PaymentForm: React.FC<PaymentFormProps> = ({ disablePayment, isSingleLineI
|
|
|
55
56
|
return (
|
|
56
57
|
<div className={styles.container}>
|
|
57
58
|
{isFormVisible &&
|
|
58
|
-
fields.map((
|
|
59
|
-
<div key={
|
|
59
|
+
fields.map((fieldItem, index) => (
|
|
60
|
+
<div key={fieldItem.id} className={styles.paymentMethodContainer}>
|
|
60
61
|
<Controller
|
|
61
62
|
control={control}
|
|
62
63
|
name={`payment.${index}.method`}
|
|
@@ -78,13 +79,17 @@ const PaymentForm: React.FC<PaymentFormProps> = ({ disablePayment, isSingleLineI
|
|
|
78
79
|
name={`payment.${index}.amount`}
|
|
79
80
|
render={({ field }) => (
|
|
80
81
|
<NumberInput
|
|
82
|
+
allowEmpty
|
|
81
83
|
id="paymentAmount"
|
|
82
|
-
{...field}
|
|
83
|
-
onChange={(e) => field.onChange(Number(e.target.value))}
|
|
84
84
|
invalid={!!errors?.payment?.[index]?.amount}
|
|
85
85
|
invalidText={errors?.payment?.[index]?.amount?.message}
|
|
86
86
|
label={t('amount', 'Amount')}
|
|
87
|
+
onChange={(_, { value }) => {
|
|
88
|
+
const numValue = value === '' || value === undefined ? undefined : Number(value);
|
|
89
|
+
field.onChange(numValue);
|
|
90
|
+
}}
|
|
87
91
|
placeholder={t('enterAmount', 'Enter amount')}
|
|
92
|
+
value={field.value ?? ''}
|
|
88
93
|
/>
|
|
89
94
|
)}
|
|
90
95
|
/>
|
|
@@ -94,31 +99,33 @@ const PaymentForm: React.FC<PaymentFormProps> = ({ disablePayment, isSingleLineI
|
|
|
94
99
|
render={({ field }) => (
|
|
95
100
|
<TextInput
|
|
96
101
|
id="paymentReferenceCode"
|
|
97
|
-
{...field}
|
|
98
102
|
labelText={t('referenceNumber', 'Reference number')}
|
|
99
|
-
|
|
103
|
+
name={field.name}
|
|
104
|
+
onBlur={field.onBlur}
|
|
105
|
+
onChange={field.onChange}
|
|
106
|
+
placeholder={t('enterReferenceNumber', 'Enter reference number')}
|
|
100
107
|
type="text"
|
|
108
|
+
value={field.value ?? ''}
|
|
101
109
|
/>
|
|
102
110
|
)}
|
|
103
111
|
/>
|
|
104
112
|
<div className={styles.removeButtonContainer}>
|
|
105
|
-
<
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
<IconButton
|
|
114
|
+
kind="danger--tertiary"
|
|
115
|
+
label={t('removePaymentMethod', 'Remove payment method')}
|
|
116
|
+
onClick={() => handleRemovePaymentMode(index)}>
|
|
117
|
+
<TrashCan />
|
|
118
|
+
</IconButton>
|
|
111
119
|
</div>
|
|
112
120
|
</div>
|
|
113
121
|
))}
|
|
114
122
|
<Button
|
|
115
123
|
disabled={disablePayment}
|
|
116
|
-
size="md"
|
|
117
124
|
onClick={handleAppendPaymentMode}
|
|
118
125
|
className={styles.paymentButtons}
|
|
119
126
|
renderIcon={(props) => <Add size={24} {...props} />}
|
|
120
|
-
iconDescription=
|
|
121
|
-
{t('
|
|
127
|
+
iconDescription={t('add', 'Add')}>
|
|
128
|
+
{t('addPaymentMethod', 'Add payment method')}
|
|
122
129
|
</Button>
|
|
123
130
|
</div>
|
|
124
131
|
);
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
@use '@carbon/type';
|
|
4
4
|
|
|
5
5
|
.container {
|
|
6
|
-
margin:
|
|
6
|
+
margin: layout.$spacing-05;
|
|
7
|
+
gap: layout.$spacing-06;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
.paymentContainer {
|
|
@@ -19,10 +20,10 @@
|
|
|
19
20
|
|
|
20
21
|
.paymentMethodContainer {
|
|
21
22
|
display: grid;
|
|
22
|
-
grid-template-columns:
|
|
23
|
+
grid-template-columns: 1fr 1fr 1fr auto;
|
|
23
24
|
align-items: flex-start;
|
|
24
|
-
|
|
25
|
-
margin:
|
|
25
|
+
gap: layout.$spacing-05;
|
|
26
|
+
margin: layout.$spacing-05 0;
|
|
26
27
|
width: 100%;
|
|
27
28
|
}
|
|
28
29
|
|
|
@@ -45,8 +46,6 @@
|
|
|
45
46
|
.removeButtonContainer {
|
|
46
47
|
display: flex;
|
|
47
48
|
align-self: center;
|
|
48
|
-
cursor: pointer;
|
|
49
|
-
margin-left: layout.$spacing-07;
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
.removeButton {
|
|
@@ -3,43 +3,48 @@ import userEvent from '@testing-library/user-event';
|
|
|
3
3
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
4
4
|
import { FormProvider, useForm } from 'react-hook-form';
|
|
5
5
|
import type { PaymentFormValue } from '../payments.component';
|
|
6
|
+
import { usePaymentModes } from '../payment.resource';
|
|
6
7
|
import PaymentForm from './payment-form.component';
|
|
7
8
|
|
|
8
9
|
jest.mock('../payment.resource', () => ({
|
|
9
10
|
usePaymentModes: jest.fn(),
|
|
10
11
|
}));
|
|
11
12
|
|
|
12
|
-
const
|
|
13
|
+
const mockUsePaymentModes = jest.mocked(usePaymentModes);
|
|
13
14
|
|
|
14
15
|
type WrapperProps = {
|
|
15
16
|
children: React.ReactNode;
|
|
17
|
+
defaultValues?: Partial<PaymentFormValue>;
|
|
16
18
|
};
|
|
17
19
|
|
|
18
|
-
const Wrapper: React.FC<WrapperProps> = ({ children }) => {
|
|
19
|
-
const methods = useForm<PaymentFormValue>(
|
|
20
|
+
const Wrapper: React.FC<WrapperProps> = ({ children, defaultValues }) => {
|
|
21
|
+
const methods = useForm<PaymentFormValue>({
|
|
22
|
+
mode: 'all',
|
|
23
|
+
defaultValues: defaultValues || { payment: [] },
|
|
24
|
+
});
|
|
20
25
|
return <FormProvider {...methods}>{children}</FormProvider>;
|
|
21
26
|
};
|
|
22
27
|
|
|
23
28
|
describe('PaymentForm Component', () => {
|
|
24
29
|
test('should render skeleton while loading payment modes', () => {
|
|
25
|
-
|
|
30
|
+
mockUsePaymentModes.mockReturnValue({
|
|
26
31
|
paymentModes: [],
|
|
27
32
|
isLoading: true,
|
|
28
33
|
error: null,
|
|
29
34
|
mutate: jest.fn(),
|
|
30
35
|
});
|
|
31
36
|
|
|
32
|
-
render(
|
|
37
|
+
const { container } = render(
|
|
33
38
|
<Wrapper>
|
|
34
39
|
<PaymentForm disablePayment={false} isSingleLineItem={false} />
|
|
35
40
|
</Wrapper>,
|
|
36
41
|
);
|
|
37
42
|
|
|
38
|
-
expect(
|
|
43
|
+
expect(container.querySelector('.cds--skeleton')).toBeInTheDocument();
|
|
39
44
|
});
|
|
40
45
|
|
|
41
46
|
test('should render error message when payment modes fail to load', () => {
|
|
42
|
-
|
|
47
|
+
mockUsePaymentModes.mockReturnValue({
|
|
43
48
|
paymentModes: [],
|
|
44
49
|
isLoading: false,
|
|
45
50
|
error: new Error('Failed to load payment modes'),
|
|
@@ -56,8 +61,8 @@ describe('PaymentForm Component', () => {
|
|
|
56
61
|
});
|
|
57
62
|
|
|
58
63
|
test('should append default payment when isSingleLineItem is true', () => {
|
|
59
|
-
|
|
60
|
-
paymentModes: [{ uuid: '1', name: 'Credit Card' }],
|
|
64
|
+
mockUsePaymentModes.mockReturnValue({
|
|
65
|
+
paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
|
|
61
66
|
isLoading: false,
|
|
62
67
|
error: null,
|
|
63
68
|
mutate: jest.fn(),
|
|
@@ -77,10 +82,10 @@ describe('PaymentForm Component', () => {
|
|
|
77
82
|
expect(screen.getByPlaceholderText(/enter amount/i)).toBeInTheDocument();
|
|
78
83
|
});
|
|
79
84
|
|
|
80
|
-
test('should append a payment field when add payment
|
|
85
|
+
test('should append a payment field when add payment method button is clicked', async () => {
|
|
81
86
|
const user = userEvent.setup();
|
|
82
|
-
|
|
83
|
-
paymentModes: [{ uuid: '1', name: 'Credit Card' }],
|
|
87
|
+
mockUsePaymentModes.mockReturnValue({
|
|
88
|
+
paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
|
|
84
89
|
isLoading: false,
|
|
85
90
|
error: null,
|
|
86
91
|
mutate: jest.fn(),
|
|
@@ -92,15 +97,21 @@ describe('PaymentForm Component', () => {
|
|
|
92
97
|
</Wrapper>,
|
|
93
98
|
);
|
|
94
99
|
|
|
95
|
-
|
|
100
|
+
// Initially no payment fields are shown
|
|
101
|
+
expect(screen.queryByPlaceholderText(/enter amount/i)).not.toBeInTheDocument();
|
|
102
|
+
|
|
103
|
+
const addButton = screen.getByText(/add payment method/i);
|
|
96
104
|
await user.click(addButton);
|
|
97
|
-
|
|
98
|
-
|
|
105
|
+
|
|
106
|
+
// After clicking, payment fields should be visible
|
|
107
|
+
expect(screen.getByPlaceholderText(/enter amount/i)).toBeInTheDocument();
|
|
108
|
+
expect(screen.getByPlaceholderText(/enter reference number/i)).toBeInTheDocument();
|
|
109
|
+
expect(screen.getByText(/select payment method/i)).toBeInTheDocument();
|
|
99
110
|
});
|
|
100
111
|
|
|
101
112
|
test('should disable add payment button when disablePayment is true', () => {
|
|
102
|
-
|
|
103
|
-
paymentModes: [{ uuid: '1', name: 'Credit Card' }],
|
|
113
|
+
mockUsePaymentModes.mockReturnValue({
|
|
114
|
+
paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
|
|
104
115
|
isLoading: false,
|
|
105
116
|
error: null,
|
|
106
117
|
mutate: jest.fn(),
|
|
@@ -112,13 +123,13 @@ describe('PaymentForm Component', () => {
|
|
|
112
123
|
</Wrapper>,
|
|
113
124
|
);
|
|
114
125
|
|
|
115
|
-
expect(screen.getByText(/add payment
|
|
126
|
+
expect(screen.getByText(/add payment method/i)).toBeDisabled();
|
|
116
127
|
});
|
|
117
128
|
|
|
118
|
-
test('should remove payment field when
|
|
129
|
+
test('should remove payment field when remove button is clicked', async () => {
|
|
119
130
|
const user = userEvent.setup();
|
|
120
|
-
|
|
121
|
-
paymentModes: [{ uuid: '1', name: 'Credit Card' }],
|
|
131
|
+
mockUsePaymentModes.mockReturnValue({
|
|
132
|
+
paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
|
|
122
133
|
isLoading: false,
|
|
123
134
|
error: null,
|
|
124
135
|
mutate: jest.fn(),
|
|
@@ -130,13 +141,182 @@ describe('PaymentForm Component', () => {
|
|
|
130
141
|
</Wrapper>,
|
|
131
142
|
);
|
|
132
143
|
|
|
133
|
-
await user.click(screen.getByText(/add payment
|
|
144
|
+
await user.click(screen.getByText(/add payment method/i));
|
|
134
145
|
|
|
135
|
-
const
|
|
136
|
-
await user.click(
|
|
146
|
+
const removeButton = screen.getByRole('button', { name: /remove payment method/i });
|
|
147
|
+
await user.click(removeButton);
|
|
137
148
|
|
|
138
149
|
await waitFor(() => {
|
|
139
150
|
expect(screen.queryByPlaceholderText(/enter amount/i)).not.toBeInTheDocument();
|
|
140
151
|
});
|
|
141
152
|
});
|
|
153
|
+
|
|
154
|
+
test('should render amount input without leading zero', () => {
|
|
155
|
+
mockUsePaymentModes.mockReturnValue({
|
|
156
|
+
paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
|
|
157
|
+
isLoading: false,
|
|
158
|
+
error: null,
|
|
159
|
+
mutate: jest.fn(),
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
render(
|
|
163
|
+
<Wrapper>
|
|
164
|
+
<PaymentForm disablePayment={false} isSingleLineItem={true} />
|
|
165
|
+
</Wrapper>,
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const amountInput = screen.getByPlaceholderText(/enter amount/i) as HTMLInputElement;
|
|
169
|
+
expect(amountInput.value).toBe('');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test('should allow user to clear amount input without reverting to zero', async () => {
|
|
173
|
+
const user = userEvent.setup();
|
|
174
|
+
mockUsePaymentModes.mockReturnValue({
|
|
175
|
+
paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
|
|
176
|
+
isLoading: false,
|
|
177
|
+
error: null,
|
|
178
|
+
mutate: jest.fn(),
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
render(
|
|
182
|
+
<Wrapper>
|
|
183
|
+
<PaymentForm disablePayment={false} isSingleLineItem={true} />
|
|
184
|
+
</Wrapper>,
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const amountInput = screen.getByPlaceholderText(/enter amount/i) as HTMLInputElement;
|
|
188
|
+
|
|
189
|
+
await user.type(amountInput, '100');
|
|
190
|
+
expect(amountInput.value).toBe('100');
|
|
191
|
+
|
|
192
|
+
await user.clear(amountInput);
|
|
193
|
+
expect(amountInput.value).toBe('');
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test('should handle amount input with decimal values', async () => {
|
|
197
|
+
const user = userEvent.setup();
|
|
198
|
+
mockUsePaymentModes.mockReturnValue({
|
|
199
|
+
paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
|
|
200
|
+
isLoading: false,
|
|
201
|
+
error: null,
|
|
202
|
+
mutate: jest.fn(),
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
render(
|
|
206
|
+
<Wrapper>
|
|
207
|
+
<PaymentForm disablePayment={false} isSingleLineItem={true} />
|
|
208
|
+
</Wrapper>,
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
const amountInput = screen.getByPlaceholderText(/enter amount/i) as HTMLInputElement;
|
|
212
|
+
|
|
213
|
+
await user.type(amountInput, '10.50');
|
|
214
|
+
expect(amountInput.value).toBe('10.5');
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test('should not auto-focus reference number input on mount', () => {
|
|
218
|
+
mockUsePaymentModes.mockReturnValue({
|
|
219
|
+
paymentModes: [{ uuid: '1', name: 'Credit Card', description: 'Credit Card', retired: false }],
|
|
220
|
+
isLoading: false,
|
|
221
|
+
error: null,
|
|
222
|
+
mutate: jest.fn(),
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
render(
|
|
226
|
+
<Wrapper>
|
|
227
|
+
<PaymentForm disablePayment={false} isSingleLineItem={true} />
|
|
228
|
+
</Wrapper>,
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
const referenceInput = screen.getByPlaceholderText(/enter reference number/i);
|
|
232
|
+
expect(referenceInput).not.toHaveFocus();
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test('should allow adding multiple payment methods', async () => {
|
|
236
|
+
const user = userEvent.setup();
|
|
237
|
+
mockUsePaymentModes.mockReturnValue({
|
|
238
|
+
paymentModes: [
|
|
239
|
+
{ uuid: '1', name: 'Cash', description: 'Cash', retired: false },
|
|
240
|
+
{ uuid: '2', name: 'Credit Card', description: 'Credit Card', retired: false },
|
|
241
|
+
],
|
|
242
|
+
isLoading: false,
|
|
243
|
+
error: null,
|
|
244
|
+
mutate: jest.fn(),
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
render(
|
|
248
|
+
<Wrapper>
|
|
249
|
+
<PaymentForm disablePayment={false} isSingleLineItem={false} />
|
|
250
|
+
</Wrapper>,
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
const addButton = screen.getByText(/add payment method/i);
|
|
254
|
+
|
|
255
|
+
await user.click(addButton);
|
|
256
|
+
await user.click(addButton);
|
|
257
|
+
|
|
258
|
+
const amountInputs = screen.getAllByPlaceholderText(/enter amount/i);
|
|
259
|
+
expect(amountInputs).toHaveLength(2);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
test('should preserve entered values when adding new payment method', async () => {
|
|
263
|
+
const user = userEvent.setup();
|
|
264
|
+
mockUsePaymentModes.mockReturnValue({
|
|
265
|
+
paymentModes: [{ uuid: '1', name: 'Cash', description: 'Cash', retired: false }],
|
|
266
|
+
isLoading: false,
|
|
267
|
+
error: null,
|
|
268
|
+
mutate: jest.fn(),
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
render(
|
|
272
|
+
<Wrapper>
|
|
273
|
+
<PaymentForm disablePayment={false} isSingleLineItem={false} />
|
|
274
|
+
</Wrapper>,
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
const addButton = screen.getByText(/add payment method/i);
|
|
278
|
+
await user.click(addButton);
|
|
279
|
+
|
|
280
|
+
const firstAmountInput = screen.getByPlaceholderText(/enter amount/i) as HTMLInputElement;
|
|
281
|
+
await user.type(firstAmountInput, '50');
|
|
282
|
+
|
|
283
|
+
await user.click(addButton);
|
|
284
|
+
|
|
285
|
+
const amountInputs = screen.getAllByPlaceholderText(/enter amount/i) as HTMLInputElement[];
|
|
286
|
+
expect(amountInputs[0].value).toBe('50');
|
|
287
|
+
expect(amountInputs[1].value).toBe('');
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test('should handle removing payment method without affecting other fields', async () => {
|
|
291
|
+
const user = userEvent.setup();
|
|
292
|
+
mockUsePaymentModes.mockReturnValue({
|
|
293
|
+
paymentModes: [{ uuid: '1', name: 'Cash', description: 'Cash', retired: false }],
|
|
294
|
+
isLoading: false,
|
|
295
|
+
error: null,
|
|
296
|
+
mutate: jest.fn(),
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
render(
|
|
300
|
+
<Wrapper>
|
|
301
|
+
<PaymentForm disablePayment={false} isSingleLineItem={false} />
|
|
302
|
+
</Wrapper>,
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
const addButton = screen.getByText(/add payment method/i);
|
|
306
|
+
await user.click(addButton);
|
|
307
|
+
await user.click(addButton);
|
|
308
|
+
|
|
309
|
+
const amountInputs = screen.getAllByPlaceholderText(/enter amount/i) as HTMLInputElement[];
|
|
310
|
+
await user.type(amountInputs[0], '50');
|
|
311
|
+
await user.type(amountInputs[1], '75');
|
|
312
|
+
|
|
313
|
+
const removeButtons = screen.getAllByRole('button', { name: /remove payment method/i });
|
|
314
|
+
await user.click(removeButtons[0]);
|
|
315
|
+
|
|
316
|
+
await waitFor(() => {
|
|
317
|
+
const remainingInputs = screen.getAllByPlaceholderText(/enter amount/i) as HTMLInputElement[];
|
|
318
|
+
expect(remainingInputs).toHaveLength(1);
|
|
319
|
+
expect(remainingInputs[0].value).toBe('75');
|
|
320
|
+
});
|
|
321
|
+
});
|
|
142
322
|
});
|