@@ -20,6 +20,7 @@ import DateField from 'components/form-elements/DateField';
2020import ProductSelectField from 'components/form-elements/ProductSelectField' ;
2121import SelectField from 'components/form-elements/SelectField' ;
2222import TextField from 'components/form-elements/TextField' ;
23+ import ConfirmExpirationDateModal from 'components/modals/ConfirmExpirationDateModal' ;
2324import { STOCK_MOVEMENT_URL } from 'consts/applicationUrls' ;
2425import apiClient from 'utils/apiClient' ;
2526import { renderFormField , setColumnValue } from 'utils/form-utils' ;
@@ -226,6 +227,10 @@ class AddItemsPage extends Component {
226227newItem :false ,
227228totalCount :0 ,
228229isFirstPageLoaded :false ,
230+ isExpirationModalOpen :false ,
231+ // Stores the resolve function for the ConfirmExpirationDateModal promise
232+ resolveExpirationModal :null ,
233+ itemsWithMismatchedExpiry :[ ] ,
229234} ;
230235
231236this . props . showSpinner ( ) ;
@@ -485,26 +490,37 @@ class AddItemsPage extends Component {
485490}
486491
487492/**
488- * Shows Inventory item expiration date update confirmation dialog.
489- *@param {function } onConfirm
493+ * Shows Inventory item expiration date update confirmation modal.
494+ *@param {Array } itemsWithMismatchedExpiry - Array of elements with mismatched expiration dates.
495+ *@returns {Promise } - Resolves to true if user confirms the update, false if not.
490496 *@public
491497 */
492- confirmInventoryItemExpirationDateUpdate ( onConfirm ) {
493- confirmAlert ( {
494- title :this . props . translate ( 'react.stockMovement.message.confirmSave.label' , 'Confirm save' ) ,
495- message :this . props . translate (
496- 'react.stockMovement.confirmExpiryDateUpdate.message' ,
497- 'This will update the expiry date across all depots in the system. Are you sure you want to proceed?' ,
498- ) ,
499- buttons :[
500- {
501- label :this . props . translate ( 'react.default.yes.label' , 'Yes' ) ,
502- onClick :onConfirm ,
503- } ,
504- {
505- label :this . props . translate ( 'react.default.no.label' , 'No' ) ,
506- } ,
507- ] ,
498+ confirmExpirationDateSave ( itemsWithMismatchedExpiry ) {
499+ return new Promise ( ( resolve ) => {
500+ this . setState ( {
501+ isExpirationModalOpen :true ,
502+ resolveExpirationModal :resolve ,
503+ itemsWithMismatchedExpiry,
504+ } ) ;
505+ } ) ;
506+ }
507+
508+ /**
509+ * Handles the response from the expiration date confirmation modal.
510+ *@param {boolean } shouldUpdate - True if the user confirmed the update, false if not.
511+ *@public
512+ */
513+ handleExpirationModalResponse ( shouldUpdate ) {
514+ // Resolve the promise returned by confirmExpirationDateSave.
515+ if ( this . state . resolveExpirationModal ) {
516+ this . state . resolveExpirationModal ( shouldUpdate ) ;
517+ }
518+
519+ // Close the modal and reset its state.
520+ this . setState ( {
521+ isExpirationModalOpen :false ,
522+ resolveExpirationModal :null ,
523+ itemsWithMismatchedExpiry :[ ] ,
508524} ) ;
509525}
510526
@@ -620,24 +636,53 @@ class AddItemsPage extends Component {
620636this . props . showSpinner ( ) ;
621637
622638this . saveRequisitionItemsInCurrentStep ( lineItems )
623- . then ( ( resp ) => {
639+ . then ( async ( resp ) => {
624640let values = formValues ;
625641if ( resp ) {
626642values = { ...formValues , lineItems :resp . data . data . lineItems } ;
627643}
628644
629- if ( _ . some ( values . lineItems , ( item ) => item . inventoryItem
630- && item . expirationDate !== item . inventoryItem . expirationDate ) ) {
631- if ( _ . some ( values . lineItems , ( item ) => item . inventoryItem . quantity && item . inventoryItem . quantity !== '0' ) ) {
632- this . props . hideSpinner ( ) ;
633- this . confirmInventoryItemExpirationDateUpdate ( ( ) =>
634- this . updateInventoryItemsAndTransitionToNextStep ( values , lineItems ) ) ;
635- } else {
636- this . updateInventoryItemsAndTransitionToNextStep ( values , lineItems ) ;
645+ const hasExpiryMismatch = values . lineItems . some (
646+ ( item ) => item . inventoryItem && item . expirationDate !== item . inventoryItem . expirationDate ,
647+ ) ;
648+
649+ if ( ! hasExpiryMismatch ) {
650+ return this . transitionToNextStepAndChangePage ( formValues ) ;
651+ }
652+
653+ const hasNonZeroQuantity = values . lineItems . some (
654+ ( item ) => item . inventoryItem ?. quantity && item . inventoryItem . quantity !== '0' ,
655+ ) ;
656+
657+ if ( hasNonZeroQuantity ) {
658+ this . props . hideSpinner ( ) ;
659+
660+ const itemsWithMismatchedExpiry = values . lineItems
661+ . filter (
662+ ( item ) =>
663+ item . inventoryItem
664+ && item . inventoryItem . expirationDate !== item . expirationDate
665+ && item . inventoryItem . quantity
666+ && item . inventoryItem . quantity !== '0' ,
667+ )
668+ . map ( ( item ) => ( {
669+ code :item . product ?. productCode ,
670+ product :item . product ,
671+ lotNumber :item . lotNumber ,
672+ previousExpiry :item . inventoryItem . expirationDate ,
673+ newExpiry :item . expirationDate ,
674+ } ) ) ;
675+
676+ if ( itemsWithMismatchedExpiry . length > 0 ) {
677+ const shouldUpdateExpirationDate =
678+ await this . confirmExpirationDateSave ( itemsWithMismatchedExpiry ) ;
679+ if ( ! shouldUpdateExpirationDate ) {
680+ return Promise . reject ( ) ;
681+ }
637682}
638- } else {
639- this . transitionToNextStepAndChangePage ( formValues ) ;
640683}
684+
685+ return this . updateInventoryItemsAndTransitionToNextStep ( values , lineItems ) ;
641686} )
642687. catch ( ( ) => this . props . hideSpinner ( ) ) ;
643688}
@@ -1098,6 +1143,12 @@ class AddItemsPage extends Component {
10981143< Translate id = "react.default.button.next.label" defaultMessage = "Next" />
10991144</ button >
11001145</ div >
1146+ < ConfirmExpirationDateModal
1147+ isOpen = { this . state . isExpirationModalOpen }
1148+ itemsWithMismatchedExpiry = { this . state . itemsWithMismatchedExpiry }
1149+ onConfirm = { ( ) => this . handleExpirationModalResponse ( true ) }
1150+ onCancel = { ( ) => this . handleExpirationModalResponse ( false ) }
1151+ />
11011152</ form >
11021153</ div >
11031154) }