@openmrs/esm-stock-management-app 1.0.1-pre.785 → 1.0.1-pre.790
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/493.js +1 -1
- package/dist/493.js.map +1 -1
- package/dist/880.js +1 -0
- package/dist/880.js.map +1 -0
- package/dist/942.js +1 -0
- package/dist/942.js.map +1 -0
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-stock-management-app.js +1 -1
- package/dist/openmrs-esm-stock-management-app.js.buildmanifest.json +41 -41
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/config-schema.ts +6 -0
- package/src/index.ts +15 -21
- package/src/routes.json +5 -4
- package/src/stock-operations/add-stock-operation/stock-operations-expanded-row/stock-items-table.scss +34 -0
- package/src/stock-operations/add-stock-operation/stock-operations-expanded-row/stock-items-table.tsx +111 -0
- package/src/stock-operations/add-stock-operation/stock-operations-expanded-row/stock-operation-expanded-row.component.tsx +116 -0
- package/src/stock-operations/add-stock-operation/stock-operations-expanded-row/stock-operation-expanded-row.scss +31 -0
- package/src/stock-operations/add-stock-operation/stock-operations-expanded-row/stock-operations-status.tsx +45 -0
- package/src/stock-operations/edit-stock-operation/edit-stock-operation-action-menu.component.tsx +2 -2
- package/src/stock-operations/stock-operation-actions.component.tsx +81 -0
- package/src/stock-operations/stock-operation-links.component.tsx +82 -0
- package/src/stock-operations/stock-operation-reference.component.tsx +2 -2
- package/src/stock-operations/stock-operation-types-selector/stock-operation-types-selector.component.tsx +2 -2
- package/src/stock-operations/stock-operation.utils.tsx +8 -13
- package/src/stock-operations/stock-operations-dialog/stock-operations-issue-stock-button.component.tsx +2 -2
- package/src/stock-operations/stock-operations-forms/input-components/stock-item-search.component.tsx +30 -7
- package/src/stock-operations/stock-operations-forms/step1.test.tsx +158 -17
- package/src/stock-operations/stock-operations-forms/step2.test.tsx +59 -10
- package/src/stock-operations/stock-operations-forms/step3.test.tsx +63 -10
- package/src/stock-operations/stock-operations-forms/steps/base-operation-details-form-step.tsx +11 -9
- package/src/stock-operations/stock-operations-forms/steps/received-items.component.tsx +111 -0
- package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-cell.component.tsx +20 -9
- package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.component.tsx +21 -46
- package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.scc.scss +4 -18
- package/src/stock-operations/stock-operations-forms/steps/stock-operation-submission-form-step.component.tsx +22 -10
- package/src/stock-operations/stock-operations-forms/stock-issue-form-initializer-with-related-requisition-operation.component.tsx +20 -3
- package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.workspace.tsx +19 -7
- package/src/stock-operations/stock-operations-forms/stock-operation-form.component.tsx +114 -67
- package/src/stock-operations/stock-operations-forms/stock-operation-form.scss +5 -24
- package/src/stock-operations/stock-operations-forms/stock-operation-related-link.component.tsx +2 -2
- package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stepper.scss +14 -11
- package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stock-operation-stepper.component.tsx +2 -6
- package/src/stock-operations/stock-operations-table.component.tsx +39 -38
- package/src/stock-operations/stock-operations-table.scss +20 -0
- package/dist/155.js +0 -1
- package/dist/155.js.map +0 -1
- package/dist/914.js +0 -1
- package/dist/914.js.map +0 -1
- package/src/stock-operations/received-items.component.tsx +0 -93
- package/src/stock-operations/stock-operations-forms/stock-operation-form-header.component.tsx +0 -166
@@ -0,0 +1,111 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { useTranslation } from 'react-i18next';
|
3
|
+
import { StockOperationDTO } from '../../../core/api/types/stockOperation/StockOperationDTO';
|
4
|
+
import {
|
5
|
+
DataTable,
|
6
|
+
Table,
|
7
|
+
TableBody,
|
8
|
+
TableContainer,
|
9
|
+
TableHead,
|
10
|
+
TableHeader,
|
11
|
+
TableRow,
|
12
|
+
TableCell,
|
13
|
+
DataTableSkeleton,
|
14
|
+
Button,
|
15
|
+
} from '@carbon/react';
|
16
|
+
import styles from './stock-operation-items-form-step.scc.scss';
|
17
|
+
import { ArrowLeft } from '@carbon/react/icons';
|
18
|
+
|
19
|
+
const formatDate = (date: Date | string | null) => {
|
20
|
+
if (!date) return ' ';
|
21
|
+
const d = new Date(date);
|
22
|
+
const day = String(d.getDate()).padStart(2, '0');
|
23
|
+
const month = String(d.getMonth() + 1).padStart(2, '0');
|
24
|
+
const year = d.getFullYear();
|
25
|
+
return `${month}/${day}/${year}`;
|
26
|
+
};
|
27
|
+
|
28
|
+
interface ReceivedItemsProps {
|
29
|
+
stockOperation?: StockOperationDTO;
|
30
|
+
onPrevious?: () => void;
|
31
|
+
}
|
32
|
+
|
33
|
+
const ReceivedItems: React.FC<ReceivedItemsProps> = ({ stockOperation, onPrevious }) => {
|
34
|
+
const { t } = useTranslation();
|
35
|
+
|
36
|
+
const headers = [
|
37
|
+
{ key: 'item', header: t('item', 'Item') },
|
38
|
+
{ key: 'requested', header: t('requested', 'Requested') },
|
39
|
+
{ key: 'batch', header: t('batch', 'Batch No') },
|
40
|
+
{ key: 'expiry', header: t('expiry', 'Expiry Date') },
|
41
|
+
{ key: 'qtySent', header: t('quantitySent', 'Quantity Sent') },
|
42
|
+
{ key: 'qtyReceived', header: t('quantityReceived', 'Quantity Received') },
|
43
|
+
{
|
44
|
+
key: 'qtyUoM',
|
45
|
+
header: t('quantityUoM', 'Quantity Unit of Measurement(UoM)'),
|
46
|
+
},
|
47
|
+
];
|
48
|
+
|
49
|
+
const rows =
|
50
|
+
stockOperation?.stockOperationItems?.map((item) => ({
|
51
|
+
id: item.uuid,
|
52
|
+
item: item.stockItemName,
|
53
|
+
requested: item.quantityRequested || ' ',
|
54
|
+
batch: item.batchNo,
|
55
|
+
expiry: formatDate(item.expiration),
|
56
|
+
qtySent: item.quantity || ' ',
|
57
|
+
qtyReceived: item.quantityReceived || ' ',
|
58
|
+
qtyUoM: item.quantityReceivedPackagingUOMName,
|
59
|
+
})) || [];
|
60
|
+
|
61
|
+
if (!stockOperation) {
|
62
|
+
return <DataTableSkeleton role="progressbar" />;
|
63
|
+
}
|
64
|
+
|
65
|
+
const headerTitle = t('receivedItems', 'Received Items');
|
66
|
+
|
67
|
+
return (
|
68
|
+
<div style={{ margin: '10px' }}>
|
69
|
+
<div className={styles.tableContainer}>
|
70
|
+
<div className={styles.heading}>
|
71
|
+
<h4>{headerTitle}</h4>
|
72
|
+
</div>
|
73
|
+
<DataTable rows={rows} headers={headers}>
|
74
|
+
{({ rows, headers, getHeaderProps, getTableProps, getRowProps }) => (
|
75
|
+
<TableContainer>
|
76
|
+
<Table {...getTableProps()}>
|
77
|
+
<TableHead>
|
78
|
+
<TableRow>
|
79
|
+
{headers.map((header) => (
|
80
|
+
<TableHeader {...getHeaderProps({ header })} key={header.key}>
|
81
|
+
{header.header}
|
82
|
+
</TableHeader>
|
83
|
+
))}
|
84
|
+
</TableRow>
|
85
|
+
</TableHead>
|
86
|
+
<TableBody>
|
87
|
+
{rows.map((row) => (
|
88
|
+
<TableRow {...getRowProps({ row })} key={row.id}>
|
89
|
+
{row.cells.map((cell) => (
|
90
|
+
<TableCell key={cell.id}>{cell.value}</TableCell>
|
91
|
+
))}
|
92
|
+
</TableRow>
|
93
|
+
))}
|
94
|
+
</TableBody>
|
95
|
+
</Table>
|
96
|
+
</TableContainer>
|
97
|
+
)}
|
98
|
+
</DataTable>
|
99
|
+
<div className={styles.btnSet}>
|
100
|
+
{typeof onPrevious === 'function' && (
|
101
|
+
<Button kind="secondary" onClick={onPrevious} renderIcon={ArrowLeft} hasIconOnly data-testid="previous-btn">
|
102
|
+
{/* {t('previous', 'Previous')} */}
|
103
|
+
</Button>
|
104
|
+
)}
|
105
|
+
</div>
|
106
|
+
</div>
|
107
|
+
</div>
|
108
|
+
);
|
109
|
+
};
|
110
|
+
|
111
|
+
export default ReceivedItems;
|
package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-cell.component.tsx
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
-
import React, { useCallback, useEffect } from 'react';
|
2
|
-
import { useStockItem } from '../../../stock-items/stock-items.resource';
|
3
|
-
import { useTranslation } from 'react-i18next';
|
4
|
-
import { showSnackbar } from '@openmrs/esm-framework';
|
5
1
|
import { InlineLoading } from '@carbon/react';
|
6
|
-
import {
|
2
|
+
import { ConfigurableLink, showSnackbar, useConfig } from '@openmrs/esm-framework';
|
3
|
+
import React, { useEffect, useMemo } from 'react';
|
4
|
+
import { useTranslation } from 'react-i18next';
|
5
|
+
import { ConfigObject } from '../../../config-schema';
|
7
6
|
import { URL_STOCK_ITEM } from '../../../constants';
|
8
|
-
import {
|
7
|
+
import { useStockItem } from '../../../stock-items/stock-items.resource';
|
9
8
|
|
10
9
|
type StockOperationItemCellProps = {
|
11
10
|
stockItemUuid: string;
|
@@ -14,7 +13,19 @@ type StockOperationItemCellProps = {
|
|
14
13
|
const StockOperationItemCell: React.FC<StockOperationItemCellProps> = ({ stockItemUuid }) => {
|
15
14
|
const { isLoading, error, item } = useStockItem(stockItemUuid);
|
16
15
|
const { t } = useTranslation();
|
16
|
+
const { useItemCommonNameAsDisplay } = useConfig<ConfigObject>();
|
17
|
+
|
18
|
+
const commonName = useMemo(() => {
|
19
|
+
if (!useItemCommonNameAsDisplay) return;
|
20
|
+
const drugName = item?.drugName ? `(Drug name: ${item.drugName})` : undefined;
|
21
|
+
return `${item?.commonName || t('noCommonNameAvailable', 'No common name available') + (drugName ?? '')}`;
|
22
|
+
}, [item, useItemCommonNameAsDisplay, t]);
|
17
23
|
|
24
|
+
const drugName = useMemo(() => {
|
25
|
+
if (useItemCommonNameAsDisplay) return;
|
26
|
+
const commonName = item?.commonName ? `(Common name: ${item.commonName})` : undefined;
|
27
|
+
return `${item?.drugName || t('noDrugNameAvailable', 'No drug name available') + (commonName ?? '')}`;
|
28
|
+
}, [item, useItemCommonNameAsDisplay, t]);
|
18
29
|
useEffect(() => {
|
19
30
|
if (error) {
|
20
31
|
showSnackbar({
|
@@ -29,9 +40,9 @@ const StockOperationItemCell: React.FC<StockOperationItemCellProps> = ({ stockIt
|
|
29
40
|
if (error) return <>--</>;
|
30
41
|
|
31
42
|
return (
|
32
|
-
<
|
33
|
-
{
|
34
|
-
</
|
43
|
+
<ConfigurableLink target={'_blank'} to={window.spaBase + URL_STOCK_ITEM(stockItemUuid)}>
|
44
|
+
{useItemCommonNameAsDisplay ? commonName : drugName}
|
45
|
+
</ConfigurableLink>
|
35
46
|
);
|
36
47
|
};
|
37
48
|
|
@@ -9,8 +9,7 @@ import {
|
|
9
9
|
TableHeader,
|
10
10
|
TableRow,
|
11
11
|
} from '@carbon/react';
|
12
|
-
import { Edit, TrashCan } from '@carbon/react/icons';
|
13
|
-
import { isDesktop, launchWorkspace } from '@openmrs/esm-framework';
|
12
|
+
import { ArrowLeft, ArrowRight, Edit, TrashCan } from '@carbon/react/icons';
|
14
13
|
import React, { useCallback, useMemo } from 'react';
|
15
14
|
import { useFormContext } from 'react-hook-form';
|
16
15
|
import { useTranslation } from 'react-i18next';
|
@@ -20,7 +19,6 @@ import { getStockOperationUniqueId } from '../../stock-operation.utils';
|
|
20
19
|
import { BaseStockOperationItemFormData, StockOperationItemDtoSchema } from '../../validation-schema';
|
21
20
|
import useOperationTypePermisions from '../hooks/useOperationTypePermisions';
|
22
21
|
import StockItemSearch from '../input-components/stock-item-search.component';
|
23
|
-
import { StockItemFormProps } from '../stock-item-form/stock-item-form.workspace';
|
24
22
|
import QuantityUomCell from './quantity-uom-cell.component';
|
25
23
|
import StockAvailability from './stock-availability-cell.component';
|
26
24
|
import StockOperationItemBatchNoCell from './stock-operation-item-batch-no-cell.component';
|
@@ -33,12 +31,14 @@ type StockOperationItemsFormStepProps = {
|
|
33
31
|
stockOperationType: StockOperationType;
|
34
32
|
onNext?: () => void;
|
35
33
|
onPrevious?: () => void;
|
34
|
+
onLaunchItemsForm?: (stockOperationItem?: BaseStockOperationItemFormData) => void;
|
36
35
|
};
|
37
36
|
const StockOperationItemsFormStep: React.FC<StockOperationItemsFormStepProps> = ({
|
38
37
|
stockOperationType,
|
39
38
|
stockOperation,
|
40
39
|
onNext,
|
41
40
|
onPrevious,
|
41
|
+
onLaunchItemsForm,
|
42
42
|
}) => {
|
43
43
|
const { t } = useTranslation();
|
44
44
|
const operationTypePermision = useOperationTypePermisions(stockOperationType);
|
@@ -103,29 +103,6 @@ const StockOperationItemsFormStep: React.FC<StockOperationItemsFormStepProps> =
|
|
103
103
|
];
|
104
104
|
}, [operationTypePermision, t]);
|
105
105
|
|
106
|
-
const handleLaunchStockItem = useCallback(
|
107
|
-
(stockOperationItem?: BaseStockOperationItemFormData) => {
|
108
|
-
launchWorkspace('stock-operation-stock-items-form', {
|
109
|
-
workspaceTitle: t('stockItem', 'StockItem'),
|
110
|
-
...({
|
111
|
-
stockOperationType,
|
112
|
-
stockOperationItem,
|
113
|
-
onSave: (data) => {
|
114
|
-
const items = (form.getValues('stockOperationItems') ?? []) as Array<BaseStockOperationItemFormData>;
|
115
|
-
const index = items.findIndex((i) => i.uuid === data.uuid);
|
116
|
-
if (index === -1) {
|
117
|
-
items.push(data);
|
118
|
-
} else {
|
119
|
-
items[index] = data;
|
120
|
-
}
|
121
|
-
form.setValue('stockOperationItems', items as any);
|
122
|
-
},
|
123
|
-
} as StockItemFormProps),
|
124
|
-
});
|
125
|
-
},
|
126
|
-
[stockOperationType, t, form],
|
127
|
-
);
|
128
|
-
|
129
106
|
const handleDeleteStockOperationItem = useCallback(
|
130
107
|
(item: BaseStockOperationItemFormData) => {
|
131
108
|
form.setValue('stockOperationItems', observableOperationItems.filter((i) => i.uuid !== item.uuid) as any);
|
@@ -183,7 +160,7 @@ const StockOperationItemsFormStep: React.FC<StockOperationItemsFormStepProps> =
|
|
183
160
|
kind="ghost"
|
184
161
|
renderIcon={Edit}
|
185
162
|
onClick={() => {
|
186
|
-
|
163
|
+
onLaunchItemsForm?.(item);
|
187
164
|
}}
|
188
165
|
/>
|
189
166
|
<Button
|
@@ -194,14 +171,14 @@ const StockOperationItemsFormStep: React.FC<StockOperationItemsFormStepProps> =
|
|
194
171
|
kind="ghost"
|
195
172
|
renderIcon={TrashCan}
|
196
173
|
onClick={() => {
|
197
|
-
|
174
|
+
onLaunchItemsForm?.(item);
|
198
175
|
}}
|
199
176
|
/>
|
200
177
|
</>
|
201
178
|
),
|
202
179
|
};
|
203
180
|
});
|
204
|
-
}, [observableOperationItems,
|
181
|
+
}, [observableOperationItems, onLaunchItemsForm, stockOperationType]);
|
205
182
|
|
206
183
|
const headerTitle = t('stockoperationItems', 'Stock operation items');
|
207
184
|
|
@@ -210,22 +187,10 @@ const StockOperationItemsFormStep: React.FC<StockOperationItemsFormStepProps> =
|
|
210
187
|
<div className={styles.tableContainer}>
|
211
188
|
<div className={styles.heading}>
|
212
189
|
<h4>{headerTitle}</h4>
|
213
|
-
<div className={styles.btnSet}>
|
214
|
-
{typeof onPrevious === 'function' && (
|
215
|
-
<Button kind="secondary" onClick={onPrevious}>
|
216
|
-
{t('previous', 'Previous')}
|
217
|
-
</Button>
|
218
|
-
)}
|
219
|
-
{typeof onNext === 'function' && (
|
220
|
-
<Button kind="primary" onClick={onNext}>
|
221
|
-
{t('next', 'Next')}
|
222
|
-
</Button>
|
223
|
-
)}
|
224
|
-
</div>
|
225
190
|
</div>
|
226
191
|
<StockItemSearch
|
227
192
|
onSelectedItem={(stockItem) =>
|
228
|
-
|
193
|
+
onLaunchItemsForm({
|
229
194
|
uuid: `new-item-${getStockOperationUniqueId()}`,
|
230
195
|
stockItemUuid: stockItem.uuid,
|
231
196
|
hasExpiration: stockItem.hasExpiration,
|
@@ -233,7 +198,6 @@ const StockOperationItemsFormStep: React.FC<StockOperationItemsFormStepProps> =
|
|
233
198
|
})
|
234
199
|
}
|
235
200
|
/>
|
236
|
-
|
237
201
|
<DataTable
|
238
202
|
rows={tableRows ?? []}
|
239
203
|
headers={headers}
|
@@ -245,13 +209,12 @@ const StockOperationItemsFormStep: React.FC<StockOperationItemsFormStepProps> =
|
|
245
209
|
<Table {...getTableProps()}>
|
246
210
|
<TableHead>
|
247
211
|
<TableRow>
|
248
|
-
{headers.map((header
|
212
|
+
{headers.map((header) => (
|
249
213
|
<TableHeader
|
250
214
|
{...getHeaderProps({
|
251
215
|
header,
|
252
216
|
isSortable: false,
|
253
217
|
})}
|
254
|
-
className={isDesktop ? styles.desktopHeader : styles.tabletHeader}
|
255
218
|
style={header?.styles}
|
256
219
|
key={`${header.key}`}
|
257
220
|
>
|
@@ -272,7 +235,19 @@ const StockOperationItemsFormStep: React.FC<StockOperationItemsFormStepProps> =
|
|
272
235
|
</Table>
|
273
236
|
</TableContainer>
|
274
237
|
)}
|
275
|
-
|
238
|
+
/>
|
239
|
+
<div className={styles.btnSet}>
|
240
|
+
{typeof onNext === 'function' && (
|
241
|
+
<Button kind="primary" onClick={onNext} renderIcon={ArrowRight}>
|
242
|
+
{t('next', 'Next')}
|
243
|
+
</Button>
|
244
|
+
)}
|
245
|
+
{typeof onPrevious === 'function' && (
|
246
|
+
<Button kind="secondary" onClick={onPrevious} renderIcon={ArrowLeft} hasIconOnly data-testid="previous-btn">
|
247
|
+
{/* {t('previous', 'Previous')} */}
|
248
|
+
</Button>
|
249
|
+
)}
|
250
|
+
</div>
|
276
251
|
</div>
|
277
252
|
</div>
|
278
253
|
);
|
package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.scc.scss
CHANGED
@@ -3,23 +3,6 @@
|
|
3
3
|
@use '@carbon/type';
|
4
4
|
@import '~@openmrs/esm-styleguide/src/vars';
|
5
5
|
|
6
|
-
.tableContainer {
|
7
|
-
:global(.cds--data-table-content) {
|
8
|
-
height: calc(100vh - 150px);
|
9
|
-
}
|
10
|
-
}
|
11
|
-
|
12
|
-
.tableHeader {
|
13
|
-
width: 3% !important;
|
14
|
-
}
|
15
|
-
|
16
|
-
.tableBody {
|
17
|
-
display: flex;
|
18
|
-
flex-direction: row;
|
19
|
-
width: 3% !important;
|
20
|
-
gap: 8px;
|
21
|
-
}
|
22
|
-
|
23
6
|
.dataTable {
|
24
7
|
width: 100%;
|
25
8
|
}
|
@@ -57,8 +40,11 @@
|
|
57
40
|
}
|
58
41
|
|
59
42
|
.btnSet {
|
43
|
+
width: 100%;
|
44
|
+
flex: 1;
|
60
45
|
display: flex;
|
61
|
-
flex-direction: row;
|
46
|
+
flex-direction: row-reverse;
|
62
47
|
gap: layout.$spacing-03;
|
63
48
|
align-items: center;
|
49
|
+
margin-top: layout.$spacing-03;
|
64
50
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Button, Column, InlineLoading, RadioButton, RadioButtonGroup, Stack } from '@carbon/react';
|
2
|
-
import { Departure, ListChecked, Save, SendFilled } from '@carbon/react/icons';
|
2
|
+
import { ArrowLeft, ArrowRight, Departure, ListChecked, Save, SendFilled } from '@carbon/react/icons';
|
3
3
|
import { restBaseUrl, showSnackbar } from '@openmrs/esm-framework';
|
4
4
|
import React, { useCallback, useMemo, useState } from 'react';
|
5
5
|
import { useFormContext } from 'react-hook-form';
|
@@ -20,11 +20,15 @@ type StockOperationSubmissionFormStepProps = {
|
|
20
20
|
onPrevious?: () => void;
|
21
21
|
stockOperation?: StockOperationDTO;
|
22
22
|
stockOperationType: StockOperationType;
|
23
|
+
onNext?: () => void;
|
24
|
+
dismissWorkspace?: () => void;
|
23
25
|
};
|
24
26
|
const StockOperationSubmissionFormStep: React.FC<StockOperationSubmissionFormStepProps> = ({
|
25
27
|
onPrevious,
|
26
28
|
stockOperationType,
|
27
29
|
stockOperation,
|
30
|
+
onNext,
|
31
|
+
dismissWorkspace,
|
28
32
|
}) => {
|
29
33
|
const { t } = useTranslation();
|
30
34
|
const operationTypePermision = useOperationTypePermisions(stockOperationType);
|
@@ -93,6 +97,7 @@ const StockOperationSubmissionFormStep: React.FC<StockOperationSubmissionFormSte
|
|
93
97
|
: createStockOperation(payload as any));
|
94
98
|
result = resp.data; // Store the response data
|
95
99
|
handleMutate(`${restBaseUrl}/stockmanagement/stockoperation`);
|
100
|
+
dismissWorkspace?.();
|
96
101
|
showSnackbar({
|
97
102
|
isLowContrast: true,
|
98
103
|
title: stockOperation
|
@@ -115,7 +120,7 @@ const StockOperationSubmissionFormStep: React.FC<StockOperationSubmissionFormSte
|
|
115
120
|
}
|
116
121
|
})(); // Call handleSubmit to trigger validation and submission
|
117
122
|
return result; // Return the result after handleSubmit completes
|
118
|
-
}, [form, stockOperation, t, approvalRequired, isStockIssueOperation]);
|
123
|
+
}, [form, stockOperation, t, approvalRequired, isStockIssueOperation, dismissWorkspace]);
|
119
124
|
|
120
125
|
const handleComplete = useCallback(() => {
|
121
126
|
handleSave().then((operation) => {
|
@@ -141,13 +146,6 @@ const StockOperationSubmissionFormStep: React.FC<StockOperationSubmissionFormSte
|
|
141
146
|
? t('submitAndDispatch', 'Submit/Dispatch')
|
142
147
|
: t('submitAndComplete', 'Submit/Complete')}
|
143
148
|
</h4>
|
144
|
-
<div className={styles.btnSet}>
|
145
|
-
{typeof onPrevious === 'function' && (
|
146
|
-
<Button kind="secondary" onClick={onPrevious}>
|
147
|
-
Previous
|
148
|
-
</Button>
|
149
|
-
)}
|
150
|
-
</div>
|
151
149
|
</div>
|
152
150
|
|
153
151
|
<Column>
|
@@ -156,7 +154,7 @@ const StockOperationSubmissionFormStep: React.FC<StockOperationSubmissionFormSte
|
|
156
154
|
legendText={t('doesThisTransactionRequireApproval', 'Does the transaction require approval ?')}
|
157
155
|
onChange={handleRadioButtonChange}
|
158
156
|
readOnly={!editable}
|
159
|
-
valueSelected={approvalRequired === true}
|
157
|
+
valueSelected={approvalRequired === true ? true : approvalRequired === false ? false : null}
|
160
158
|
>
|
161
159
|
<RadioButton value={true} id="rbgApprovelRequired-true" labelText={t('yes', 'Yes')} />
|
162
160
|
<RadioButton value={false} id="rbgApprovelRequired-false" labelText={t('no', 'No')} />
|
@@ -169,6 +167,7 @@ const StockOperationSubmissionFormStep: React.FC<StockOperationSubmissionFormSte
|
|
169
167
|
{!operationTypePermision.requiresDispatchAcknowledgement && !approvalRequired && (
|
170
168
|
<Button
|
171
169
|
name="complete"
|
170
|
+
data-testid="complete-button"
|
172
171
|
type="button"
|
173
172
|
style={{ margin: '4px' }}
|
174
173
|
className="submitButton"
|
@@ -184,6 +183,7 @@ const StockOperationSubmissionFormStep: React.FC<StockOperationSubmissionFormSte
|
|
184
183
|
name="dispatch"
|
185
184
|
type="button"
|
186
185
|
style={{ margin: '4px' }}
|
186
|
+
data-testid="dipatch-button"
|
187
187
|
className="submitButton"
|
188
188
|
kind="primary"
|
189
189
|
onClick={handleDispatch}
|
@@ -229,6 +229,18 @@ const StockOperationSubmissionFormStep: React.FC<StockOperationSubmissionFormSte
|
|
229
229
|
</Button>
|
230
230
|
</Column>
|
231
231
|
)}
|
232
|
+
<div className={styles.btnSet}>
|
233
|
+
{typeof onNext === 'function' && (
|
234
|
+
<Button kind="tertiary" onClick={onNext} renderIcon={ArrowRight}>
|
235
|
+
{t('next', 'Next')}
|
236
|
+
</Button>
|
237
|
+
)}
|
238
|
+
{typeof onPrevious === 'function' && (
|
239
|
+
<Button kind="tertiary" onClick={onPrevious} renderIcon={ArrowLeft} hasIconOnly data-testid="previous-btn">
|
240
|
+
{/* {t('previous', 'Previous')} */}
|
241
|
+
</Button>
|
242
|
+
)}
|
243
|
+
</div>
|
232
244
|
</Stack>
|
233
245
|
);
|
234
246
|
};
|
@@ -1,10 +1,12 @@
|
|
1
|
-
import { showSnackbar } from '@openmrs/esm-framework';
|
1
|
+
import { parseDate, showSnackbar } from '@openmrs/esm-framework';
|
2
2
|
import React, { useEffect, useMemo } from 'react';
|
3
3
|
import { useFormContext } from 'react-hook-form';
|
4
4
|
import { useTranslation } from 'react-i18next';
|
5
5
|
import { OperationType, StockOperationType } from '../../core/api/types/stockOperation/StockOperationType';
|
6
|
-
import {
|
6
|
+
import { useStockOperationAndItems } from '../stock-operations.resource';
|
7
7
|
import { getStockOperationItemFormSchema, StockOperationItemDtoSchema } from '../validation-schema';
|
8
|
+
import { pick } from '../../core/utils/utils';
|
9
|
+
import { Loading } from '@carbon/react';
|
8
10
|
|
9
11
|
type StockIssueFormInitializerWithRelatedRequisitionOperationProps = {
|
10
12
|
stockRequisitionUuid: string;
|
@@ -16,11 +18,12 @@ const StockIssueFormInitializerWithRelatedRequisitionOperation: React.FC<
|
|
16
18
|
> = ({ stockRequisitionUuid, stockOperationType }) => {
|
17
19
|
const form = useFormContext<StockOperationItemDtoSchema>();
|
18
20
|
const { t } = useTranslation();
|
19
|
-
const { error, items: stockOperation, isLoading } =
|
21
|
+
const { error, items: stockOperation, isLoading } = useStockOperationAndItems(stockRequisitionUuid);
|
20
22
|
const { setValue } = form;
|
21
23
|
const stockOperationItemFormSchema = useMemo(() => {
|
22
24
|
return getStockOperationItemFormSchema(OperationType.STOCK_ISSUE_OPERATION_TYPE);
|
23
25
|
}, []);
|
26
|
+
|
24
27
|
const items = form.watch('stockOperationItems');
|
25
28
|
// initialize form values with requisition values for Stock issue operation type
|
26
29
|
useEffect(() => {
|
@@ -30,6 +33,17 @@ const StockIssueFormInitializerWithRelatedRequisitionOperation: React.FC<
|
|
30
33
|
setValue('destinationUuid', stockOperation.destinationUuid);
|
31
34
|
setValue('requisitionStockOperationUuid', stockRequisitionUuid);
|
32
35
|
setValue('operationTypeUuid', stockOperationType.uuid);
|
36
|
+
setValue('responsiblePersonUuid', stockOperation.responsiblePersonUuid);
|
37
|
+
setValue('responsiblePersonOther', stockOperation.responsiblePersonOther);
|
38
|
+
setValue(
|
39
|
+
'stockOperationItems',
|
40
|
+
(stockOperation?.stockOperationItems?.map((item) =>
|
41
|
+
pick(
|
42
|
+
{ ...item, expiration: item.expiration ? parseDate(item.expiration as any) : undefined },
|
43
|
+
stockOperationItemFormSchema.keyof().options,
|
44
|
+
),
|
45
|
+
) ?? []) as any,
|
46
|
+
);
|
33
47
|
}
|
34
48
|
}, [stockOperation, stockOperationItemFormSchema, setValue, items, stockOperationType, stockRequisitionUuid]);
|
35
49
|
|
@@ -49,6 +63,9 @@ const StockIssueFormInitializerWithRelatedRequisitionOperation: React.FC<
|
|
49
63
|
});
|
50
64
|
}
|
51
65
|
}, [stockRequisitionUuid, error, t]);
|
66
|
+
|
67
|
+
if (isLoading) return <Loading active description="Loading" />;
|
68
|
+
|
52
69
|
return <React.Fragment />;
|
53
70
|
};
|
54
71
|
|
package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.workspace.tsx
CHANGED
@@ -10,7 +10,7 @@ import {
|
|
10
10
|
TextInput,
|
11
11
|
} from '@carbon/react';
|
12
12
|
import { zodResolver } from '@hookform/resolvers/zod';
|
13
|
-
import { DefaultWorkspaceProps } from '@openmrs/esm-framework';
|
13
|
+
import { DefaultWorkspaceProps, useConfig } from '@openmrs/esm-framework';
|
14
14
|
import React, { useMemo } from 'react';
|
15
15
|
import { Controller, useForm } from 'react-hook-form';
|
16
16
|
import { useTranslation } from 'react-i18next';
|
@@ -24,15 +24,16 @@ import BatchNoSelector from '../input-components/batch-no-selector.component';
|
|
24
24
|
import QtyUomSelector from '../input-components/quantity-uom-selector.component';
|
25
25
|
import styles from './stock-item-form.scss';
|
26
26
|
import UniqueBatchNoEntryInput from '../input-components/unique-batch-no-entry-input.component';
|
27
|
+
import { ConfigObject } from '../../../config-schema';
|
27
28
|
|
28
29
|
export interface StockItemFormProps {
|
29
30
|
stockOperationType: StockOperationType;
|
30
31
|
stockOperationItem: BaseStockOperationItemFormData;
|
31
32
|
onSave?: (data: BaseStockOperationItemFormData) => void;
|
33
|
+
onBack?: () => void;
|
32
34
|
}
|
33
35
|
|
34
|
-
|
35
|
-
const StockItemForm: React.FC<Props> = ({ closeWorkspace, stockOperationType, stockOperationItem, onSave }) => {
|
36
|
+
const StockItemForm: React.FC<StockItemFormProps> = ({ stockOperationType, stockOperationItem, onSave, onBack }) => {
|
36
37
|
const operationType = useMemo(() => {
|
37
38
|
return operationFromString(stockOperationType.operationType);
|
38
39
|
}, [stockOperationType]);
|
@@ -40,6 +41,7 @@ const StockItemForm: React.FC<Props> = ({ closeWorkspace, stockOperationType, st
|
|
40
41
|
return getStockOperationItemFormSchema(operationType);
|
41
42
|
}, [operationType]);
|
42
43
|
const operationTypePermision = useOperationTypePermisions(stockOperationType);
|
44
|
+
const { useItemCommonNameAsDisplay } = useConfig<ConfigObject>();
|
43
45
|
|
44
46
|
const fields = formschema.keyof().options;
|
45
47
|
const form = useForm<z.infer<typeof formschema>>({
|
@@ -49,15 +51,25 @@ const StockItemForm: React.FC<Props> = ({ closeWorkspace, stockOperationType, st
|
|
49
51
|
});
|
50
52
|
const { t } = useTranslation();
|
51
53
|
const { item } = useStockItem(form.getValues('stockItemUuid'));
|
54
|
+
const commonName = useMemo(() => {
|
55
|
+
if (!useItemCommonNameAsDisplay) return;
|
56
|
+
const drugName = item?.drugName ? `(Drug name: ${item.drugName})` : undefined;
|
57
|
+
return `${item?.commonName || t('noCommonNameAvailable', 'No common name available') + (drugName ?? '')}`;
|
58
|
+
}, [item, useItemCommonNameAsDisplay, t]);
|
59
|
+
|
60
|
+
const drugName = useMemo(() => {
|
61
|
+
if (useItemCommonNameAsDisplay) return;
|
62
|
+
const commonName = item?.commonName ? `(Common name: ${item.commonName})` : undefined;
|
63
|
+
return `${item?.drugName || t('noDrugNameAvailable', 'No drug name available') + (commonName ?? '')}`;
|
64
|
+
}, [item, useItemCommonNameAsDisplay, t]);
|
65
|
+
|
52
66
|
const onSubmit = (data: z.infer<typeof formschema>) => {
|
53
67
|
onSave?.(data);
|
54
|
-
closeWorkspace();
|
55
|
-
// Implementation of adding or updating itsms in items table
|
56
68
|
};
|
57
69
|
return (
|
58
70
|
<Form onSubmit={form.handleSubmit(onSubmit)} className={styles.form}>
|
59
71
|
<Stack gap={4} className={styles.grid}>
|
60
|
-
|
72
|
+
<p className={styles.title}>{useItemCommonNameAsDisplay ? commonName : drugName}</p>
|
61
73
|
|
62
74
|
{(operationTypePermision.requiresActualBatchInfo || operationTypePermision.requiresBatchUuid) &&
|
63
75
|
fields.includes('batchNo' as any) && (
|
@@ -183,7 +195,7 @@ const StockItemForm: React.FC<Props> = ({ closeWorkspace, stockOperationType, st
|
|
183
195
|
</Stack>
|
184
196
|
|
185
197
|
<ButtonSet className={styles.buttonSet}>
|
186
|
-
<Button className={styles.button} kind="secondary" onClick={
|
198
|
+
<Button className={styles.button} kind="secondary" onClick={onBack}>
|
187
199
|
{t('discard', 'Discard')}
|
188
200
|
</Button>
|
189
201
|
<Button className={styles.button} kind="primary" type="submit" disabled={form.formState.isSubmitting}>
|