Index: src/stock-adjustment-mobile/add-products-page/add-product-page.jsx =================================================================== diff -u -N -rcc51a07104241eccae02f0a18b5df64289fed08d -re98f0c8132884e08b48d3ce6705938335f1280ad --- src/stock-adjustment-mobile/add-products-page/add-product-page.jsx (.../add-product-page.jsx) (revision cc51a07104241eccae02f0a18b5df64289fed08d) +++ src/stock-adjustment-mobile/add-products-page/add-product-page.jsx (.../add-product-page.jsx) (revision e98f0c8132884e08b48d3ce6705938335f1280ad) @@ -30,7 +30,7 @@ import Input from '../../react-components/inputs/input'; import { formatLot, formatDate, formatDateISO, isQuantityNotFilled, maxDateToday } from '../format-utils'; import AddButton from '../../react-components/buttons/add-button'; -import { CREDIT, ISSUE } from '../consts'; +import { CREDIT, ISSUE, RECEIVE } from '../consts'; const AddProductsPage = ({ adjustmentType, appendToAdjustment }) => { @@ -105,7 +105,7 @@ } } - if (adjustmentType === ISSUE) { + if (adjustmentType === ISSUE || adjustmentType === RECEIVE) { if (!item.assignment) { errors.items['assignment'] = { issueTo: 'Required' }; } @@ -138,8 +138,9 @@ const updateAdjustmentList = (values) => { values.reasonFreeText = null; values.occurredDate = values.items[0]?.occurredDate ?? formatDateISO(new Date()); - if (adjustmentType === ISSUE) { + if (adjustmentType === ISSUE || adjustmentType === RECEIVE) { values.assignment = values.items[0].assignment; + values.assigmentName = values.items[0].assignment.name; if (values.assignment.isFreeTextAllowed ) { values.srcDstFreeText = values.items[0]?.srcDstFreeText ?? ""; } @@ -214,6 +215,20 @@ } }; + const renderReceiveFromSelectField = (fieldName, product, v) => { + if (adjustmentType === RECEIVE) { + return ( + + ); + } + }; + const renderIssueDestinationCommentField = (fieldName, product, v) => { if (adjustmentType === ISSUE) { const inputProps = {}; @@ -271,6 +286,7 @@ label="Stock on Hand" containerClass='field-full-width' /> + {renderReceiveFromSelectField(name, values.items[index].product)} {renderIssueSelectField(name, values.items[index].product)} {renderIssueDestinationCommentField(name, values.items[index].product)} } @@ -122,6 +123,7 @@ resetAdjustment={resetAdjustment} setSourceDestinations={setSourceDestinations} setToastList={setToastList} + orderableGroupService={orderableGroupService} /> } Index: src/stock-adjustment-mobile/adjustment-form.component.jsx =================================================================== diff -u -N -r14d88fc7e9bf0d7ea8a0020a2777c017abb3b427 -re98f0c8132884e08b48d3ce6705938335f1280ad --- src/stock-adjustment-mobile/adjustment-form.component.jsx (.../adjustment-form.component.jsx) (revision 14d88fc7e9bf0d7ea8a0020a2777c017abb3b427) +++ src/stock-adjustment-mobile/adjustment-form.component.jsx (.../adjustment-form.component.jsx) (revision e98f0c8132884e08b48d3ce6705938335f1280ad) @@ -23,7 +23,7 @@ import confirmAlertCustom from '../react-components/modals/confirm'; import BlockList from './components/block-list.component'; import Toast from './components/toast.component'; -import { SUCCESS, OFFLINE, ERROR } from './consts'; +import { SUCCESS, OFFLINE, ERROR, RECEIVE, ADJUSTMENT, ISSUE } from './consts'; const AdjustmentForm = ({ stockAdjustmentCreationService, @@ -115,11 +115,19 @@ const deleteToast = (id, listToRemove) => listToRemove.filter(element => element.id !== id); - const dataToDisplay = [ + const dataToDisplayIssueReceive = [ {"key": "productNameWithReason", "textToDisplay": ""}, {"key": "displayLotMessage", "textToDisplay": "Lot Code"}, - {"key": "quantity", "textToDisplay": "Quantity"} + {"key": "quantity", "textToDisplay": "Quantity"}, + {"key": "assigmentName", "textToDisplay": adjustmentType === ISSUE ? "Issue to": "Receive From"} ]; + const DataToDisplayAdjustment = [ + {"key": "productNameWithReason", "textToDisplay": ""}, + {"key": "displayLotMessage", "textToDisplay": "Lot Code"}, + {"key": "quantity", "textToDisplay": "Quantity"} + ] + const dataToDisplay = adjustmentType === ADJUSTMENT ? DataToDisplayAdjustment : dataToDisplayIssueReceive; + const heightOfBlock = dataToDisplay.length === 3 ? "120px" : "160px"; const headerToDisplay = "productNameWithReason"; return ( @@ -145,6 +153,7 @@ data={adjustment} dataToDisplay={dataToDisplay} headerToDisplay={headerToDisplay} + heightOfBlock={heightOfBlock} onClickAction={editProduct} /> Index: src/stock-adjustment-mobile/components/block-list.component.jsx =================================================================== diff -u -N -rf4306c9bcf34f8fde8362e3081adb9630a7ca8f8 -re98f0c8132884e08b48d3ce6705938335f1280ad --- src/stock-adjustment-mobile/components/block-list.component.jsx (.../block-list.component.jsx) (revision f4306c9bcf34f8fde8362e3081adb9630a7ca8f8) +++ src/stock-adjustment-mobile/components/block-list.component.jsx (.../block-list.component.jsx) (revision e98f0c8132884e08b48d3ce6705938335f1280ad) @@ -15,13 +15,13 @@ import React from 'react'; -const BlockList = ({data, dataToDisplay, headerToDisplay, onClickAction}) => { +const BlockList = ({data, dataToDisplay, headerToDisplay, heightOfBlock, onClickAction}) => { return (
{data.map((row, i) => { return ( -
onClickAction(row, i)} style={{height: "120px", width: "100%", borderBottom: "1px solid #dbdada", borderTop: "1px solid #dbdada"}}> +
onClickAction(row, i)} style={{height: heightOfBlock, width: "100%", borderBottom: "1px solid #dbdada", borderTop: "1px solid #dbdada"}}> {dataToDisplay.map((display, index) => { if (row.hasOwnProperty(display.key)) { if (headerToDisplay === display.key) { Index: src/stock-adjustment-mobile/edit-product-page/edit-product-page.jsx =================================================================== diff -u -N -r14d88fc7e9bf0d7ea8a0020a2777c017abb3b427 -re98f0c8132884e08b48d3ce6705938335f1280ad --- src/stock-adjustment-mobile/edit-product-page/edit-product-page.jsx (.../edit-product-page.jsx) (revision 14d88fc7e9bf0d7ea8a0020a2777c017abb3b427) +++ src/stock-adjustment-mobile/edit-product-page/edit-product-page.jsx (.../edit-product-page.jsx) (revision e98f0c8132884e08b48d3ce6705938335f1280ad) @@ -31,7 +31,7 @@ import Input from '../../react-components/inputs/input'; import { formatLot, formatDateISO, toastProperties, isQuantityNotFilled, maxDateToday } from '../format-utils'; import AddButton from '../../react-components/buttons/add-button'; -import { SUCCESS, OFFLINE, ISSUE, CREDIT } from '../consts'; +import { SUCCESS, OFFLINE, ISSUE, CREDIT, RECEIVE } from '../consts'; const EditProductPage = ({ offlineService, adjustmentType, setToastList, setAdjustment }) => { @@ -67,7 +67,7 @@ setReasonCurrentState(location.state.productToEdit.reason.name); setLotCodeCurrentState(location.state.productToEdit?.lot?.lotCode ?? null); setDateCurrentState(location.state.productToEdit.occurredDate); - if (adjustmentType === ISSUE) { + if (adjustmentType === ISSUE || adjustmentType === RECEIVE) { setSrcDstCurrentState(location.state.productToEdit.assignment.id); setSrcDstFreeTextCCurrentState(location.state.productToEdit?.srcDstFreeText ?? null); } @@ -131,7 +131,7 @@ } } - if (adjustmentType === ISSUE) { + if (adjustmentType === ISSUE || adjustmentType === RECEIVE) { if (!item.assignment) { errors.items['assignment'] = { issueTo: 'Required' }; } @@ -180,8 +180,9 @@ const updateAdjustmentList = (values) => { values.reasonFreeText = null; values.occurredDate = values.items[0]?.occurredDate ?? formatDateISO(new Date()); - if (adjustmentType === ISSUE) { + if (adjustmentType === ISSUE || adjustmentType === RECEIVE) { values.assignment = values.items[0].assignment; + values.assigmentName = values.items[0].assignment.name; if (values.assignment.isFreeTextAllowed ) { values.srcDstFreeText = values.items[0]?.srcDstFreeText ?? ""; } @@ -209,8 +210,8 @@ const onSubmit = (values) => { values = updateAdjustmentList(values); const lotCode = values?.lot?.lotCode ?? null; - if (adjustmentType === ISSUE) { - onSubmitIssue(values, lotCode); + if (adjustmentType === ISSUE || adjustmentType === RECEIVE) { + onSubmitIssueReceive(values, lotCode); } else { onSubmitAdjustment(values, lotCode); } @@ -224,7 +225,7 @@ } } - const onSubmitIssue = (values, lotCode) => { + const onSubmitIssueReceive = (values, lotCode) => { if (values.quantity === quantityCurrentState && values.reason.name === reasonCurrentState && lotCode === lotCodeCurrentState && values.assignment.id === srcDstCurrentState && (values?.srcDstFreeText ?? null) === srcDstFreeTextCurrentState && dateCurrentState === values.occurredDate) { @@ -272,6 +273,20 @@ ); }; + const renderReceiveFromSelectField = (fieldName, product, v) => { + if (adjustmentType === RECEIVE) { + return ( + + ); + } + }; + const renderIssueSelectField = (fieldName, product, v) => { if (adjustmentType === ISSUE) { return ( @@ -344,6 +359,7 @@ label="Stock on Hand" containerClass='field-full-width' /> + {renderReceiveFromSelectField(name, values.items[index].product)} {renderIssueSelectField(name, values.items[index].product)} {renderIssueDestinationCommentField(name, values.items[index].product)} { + setSourceDestinations, resetAdjustment, setProgram, setToastList, orderableGroupService }) => { const history = useHistory(); const dispatch = useDispatch(); @@ -45,32 +45,55 @@ if (programId !== null) { const stateParams = {orderableGroups: null} const program = {id: programId} - existingStockOrderableGroupsFactory.getGroupsWithNotZeroSoh(stateParams, program, facility).then(groups => { - const productOptions = _.map(groups, group => ({ name: group[0].orderable.fullProductName, value: group })); - dispatch(setProductOptions(productOptions)); - return productOptions; - }).then(productOptions => { - const reasonType = adjustmentType === ADJUSTMENT ? null : (adjustmentType === ISSUE ? DEBIT : CREDIT ); - if (!reasonType) { - stockReasonsFactory.getAdjustmentReasons(program.id, facility.type.id).then(reasons => { - const mappedReasons = _.map(reasons, reason => ({ name: reason.name, value: reason })); - dispatch(setReasons(mappedReasons)); - return mappedReasons - }).then(mappedReasons => { - goToProductPage(programId, programObject, program); - }); - } - else { - stockReasonsFactory.getReasons(program.id, facility.type.id, reasonType).then(reasons => { - const mappedReasons = _.map(reasons.filter(reason => reason.name.contains('Transfer ')), reason => ({ name: reason.name, value: reason })); - dispatch(setReasons(mappedReasons)); - return mappedReasons - }).then(mappedReasons => { - goToProductPage(programId, programObject, program); - }); - } + if (adjustmentType === ADJUSTMENT || adjustmentType === ISSUE) { + existingStockOrderableGroupsFactory.getGroupsWithNotZeroSoh(stateParams, program, facility).then(groups => { + const productOptions = _.map(groups, group => ({ name: group[0].orderable.fullProductName, value: group })); + dispatch(setProductOptions(productOptions)); + return productOptions; + }).then(productOptions => { + afterSelectingProducts(programId, programObject, program); + }); + } + else { + orderableGroupService.findAvailableProductsAndCreateOrderableGroups(program.id, facility.id, true).then(groups => { + const productOptions = _.map(groups, group => ({ name: group[0].orderable.fullProductName, value: group })); + dispatch(setProductOptions(productOptions)); + return productOptions; + }).then(productOptions => { + afterSelectingProducts(programId, programObject, program); + }); + } + } + }; + + const afterSelectingProducts = (programId, programObject, program) => { + const reasonType = adjustmentType === ADJUSTMENT ? null : (adjustmentType === ISSUE ? DEBIT : CREDIT ); + if (!reasonType) { + stockReasonsFactory.getAdjustmentReasons(program.id, facility.type.id).then(reasons => { + const mappedReasons = _.map(reasons, reason => ({ name: reason.name, value: reason })); + dispatch(setReasons(mappedReasons)); + return mappedReasons + }).then(mappedReasons => { + goToProductPage(programId, programObject, program); }); } + else { + stockReasonsFactory.getReasons(program.id, facility.type.id, reasonType).then(reasons => { + const mappedReasons = _.map(reasons.filter(reason => reason.name.contains('Transfer ')), reason => ({ name: reason.name, value: reason })); + dispatch(setReasons(mappedReasons)); + return mappedReasons + }).then(mappedReasons => { + chooseAssigments(programId, programObject, program); + }); + } + } + + const chooseAssigments = (programId, programObject, program) => { + if (adjustmentType === ISSUE) { + goToProductPage(programId, programObject, program); + } else { + goToProductPageReceive(programId, programObject, program); + } }; const goToProductPage = (programId, programObject, program) => { @@ -88,6 +111,21 @@ }); }; + const goToProductPageReceive = (programId, programObject, program) => { + sourceDestinationService.getSourceAssignments(programId, facility.id).then(sourceDestinations => { + const returnedSourceDestination = _.map(sourceDestinations, source => ({ name: source.name, value: source })); + dispatch(setSourceDestinations(returnedSourceDestination)); + return returnedSourceDestination; + }).then(returnedSourceDestination => { + if (programSelected.programId !== program.id) { + dispatch(resetAdjustment(adjustment)); + } + dispatch(setProgram(programObject)); + removeToast(); + history.push(`/make${adjustmentType}AddProducts`); + }); + }; + const removeToast = () => { let listToRemove = toastList; if (listToRemove.length) { Index: src/stock-issue-mobile/issue-app.jsx =================================================================== diff -u -N -r14d88fc7e9bf0d7ea8a0020a2777c017abb3b427 -re98f0c8132884e08b48d3ce6705938335f1280ad --- src/stock-issue-mobile/issue-app.jsx (.../issue-app.jsx) (revision 14d88fc7e9bf0d7ea8a0020a2777c017abb3b427) +++ src/stock-issue-mobile/issue-app.jsx (.../issue-app.jsx) (revision e98f0c8132884e08b48d3ce6705938335f1280ad) @@ -36,6 +36,7 @@ sourceDestinationService, stockAdjustmentCreationService, offlineService, + orderableGroupService }) => { const dispatch = useDispatch(); @@ -69,6 +70,7 @@ resetAdjustment={resetAdjustment} setSourceDestinations={setSourceDestinations} setToastList={setToastList} + orderableGroupService={orderableGroupService} /> } @@ -119,6 +121,7 @@ resetAdjustment={resetAdjustment} setSourceDestinations={setSourceDestinations} setToastList={setToastList} + orderableGroupService={orderableGroupService} /> } Index: src/stock-issue-mobile/issue-mobile.wrapper.jsx =================================================================== diff -u -N -rdfe1bc49636a1b2a92880e2ad8f3c946c2123715 -re98f0c8132884e08b48d3ce6705938335f1280ad --- src/stock-issue-mobile/issue-mobile.wrapper.jsx (.../issue-mobile.wrapper.jsx) (revision dfe1bc49636a1b2a92880e2ad8f3c946c2123715) +++ src/stock-issue-mobile/issue-mobile.wrapper.jsx (.../issue-mobile.wrapper.jsx) (revision e98f0c8132884e08b48d3ce6705938335f1280ad) @@ -50,6 +50,7 @@ sourceDestinationService={sourceDestinationService} offlineService={offlineService} stockAdjustmentCreationService={stockAdjustmentCreationService} + orderableGroupService={orderableGroupService} /> , app Index: src/stock-receive-mobile/receive-app.jsx =================================================================== diff -u -N -r9b23add288958da43e8a4f8be30e48edda073463 -re98f0c8132884e08b48d3ce6705938335f1280ad --- src/stock-receive-mobile/receive-app.jsx (.../receive-app.jsx) (revision 9b23add288958da43e8a4f8be30e48edda073463) +++ src/stock-receive-mobile/receive-app.jsx (.../receive-app.jsx) (revision e98f0c8132884e08b48d3ce6705938335f1280ad) @@ -17,21 +17,26 @@ import { HashRouter as Router, Route, Switch } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux'; import { setUserHomeFacility } from './reducers/facilities'; -import { resetAdjustment } from './reducers/adjustment'; +import { appendToAdjustment, resetAdjustment, setAdjustment } from './reducers/adjustment'; import { setProductOptions } from './reducers/product-options'; import { setReasons } from './reducers/reasons'; import { setProgram } from './reducers/program'; import { setSourceDestinations } from './reducers/source-destination'; import { setToastList } from './reducers/toasts'; import ProgramSelect from '../stock-adjustment-mobile/program-select'; +import AddProductsPage from '../stock-adjustment-mobile/add-products-page/add-product-page'; +import AdjustmentForm from '../stock-adjustment-mobile/adjustment-form.component'; +import EditProductPage from '../stock-adjustment-mobile/edit-product-page/edit-product-page'; import { RECEIVE } from '../stock-adjustment-mobile/consts'; const ReceiveApp = ({ facilityFactory, existingStockOrderableGroupsFactory, stockReasonsFactory, sourceDestinationService, + stockAdjustmentCreationService, offlineService, + orderableGroupService }) => { const dispatch = useDispatch(); @@ -50,6 +55,57 @@ hashType="hashbang" > + + { + userHomeFacility + && + } + + + { + userHomeFacility + && + } + + + { + userHomeFacility + && + } + + + { + userHomeFacility + && + } + { userHomeFacility @@ -65,6 +121,7 @@ resetAdjustment={resetAdjustment} setSourceDestinations={setSourceDestinations} setToastList={setToastList} + orderableGroupService={orderableGroupService} /> } Index: src/stock-receive-mobile/receive-mobile.routes.js =================================================================== diff -u -N -r9b23add288958da43e8a4f8be30e48edda073463 -re98f0c8132884e08b48d3ce6705938335f1280ad --- src/stock-receive-mobile/receive-mobile.routes.js (.../receive-mobile.routes.js) (revision 9b23add288958da43e8a4f8be30e48edda073463) +++ src/stock-receive-mobile/receive-mobile.routes.js (.../receive-mobile.routes.js) (revision e98f0c8132884e08b48d3ce6705938335f1280ad) @@ -41,6 +41,28 @@ } }, accessRights: [STOCKMANAGEMENT_RIGHTS.STOCK_ADJUST] - }); + }) + .state('openlmis.stockmanagement.receiveMobile.form', { + url: '/makeReceiveAddProducts', + isOffline: true, + accessRights: [STOCKMANAGEMENT_RIGHTS.STOCK_ADJUST], + showInNavigation: false, + showInNavigationOnLowResolutions: false + }) + .state('openlmis.stockmanagement.receiveMobile.form.submitReceive', { + url: '/submitReceive', + isOffline: true, + accessRights: [STOCKMANAGEMENT_RIGHTS.STOCK_ADJUST] + }) + .state('openlmis.stockmanagement.receiveMobile.form.submitReceive.programChoice', { + url: '/programChoice', + isOffline: true, + accessRights: [STOCKMANAGEMENT_RIGHTS.STOCK_ADJUST] + }) + .state('openlmis.stockmanagement.receiveMobile.form.editProductReceive', { + url: '/editProductReceive', + isOffline: true, + accessRights: [STOCKMANAGEMENT_RIGHTS.STOCK_ADJUST] + }); } })(); Index: src/stock-receive-mobile/receive-mobile.wrapper.jsx =================================================================== diff -u -N -r9b23add288958da43e8a4f8be30e48edda073463 -re98f0c8132884e08b48d3ce6705938335f1280ad --- src/stock-receive-mobile/receive-mobile.wrapper.jsx (.../receive-mobile.wrapper.jsx) (revision 9b23add288958da43e8a4f8be30e48edda073463) +++ src/stock-receive-mobile/receive-mobile.wrapper.jsx (.../receive-mobile.wrapper.jsx) (revision e98f0c8132884e08b48d3ce6705938335f1280ad) @@ -49,6 +49,8 @@ stockReasonsFactory={stockReasonsFactory} sourceDestinationService={sourceDestinationService} offlineService={offlineService} + stockAdjustmentCreationService={stockAdjustmentCreationService} + orderableGroupService={orderableGroupService} /> , app