onClickAction(row, i)} style={{height: "160px", 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
--- src/stock-adjustment-mobile/edit-product-page/edit-product-page.jsx (revision 0)
+++ src/stock-adjustment-mobile/edit-product-page/edit-product-page.jsx (revision f88f8b7d1f2a79ab3a66389d30d09caceffcda5e)
@@ -0,0 +1,315 @@
+/*
+ * This program is part of the OpenLMIS logistics management information system platform software.
+ * Copyright © 2017 VillageReach
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Affero General Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Affero General Public License for more details. You should have received a copy of
+ * the GNU Affero General Public License along with this program. If not, see
+ * http://www.gnu.org/licenses. For additional information contact info@OpenLMIS.org.
+ */
+
+import React, { useMemo, useState, useEffect } from 'react';
+import { useHistory, useLocation } from 'react-router-dom';
+import { useDispatch, useSelector } from 'react-redux';
+import { Form } from 'react-final-form';
+import arrayMutators from 'final-form-arrays';
+import { FieldArray } from 'react-final-form-arrays';
+import createDecorator from 'final-form-calculate';
+import update from 'immutability-helper';
+
+import InputField from '../../react-components/form-fields/input-field';
+import SelectField from '../../react-components/form-fields/select-field';
+import ReadOnlyField from '../../react-components/form-fields/read-only-field';
+import confirmAlertCustom from '../../react-components/modals/confirm';
+import { formatLot, formatDate, formatDateISO, toastProperties, formatProductName } from '../format-utils';
+import AddButton from '../../react-components/buttons/add-button';
+import { setAdjustment } from '../reducers/adjustment';
+import { setToastList } from '../reducers/toasts';
+
+
+const EditProductPage = ({}) => {
+ const history = useHistory();
+ const location = useLocation();
+ const dispatch = useDispatch();
+
+ const userHomeFacility = useSelector(state => state.facilities.userHomeFacility);
+ const productOptions = useSelector(state => state.productOptions.productOptions);
+ const reasons = useSelector(state => state.reasons.reasons);
+ const adjustment = useSelector(state => state.adjustment.adjustment);
+ const program = useSelector(state => state.program.program);
+ const [productToEdit, setProductToEdit] = useState(null)
+ const [indexOfProductToEdit, setIndexOfProductToEdit] = useState(null);
+ const toastList = useSelector(state => state.toasts.toasts);
+ const [quantityCurrentState, setQuantityCurrentState] = useState(null);
+ const [reasonCurrentState, setReasonCurrentState] = useState(null);
+
+ useEffect(() => {
+ setProductToEdit(location.state.productToEdit);
+ setIndexOfProductToEdit(location.state.indexOfProductToEdit);
+ setQuantityCurrentState(location.state.productToEdit.quantity);
+ setReasonCurrentState(location.state.productToEdit.reason.name);
+ }, [location]);
+
+ const decorator = useMemo(() => createDecorator({
+ field: /product/,
+ updates: {
+ stockOnHand: (productVal, itemsVal) => {
+ const orderable = itemsVal.items[0]?.product ?? [];
+ if (itemsVal.items[0].hasOwnProperty('lot')) {
+ delete itemsVal.items[0].lot;
+ }
+ const lotCode = null;
+ const stockOnHand = getStockOnHand(orderable, lotCode);
+ return stockOnHand;
+ }
+ }
+ },
+ {
+ field: /quantity/,
+ updates: {
+ stockOnHand: (productVal, itemsVal) => {
+ const orderable = itemsVal.items[0]?.product ?? [];
+ const lotCode = itemsVal.items[0]?.lot?.lotCode ?? null;
+ const stockOnHand = getStockOnHand(orderable, lotCode);
+ return stockOnHand;
+ }
+ }
+ }
+ ), []);
+
+ const isQuantityNotFilled = (quantity) => {
+ return _.isUndefined(quantity) || _.isNull(quantity) || _.isNaN(quantity) || quantity === "";
+ }
+
+ const validate = values => {
+ const errors = { items: [] };
+
+ values.items.forEach(item => {
+ let orderable = item.product;
+ if (!item.product) {
+ errors.items['product'] = { product: 'Required' };
+ orderable = [];
+ }
+
+ if (isQuantityNotFilled(item.quantity)) {
+ errors.items['quantity'] = { quantity: 'Required' };
+ }
+
+ if (!item.reason) {
+ errors.items['reason'] = { reason: 'Required' };
+ } else {
+ const stockOnHandQuantity = getStockOnHand(orderable, item?.lot?.lotCode ?? null);
+ if (!errors.items.hasOwnProperty('quantity')) {
+ if (item.reason.reasonType !== "CREDIT" && item.quantity > stockOnHandQuantity) {
+ errors.items['quantity'] = { quantity: 'Quantity cannot be greater than stock on hand value.' };
+ }
+ }
+ }
+ });
+
+ return errors;
+ };
+
+ const getStockOnHand = (orderable, lotCode) => {
+ let returnedStock = null;
+ orderable.forEach(product => {
+ const productLotCode = product?.lot?.lotCode ?? null;
+ if (lotCode === productLotCode) {
+ returnedStock = product.stockOnHand;
+ }
+ });
+ return returnedStock;
+ };
+
+ const showToast = (type) => {
+ const toastPropertiesList = toastProperties.find((toast) => toast.title.toLowerCase() === type);
+ dispatch(setToastList([...toastList, toastPropertiesList]));
+ };
+
+ const cancel = () => {
+ history.goBack();
+ };
+
+ const deleteProduct = () => {
+ const adjustmentLenght = adjustment.length;
+ dispatch(setAdjustment(update(adjustment, { $splice: [[indexOfProductToEdit, 1]] } )));
+ showToast('success');
+ if (adjustmentLenght > 1) {
+ history.goBack();
+ }
+ else{
+ history.push('/makeAdjustmentAddProducts/submitAdjustment/programChoice');
+ }
+ };
+
+ const updateAdjustmentList = (values) => {
+ values.reasonFreeText = null;
+ values.occurredDate = formatDateISO(new Date());
+ values.reason = values.items[0].reason;
+ values.lot = values.items[0]?.lot ?? null;
+ values.displayLotMessage = values?.lot?.lotCode ?? "No lot defined";
+ values.quantity = values.items[0].quantity;
+
+ const productInformation = values.items[0].product;
+ const lotCode = values?.lot?.lotCode ?? null;
+ productInformation.forEach(prod => {
+ const productLotCode = prod?.lot?.lotCode ?? null;
+ if (lotCode === productLotCode) {
+ values.orderable = prod.orderable;
+ values.stockCard = prod.stockCard;
+ values.productName = prod.orderable.fullProductName;
+ }
+ });
+ return values;
+ }
+
+ const onSubmit = (values) => {
+ values = updateAdjustmentList(values);
+ if (values.quantity === quantityCurrentState && values.reason.name === reasonCurrentState) {
+ onSubmitWithoutChanges();
+ } else {
+ onSubmitWithChanges(values);
+ }
+ }
+
+ const onSubmitWithChanges = (values) => {
+ dispatch(setAdjustment(update(adjustment, { [indexOfProductToEdit] : {$set: values} })));
+ showToast('success');
+ history.push("/makeAdjustmentAddProducts/submitAdjustment");
+ };
+
+ const onSubmitWithoutChanges = () => {
+ history.push("/makeAdjustmentAddProducts/submitAdjustment");
+ };
+
+ const getLotsOptions = (orderableGroup) => {
+ const lots = _.chain(orderableGroup).pluck('lot')
+ .compact()
+ .map(lot => ({ ...lot, expirationDate: new Date(lot.expirationDate) }))
+ .value();
+
+ return _.map(lots, lot => ({ name: formatLot(lot), value: lot }));
+ };
+
+ const renderLotSelect = (fieldName, product, v) => {
+ const options = getLotsOptions(product);
+ const noOptions = !options?.length;
+ return (
+
+ );
+ };
+
+ return (
+
+ );
+};
+
+export default EditProductPage;
Index: src/stock-adjustment-mobile/reducers/adjustment.jsx
===================================================================
diff -u -N -rd30e1686e3d50852bb158a59d5c943d9d9afd835 -rf88f8b7d1f2a79ab3a66389d30d09caceffcda5e
--- src/stock-adjustment-mobile/reducers/adjustment.jsx (.../adjustment.jsx) (revision d30e1686e3d50852bb158a59d5c943d9d9afd835)
+++ src/stock-adjustment-mobile/reducers/adjustment.jsx (.../adjustment.jsx) (revision f88f8b7d1f2a79ab3a66389d30d09caceffcda5e)
@@ -21,6 +21,9 @@
adjustment: []
},
reducers: {
+ setAdjustment: (state, action) => {
+ state.adjustment = action.payload;
+ },
appendToAdjustment: (state, action) => {
state.adjustment.push(action.payload);
},
@@ -30,6 +33,7 @@
}
});
+export const {setAdjustment} = adjustmentSlice.actions;
export const {appendToAdjustment} = adjustmentSlice.actions;
export const {resetAdjustment} = adjustmentSlice.actions;