@openmrs/esm-stock-management-app 1.0.1-pre.777 → 1.0.1-pre.785

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.
Files changed (120) hide show
  1. package/__mocks__/index.ts +1 -0
  2. package/__mocks__/operation-type.mock.ts +532 -0
  3. package/dist/155.js +1 -0
  4. package/dist/155.js.map +1 -0
  5. package/dist/172.js +1 -1
  6. package/dist/20.js +1 -1
  7. package/dist/290.js +1 -1
  8. package/dist/493.js +2 -0
  9. package/dist/493.js.map +1 -0
  10. package/dist/606.js +1 -1
  11. package/dist/627.js +1 -1
  12. package/dist/{400.js → 914.js} +1 -1
  13. package/dist/914.js.map +1 -0
  14. package/dist/main.js +1 -1
  15. package/dist/main.js.map +1 -1
  16. package/dist/openmrs-esm-stock-management-app.js +1 -1
  17. package/dist/openmrs-esm-stock-management-app.js.buildmanifest.json +81 -57
  18. package/dist/openmrs-esm-stock-management-app.js.map +1 -1
  19. package/dist/routes.json +1 -1
  20. package/package.json +1 -1
  21. package/src/core/utils/utils.ts +29 -0
  22. package/src/index.ts +4 -0
  23. package/src/routes.json +9 -0
  24. package/src/stock-items/add-stock-item/transactions/printout/transactions-stockcard-printout.component.tsx +8 -12
  25. package/src/stock-items/add-stock-item/transactions/transactions.component.tsx +8 -12
  26. package/src/stock-items/stock-items.resource.ts +5 -5
  27. package/src/stock-lookups/stock-lookups.resource.ts +2 -2
  28. package/src/stock-operations/edit-stock-operation/edit-stock-operation-action-menu.component.tsx +41 -16
  29. package/src/stock-operations/{add-stock-operation/received-items.component.tsx → received-items.component.tsx} +1 -1
  30. package/src/stock-operations/stock-operation-reference.component.tsx +64 -0
  31. package/src/stock-operations/stock-operation-status/stock-operation-status-row.tsx +77 -0
  32. package/src/stock-operations/stock-operation-status/stock-operation-status.scss +32 -0
  33. package/src/stock-operations/stock-operation-status/stock-operation-status.tsx +45 -0
  34. package/src/stock-operations/stock-operation-types-selector/stock-operation-types-selector.component.tsx +30 -29
  35. package/src/stock-operations/stock-operation.utils.tsx +16 -79
  36. package/src/stock-operations/stock-operations-dialog/stock-operations-issue-stock-button.component.tsx +27 -39
  37. package/src/stock-operations/stock-operations-dialog/stock-operations-print-button.component.tsx +51 -59
  38. package/src/stock-operations/{stock-item-selector/stock-item-selector.resource.tsx → stock-operations-forms/hooks/useFilterableStockItems.ts} +4 -4
  39. package/src/stock-operations/stock-operations-forms/hooks/useFilteredOperationTypesByRoles.ts +30 -0
  40. package/src/stock-operations/stock-operations-forms/hooks/useOperationTypePermisions.ts +29 -0
  41. package/src/stock-operations/stock-operations-forms/hooks/useParties.ts +73 -0
  42. package/src/stock-operations/{users-selector/users-selector.resource.tsx → stock-operations-forms/hooks/useSearchUser.ts} +9 -7
  43. package/src/stock-operations/{batch-no-selector/batch-no-selector.resource.tsx → stock-operations-forms/hooks/useStockItemBatchNumbers.ts} +3 -3
  44. package/src/stock-operations/stock-operations-forms/hooks/useStockOperationLinks.ts +20 -0
  45. package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.component.tsx +72 -0
  46. package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.test.tsx +90 -0
  47. package/src/stock-operations/{add-stock-operation/stock-item-search/stock-item-search.scss → stock-operations-forms/input-components/input-components-styles.scss} +2 -2
  48. package/src/stock-operations/stock-operations-forms/input-components/qty-uim-selector.test.tsx +157 -0
  49. package/src/stock-operations/stock-operations-forms/input-components/quantity-uom-selector.component.tsx +53 -0
  50. package/src/stock-operations/stock-operations-forms/input-components/stock-item-search.component.tsx +56 -0
  51. package/src/stock-operations/stock-operations-forms/input-components/stock-operation-reason-selector.component.tsx +59 -0
  52. package/src/stock-operations/stock-operations-forms/input-components/stock-operation-reason-selector.test.tsx +216 -0
  53. package/src/stock-operations/stock-operations-forms/input-components/unique-batch-no-entry-input.component.tsx +59 -0
  54. package/src/stock-operations/stock-operations-forms/input-components/user-selector.test.tsx +110 -0
  55. package/src/stock-operations/stock-operations-forms/input-components/users-selector.component.tsx +111 -0
  56. package/src/stock-operations/stock-operations-forms/step1.test.tsx +303 -0
  57. package/src/stock-operations/stock-operations-forms/step2.test.tsx +250 -0
  58. package/src/stock-operations/stock-operations-forms/step3.test.tsx +223 -0
  59. package/src/stock-operations/stock-operations-forms/steps/base-operation-details-form-step.tsx +241 -0
  60. package/src/stock-operations/stock-operations-forms/steps/quantity-uom-cell.component.tsx +33 -0
  61. package/src/stock-operations/stock-operations-forms/steps/stock-availability-cell.component.tsx +51 -0
  62. package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-batch-no-cell.component.tsx +40 -0
  63. package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-cell.component.tsx +38 -0
  64. package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-expiry-cell.component.tsx +41 -0
  65. package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.component.tsx +281 -0
  66. package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.scc.scss +64 -0
  67. package/src/stock-operations/stock-operations-forms/steps/stock-operation-submission-form-step.component.tsx +236 -0
  68. package/src/stock-operations/stock-operations-forms/stock-issue-form-initializer-with-related-requisition-operation.component.tsx +55 -0
  69. package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.scss +41 -0
  70. package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.workspace.tsx +197 -0
  71. package/src/stock-operations/stock-operations-forms/stock-operation-form-header.component.tsx +166 -0
  72. package/src/stock-operations/stock-operations-forms/stock-operation-form.component.tsx +200 -0
  73. package/src/stock-operations/stock-operations-forms/stock-operation-form.scss +111 -0
  74. package/src/stock-operations/stock-operations-forms/stock-operation-related-link.component.tsx +45 -0
  75. package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stepper.scss +41 -0
  76. package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stock-operation-stepper.component.tsx +52 -0
  77. package/src/stock-operations/stock-operations-forms/stock-operations-form-utils.ts +32 -0
  78. package/src/stock-operations/stock-operations-table.component.tsx +20 -56
  79. package/src/stock-operations/stock-operations.resource.ts +16 -13
  80. package/src/stock-operations/validation-schema.ts +72 -14
  81. package/dist/400.js.map +0 -1
  82. package/dist/766.js +0 -2
  83. package/dist/766.js.map +0 -1
  84. package/src/stock-operations/add-stock-operation/add-stock-operation.component.tsx +0 -349
  85. package/src/stock-operations/add-stock-operation/add-stock-operation.resource.tsx +0 -27
  86. package/src/stock-operations/add-stock-operation/add-stock-operation.scss +0 -60
  87. package/src/stock-operations/add-stock-operation/add-stock-operation.test.tsx +0 -192
  88. package/src/stock-operations/add-stock-operation/add-stock-operation.utils.tsx +0 -152
  89. package/src/stock-operations/add-stock-operation/add-stock-utils.ts +0 -103
  90. package/src/stock-operations/add-stock-operation/base-operation-details.component.tsx +0 -439
  91. package/src/stock-operations/add-stock-operation/base-operation-details.scss +0 -30
  92. package/src/stock-operations/add-stock-operation/stock-item-search/stock-item-search.component.tsx +0 -70
  93. package/src/stock-operations/add-stock-operation/stock-items-addition-row.component.tsx +0 -360
  94. package/src/stock-operations/add-stock-operation/stock-items-addition-row.resource.tsx +0 -0
  95. package/src/stock-operations/add-stock-operation/stock-items-addition-row.scss +0 -12
  96. package/src/stock-operations/add-stock-operation/stock-items-addition-row.test.tsx +0 -10
  97. package/src/stock-operations/add-stock-operation/stock-items-addition.component.scss +0 -17
  98. package/src/stock-operations/add-stock-operation/stock-items-addition.component.tsx +0 -254
  99. package/src/stock-operations/add-stock-operation/stock-operation-context/useStockOperationContext.tsx +0 -16
  100. package/src/stock-operations/add-stock-operation/stock-operation-reference.component.tsx +0 -39
  101. package/src/stock-operations/add-stock-operation/stock-operation-related-link.component.tsx +0 -38
  102. package/src/stock-operations/add-stock-operation/stock-operation-status.component.tsx +0 -170
  103. package/src/stock-operations/add-stock-operation/stock-operation-submission.component.tsx +0 -189
  104. package/src/stock-operations/add-stock-operation/stock-operation-submission.test.tsx +0 -138
  105. package/src/stock-operations/add-stock-operation/types.ts +0 -55
  106. package/src/stock-operations/add-stock-operation/validationSchema.ts +0 -54
  107. package/src/stock-operations/batch-no-selector/batch-no-selector.component.tsx +0 -114
  108. package/src/stock-operations/batch-no-selector/batch-no-selector.scss +0 -0
  109. package/src/stock-operations/batch-no-selector/batch-no-selector.test.tsx +0 -101
  110. package/src/stock-operations/party-selector/party-selector.component.tsx +0 -59
  111. package/src/stock-operations/qty-uom-selector/qty-uom-selector.component.tsx +0 -65
  112. package/src/stock-operations/qty-uom-selector/qty-uom-selector.resource.tsx +0 -0
  113. package/src/stock-operations/qty-uom-selector/qty-uom-selector.scss +0 -0
  114. package/src/stock-operations/qty-uom-selector/qty-uom-selector.test.tsx +0 -10
  115. package/src/stock-operations/stock-item-selector/stock-item-selector.component.tsx +0 -69
  116. package/src/stock-operations/stock-item-selector/stock-item-selector.scss +0 -0
  117. package/src/stock-operations/stock-item-selector/stock-item-selector.test.tsx +0 -10
  118. package/src/stock-operations/stock-operation-reason-selector/stock-operation-reason-selector.component.tsx +0 -62
  119. package/src/stock-operations/users-selector/users-selector.component.tsx +0 -75
  120. /package/dist/{766.js.LICENSE.txt → 493.js.LICENSE.txt} +0 -0
@@ -0,0 +1,45 @@
1
+ import React, { useCallback } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { useStockOperationTypes } from '../../stock-lookups/stock-lookups.resource';
4
+ import { launchStockoperationAddOrEditDialog } from '../stock-operation.utils';
5
+ import { useStockOperationAndItems } from '../stock-operations.resource';
6
+
7
+ interface StockOperationRelatedLinkProps {
8
+ stockOperationUuid: string;
9
+ operationNumber: string;
10
+ }
11
+
12
+ const StockOperationRelatedLink: React.FC<StockOperationRelatedLinkProps> = ({
13
+ stockOperationUuid,
14
+ operationNumber,
15
+ }) => {
16
+ const { error, isLoading, types } = useStockOperationTypes();
17
+ const {
18
+ error: stockOperationError,
19
+ isLoading: isStockOperationLoading,
20
+ items: stockOperation,
21
+ } = useStockOperationAndItems(stockOperationUuid);
22
+ const { t } = useTranslation();
23
+
24
+ const handleEdit = useCallback(() => {
25
+ const operationType = types?.results?.find((op) => op?.uuid === stockOperation?.operationTypeUuid);
26
+ if (!operationType) {
27
+ return;
28
+ }
29
+ launchStockoperationAddOrEditDialog(
30
+ t,
31
+ operationType,
32
+ stockOperation,
33
+ stockOperation?.requisitionStockOperationUuid,
34
+ );
35
+ }, [types, stockOperation, t]);
36
+
37
+ if (isLoading || error || stockOperationError || isStockOperationLoading) return null;
38
+ return (
39
+ <span onClick={handleEdit} style={{ cursor: 'pointer', textDecoration: 'underline' }}>
40
+ {operationNumber}
41
+ </span>
42
+ );
43
+ };
44
+
45
+ export default StockOperationRelatedLink;
@@ -0,0 +1,41 @@
1
+ @use '@carbon/layout';
2
+ @use '@carbon/type';
3
+ @use '@carbon/colors';
4
+
5
+ .layer {
6
+ display: flex;
7
+ flex-direction: column;
8
+ gap: layout.$spacing-05;
9
+ padding: layout.$spacing-05;
10
+ }
11
+
12
+ .stepperContainer {
13
+ display: flex;
14
+ gap: layout.$spacing-03;
15
+ flex: 1;
16
+ align-items: center;
17
+ width: 100%;
18
+ }
19
+
20
+ .stepperItem {
21
+ flex: 1;
22
+ height: 100%;
23
+ display: flex;
24
+ gap: layout.$spacing-03;
25
+ align-items: center;
26
+ padding: layout.$spacing-03;
27
+ border-top: layout.$spacing-01 solid colors.$gray-30;
28
+ }
29
+
30
+ .stepperItemActive {
31
+ border-top: layout.$spacing-02 solid var(--brand-03);
32
+ }
33
+
34
+ .subtTitle {
35
+ color: colors.$gray-50;
36
+ @include type.type-style('body-01');
37
+ }
38
+
39
+ .title {
40
+ @include type.type-style('heading-02');
41
+ }
@@ -0,0 +1,52 @@
1
+ import { Layer } from '@carbon/react';
2
+ import React from 'react';
3
+ import styles from './stepper.scss';
4
+ export type Step = {
5
+ title: string;
6
+ subTitle?: string;
7
+ icon?: React.ReactNode;
8
+ component: React.ReactElement;
9
+ disabled?: boolean;
10
+ };
11
+
12
+ type StockOperationStepperProps = {
13
+ steps: Step[];
14
+ title?: string;
15
+ hasContainer?: boolean;
16
+ selectedIndex?: number;
17
+ onChange?: (index: number) => void;
18
+ };
19
+ const StockOperationStepper: React.FC<StockOperationStepperProps> = ({
20
+ steps,
21
+ hasContainer,
22
+ onChange,
23
+ selectedIndex,
24
+ title,
25
+ }) => {
26
+ return (
27
+ <Layer className={styles.layer}>
28
+ <ol className={styles.stepperContainer}>
29
+ {steps.map(({ title, subTitle, icon, disabled }, index) => {
30
+ const active = selectedIndex >= index;
31
+ return (
32
+ <li
33
+ role="button"
34
+ className={`${styles.stepperItem} ${active ? styles.stepperItemActive : ''}`}
35
+ key={index}
36
+ onClick={!disabled ? () => onChange?.(index) : undefined}
37
+ >
38
+ {icon}
39
+ <div>
40
+ <p className={styles.title}>{title}</p>
41
+ <p className={styles.subtTitle}>{subTitle}</p>
42
+ </div>
43
+ </li>
44
+ );
45
+ })}
46
+ </ol>
47
+ <Layer>{steps[selectedIndex].component}</Layer>
48
+ </Layer>
49
+ );
50
+ };
51
+
52
+ export default StockOperationStepper;
@@ -0,0 +1,32 @@
1
+ import { StockOperationDTO } from '../../core/api/types/stockOperation/StockOperationDTO';
2
+ import { OperationType } from '../../core/api/types/stockOperation/StockOperationType';
3
+
4
+ export function mapIssueStockLocations(stockOperation) {
5
+ /** Since we are using requisition information to issue stock,
6
+ please note that the locations will be inverted: the destination listed on the requisition will become the issuing location.
7
+ */
8
+ const { sourceUuid, sourceName, destinationUuid, destinationName } = stockOperation;
9
+ return {
10
+ ...stockOperation,
11
+ sourceUuid: destinationUuid,
12
+ sourceName: destinationName,
13
+ destinationUuid: sourceUuid,
14
+ destinationName: sourceName,
15
+ };
16
+ }
17
+
18
+ export const getStockOperationLocationByOperationType = (
19
+ operationType: OperationType,
20
+ stockOperation?: StockOperationDTO,
21
+ ) => {
22
+ if (operationType === OperationType.STOCK_ISSUE_OPERATION_TYPE)
23
+ return {
24
+ sourceUuid: stockOperation?.destinationUuid ?? '',
25
+ destinationUuid: stockOperation?.sourceUuid ?? '',
26
+ };
27
+
28
+ return {
29
+ sourceUuid: stockOperation?.sourceUuid ?? '',
30
+ destinationUuid: stockOperation?.destinationUuid ?? '',
31
+ };
32
+ };
@@ -1,10 +1,9 @@
1
- import React, { useCallback, useMemo, useState } from 'react';
2
- import { useStockOperationPages } from './stock-operations-table.resource';
3
- import { ResourceRepresentation } from '../core/api/api';
4
1
  import {
5
2
  DataTable,
6
- TabPanel,
7
3
  DataTableSkeleton,
4
+ DatePicker,
5
+ DatePickerInput,
6
+ InlineLoading,
8
7
  Pagination,
9
8
  Table,
10
9
  TableBody,
@@ -17,30 +16,29 @@ import {
17
16
  TableHeader,
18
17
  TableRow,
19
18
  TableToolbar,
19
+ TableToolbarAction,
20
20
  TableToolbarContent,
21
+ TableToolbarMenu,
21
22
  TableToolbarSearch,
23
+ TabPanel,
22
24
  Tile,
23
- DatePickerInput,
24
- DatePicker,
25
- TableToolbarMenu,
26
- TableToolbarAction,
27
- InlineLoading,
28
25
  } from '@carbon/react';
29
26
  import { ArrowRight } from '@carbon/react/icons';
30
- import { formatDisplayDate } from '../core/utils/datetimeUtils';
31
27
  import { isDesktop, restBaseUrl } from '@openmrs/esm-framework';
32
- import StockOperationTypesSelector from './stock-operation-types-selector/stock-operation-types-selector.component';
33
- import { launchAddOrEditDialog } from './stock-operation.utils';
34
- import { initialStockOperationValue } from '../core/utils/utils';
35
- import { StockOperationType } from '../core/api/types/stockOperation/StockOperationType';
28
+ import React, { useCallback, useMemo, useState } from 'react';
36
29
  import { useTranslation } from 'react-i18next';
37
- import EditStockOperationActionMenu from './edit-stock-operation/edit-stock-operation-action-menu.component';
38
- import StockOperationsFilters from './stock-operations-filters.component';
39
30
  import { DATE_PICKER_CONTROL_FORMAT, DATE_PICKER_FORMAT, StockFilters } from '../constants';
31
+ import { ResourceRepresentation } from '../core/api/api';
32
+ import { StockOperationType } from '../core/api/types/stockOperation/StockOperationType';
33
+ import { formatDisplayDate } from '../core/utils/datetimeUtils';
40
34
  import { handleMutate } from '../utils';
35
+ import EditStockOperationActionMenu from './edit-stock-operation/edit-stock-operation-action-menu.component';
36
+ import StockOperationTypesSelector from './stock-operation-types-selector/stock-operation-types-selector.component';
37
+ import StockOperationsFilters from './stock-operations-filters.component';
38
+ import { useStockOperationPages } from './stock-operations-table.resource';
41
39
 
42
40
  import styles from './stock-operations-table.scss';
43
- import StockOperationStatus from './add-stock-operation/stock-operation-status.component';
41
+ import StockOperationStatusRow from './stock-operation-status/stock-operation-status-row';
44
42
 
45
43
  interface StockOperationsTableProps {
46
44
  status?: string;
@@ -98,8 +96,6 @@ const StockOperations: React.FC<StockOperationsTableProps> = () => {
98
96
  const filterApplied =
99
97
  selectedFromDate || selectedToDate || selectedSources.length || selectedStatus.length || selectedOperations.length;
100
98
 
101
- const [operations, setOperations] = useState<StockOperationType[]>([]);
102
-
103
99
  const handleOnFilterChange = useCallback((selectedItems, filterType) => {
104
100
  if (filterType === StockFilters.SOURCES) {
105
101
  setSelectedSources(selectedItems);
@@ -125,13 +121,6 @@ const StockOperations: React.FC<StockOperationsTableProps> = () => {
125
121
  }
126
122
  };
127
123
 
128
- const handleEditClick = useCallback(
129
- (stockOperation, isEditing) => {
130
- launchAddOrEditDialog(t, stockOperation, isEditing, operation, operations, false);
131
- },
132
- [t, operation, operations],
133
- );
134
-
135
124
  const tableRows = useMemo(() => {
136
125
  return items?.map((stockOperation, index) => {
137
126
  const commonNames = stockOperation?.stockOperationItems
@@ -144,15 +133,7 @@ const StockOperations: React.FC<StockOperationsTableProps> = () => {
144
133
  key: `key-${stockOperation?.uuid}`,
145
134
  operationTypeName: `${stockOperation?.operationTypeName}`,
146
135
  operationNumber: (
147
- <EditStockOperationActionMenu
148
- model={stockOperation}
149
- operations={operations}
150
- operationUuid={operation.uuid}
151
- operationNumber={''}
152
- onEdit={() => handleEditClick(stockOperation, true)}
153
- showIcon={false}
154
- showprops={true}
155
- />
136
+ <EditStockOperationActionMenu stockOperation={stockOperation} showIcon={false} showprops={true} />
156
137
  ),
157
138
  stockOperationItems: commonNames,
158
139
  status: `${stockOperation?.status}`,
@@ -169,20 +150,10 @@ const StockOperations: React.FC<StockOperationsTableProps> = () => {
169
150
  stockOperation?.responsiblePersonFamilyName ?? stockOperation?.responsiblePersonOther ?? ''
170
151
  } ${stockOperation?.responsiblePersonGivenName ?? ''}`,
171
152
  operationDate: formatDisplayDate(stockOperation?.operationDate),
172
- actions: (
173
- <EditStockOperationActionMenu
174
- model={stockOperation}
175
- operations={operations}
176
- operationUuid={operation.uuid}
177
- operationNumber={''}
178
- onEdit={() => handleEditClick(stockOperation, true)}
179
- showIcon={true}
180
- showprops={false}
181
- />
182
- ),
153
+ actions: <EditStockOperationActionMenu stockOperation={stockOperation} showIcon={true} showprops={false} />,
183
154
  };
184
155
  });
185
- }, [items, operations, handleEditClick, operation]);
156
+ }, [items]);
186
157
 
187
158
  if (isLoading && !filterApplied) {
188
159
  return (
@@ -243,14 +214,7 @@ const StockOperations: React.FC<StockOperationsTableProps> = () => {
243
214
  <TableToolbarAction onClick={handleRefresh}>Refresh</TableToolbarAction>
244
215
  </TableToolbarMenu>
245
216
 
246
- <StockOperationTypesSelector
247
- onOperationTypeSelected={(operation) => {
248
- launchAddOrEditDialog(t, initialStockOperationValue(), false, operation, operations, false);
249
- }}
250
- onOperationLoaded={(ops) => {
251
- setOperations(ops);
252
- }}
253
- />
217
+ <StockOperationTypesSelector />
254
218
  </TableToolbarContent>
255
219
  </TableToolbar>
256
220
  <Table {...getTableProps()}>
@@ -289,7 +253,7 @@ const StockOperations: React.FC<StockOperationsTableProps> = () => {
289
253
  </TableExpandRow>
290
254
  {row.isExpanded ? (
291
255
  <TableExpandedRow colSpan={headers.length + 2}>
292
- <StockOperationStatus model={items[index]} />
256
+ <StockOperationStatusRow stockOperation={items[index]} />
293
257
  </TableExpandedRow>
294
258
  ) : (
295
259
  <TableExpandedRow className={styles.hiddenRow} colSpan={headers.length + 2} />
@@ -2,9 +2,12 @@ import { FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework
2
2
  import useSWR from 'swr';
3
3
  import { ResourceFilterCriteria, toQueryParams } from '../core/api/api';
4
4
  import { PageableResult } from '../core/api/types/PageableResult';
5
- import { StockOperationDTO } from '../core/api/types/stockOperation/StockOperationDTO';
6
- import { StopOperationAction } from '../core/api/types/stockOperation/StockOperationAction';
7
5
  import { InventoryGroupBy } from '../core/api/types/stockItem/StockItem';
6
+ import { StopOperationAction } from '../core/api/types/stockOperation/StockOperationAction';
7
+ import { StockOperationDTO } from '../core/api/types/stockOperation/StockOperationDTO';
8
+ import { StockOperationItemDtoSchema } from './validation-schema';
9
+ import { StockOperationItemCost } from '../core/api/types/stockOperation/StockOperationItemCost';
10
+ import { StockItemInventory } from '../core/api/types/stockItem/StockItemInventory';
8
11
 
9
12
  export interface StockOperationFilter extends ResourceFilterCriteria {
10
13
  status?: string | null | undefined;
@@ -63,7 +66,7 @@ export function useStockOperation(id: string | null) {
63
66
  const apiUrl = id ? `${restBaseUrl}/stockmanagement/stockoperation/${id}` : null;
64
67
  const { data, error, isLoading } = useSWR<{ data: StockOperationDTO }, Error>(apiUrl, apiUrl ? openmrsFetch : null);
65
68
  return {
66
- items: data?.data || {},
69
+ items: data?.data,
67
70
  isLoading,
68
71
  error,
69
72
  };
@@ -83,7 +86,7 @@ export function useStockOperationAndItems(id: string) {
83
86
  const apiUrl = `${restBaseUrl}/stockmanagement/stockoperation/${id}?v=full`;
84
87
  const { data, error, isLoading } = useSWR<{ data: StockOperationDTO }, Error>(apiUrl, openmrsFetch);
85
88
  return {
86
- items: data.data ? data.data : {},
89
+ items: data?.data,
87
90
  isLoading,
88
91
  error,
89
92
  };
@@ -124,30 +127,30 @@ export function deleteStockOperationItem(id: string) {
124
127
  }
125
128
 
126
129
  // createStockOperation
127
- export function createStockOperation(item: StockOperationDTO) {
130
+ export function createStockOperation(data: StockOperationItemDtoSchema) {
128
131
  const apiUrl = `${restBaseUrl}/stockmanagement/stockoperation`;
129
132
  const abortController = new AbortController();
130
- return openmrsFetch(apiUrl, {
133
+ return openmrsFetch<StockOperationDTO>(apiUrl, {
131
134
  method: 'POST',
132
135
  headers: {
133
136
  'Content-Type': 'application/json',
134
137
  },
135
138
  signal: abortController.signal,
136
- body: item,
139
+ body: data,
137
140
  });
138
141
  }
139
142
 
140
143
  // updateStockOperation
141
- export function updateStockOperation(item: StockOperationDTO) {
142
- const apiUrl = `${restBaseUrl}/stockmanagement/stockoperation/${item.uuid}`;
144
+ export function updateStockOperation(stockOperation: StockOperationDTO, data: StockOperationItemDtoSchema) {
145
+ const apiUrl = `${restBaseUrl}/stockmanagement/stockoperation/${stockOperation.uuid}`;
143
146
  const abortController = new AbortController();
144
- return openmrsFetch(apiUrl, {
147
+ return openmrsFetch<StockOperationDTO>(apiUrl, {
145
148
  method: 'POST',
146
149
  headers: {
147
150
  'Content-Type': 'application/json',
148
151
  },
149
152
  signal: abortController.signal,
150
- body: item,
153
+ body: data,
151
154
  });
152
155
  }
153
156
 
@@ -183,7 +186,7 @@ export function updateStockOperationBatchNumbers(item: StockOperationDTO, uuid:
183
186
  export function getStockOperationItemsCost(filter: StockOperationFilter) {
184
187
  const apiUrl = `${restBaseUrl}/stockmanagement/stockoperationitemcost?v=default&stockOperationUuid=${filter}`;
185
188
  const abortController = new AbortController();
186
- return openmrsFetch(apiUrl, {
189
+ return openmrsFetch<{ results: Array<StockOperationItemCost> }>(apiUrl, {
187
190
  method: 'GET',
188
191
  headers: {
189
192
  'Content-Type': 'application/json',
@@ -195,7 +198,7 @@ export function getStockOperationItemsCost(filter: StockOperationFilter) {
195
198
  export function getStockItemInventory(filter: StockItemInventoryFilter) {
196
199
  const apiUrl = `${restBaseUrl}/stockmanagement/stockiteminventory${toQueryParams(filter)}&v=default`;
197
200
  const abortController = new AbortController();
198
- return openmrsFetch(apiUrl, {
201
+ return openmrsFetch<{ results: Array<StockItemInventory> }>(apiUrl, {
199
202
  method: 'GET',
200
203
  headers: {
201
204
  'Content-Type': 'application/json',
@@ -114,9 +114,49 @@ export const stockOperationSchema = z.object({
114
114
  dispatchedByGivenName: z.string().nullish(),
115
115
  dispatchedByFamilyName: z.string().nullish(),
116
116
  dispatchedDate: z.coerce.date(),
117
- requisitionStockOperationUuid: z.string(),
117
+ requisitionStockOperationUuid: z.string().uuid().nullish(),
118
+ });
119
+ export const baseStockOperationItemSchema = z.object({
120
+ uuid: z.string().min(1, 'Required'),
121
+ stockItemUuid: z.string().min(1, { message: 'Required' }),
122
+ stockItemPackagingUOMUuid: z.string().min(1, { message: 'Required' }),
123
+ batchNo: z.string().min(1, { message: 'Required' }),
124
+ stockBatchUuid: z.string().optional(),
125
+ expiration: z.coerce.date({ required_error: 'Required' }),
126
+ quantity: z.coerce.number().min(1, { message: 'Required' }),
127
+ purchasePrice: z.coerce.number().nullish(),
128
+ hasExpiration: z.boolean().nullish(),
118
129
  });
119
130
 
131
+ export type BaseStockOperationItemFormData = z.infer<typeof baseStockOperationItemSchema>;
132
+
133
+ export const getStockOperationItemFormSchema = (operationType: OperationType) => {
134
+ switch (operationType) {
135
+ case OperationType.RECEIPT_OPERATION_TYPE:
136
+ case OperationType.OPENING_STOCK_OPERATION_TYPE:
137
+ return baseStockOperationItemSchema.omit({ stockBatchUuid: true });
138
+ case OperationType.REQUISITION_OPERATION_TYPE:
139
+ return baseStockOperationItemSchema.omit({
140
+ batchNo: true,
141
+ stockBatchUuid: true,
142
+ expiration: true,
143
+ purchasePrice: true,
144
+ });
145
+ case OperationType.ADJUSTMENT_OPERATION_TYPE:
146
+ case OperationType.DISPOSED_OPERATION_TYPE:
147
+ case OperationType.RETURN_OPERATION_TYPE:
148
+ case OperationType.STOCK_ISSUE_OPERATION_TYPE:
149
+ case OperationType.STOCK_TAKE_OPERATION_TYPE:
150
+ case OperationType.TRANSFER_OUT_OPERATION_TYPE:
151
+ return baseStockOperationItemSchema.omit({
152
+ batchNo: true,
153
+ expiration: true,
154
+ purchasePrice: true,
155
+ });
156
+ default:
157
+ return baseStockOperationItemSchema;
158
+ }
159
+ };
120
160
  export const stockOperationItemDtoSchema = z.object({
121
161
  operationDate: z.coerce.date(),
122
162
  sourceUuid: z.string({ required_error: 'Location Required' }).min(1, {
@@ -137,47 +177,65 @@ export const stockOperationItemDtoSchema = z.object({
137
177
  }),
138
178
  responsiblePersonOther: z.string().nullish(),
139
179
  remarks: z.string().nullish(),
180
+ operationTypeUuid: z.string().min(1, 'Operation type required').uuid('Invalid operation type'),
181
+ stockOperationItems: baseStockOperationItemSchema.array().nonempty('You must add atleast one stock item'),
182
+ requisitionStockOperationUuid: z.string().uuid().optional(), // Suplied only for stock issue operation
140
183
  });
141
184
 
142
185
  export type StockOperationItemDtoSchema = z.infer<typeof stockOperationItemDtoSchema>;
143
186
 
144
187
  export type StockOperationFormData = z.infer<typeof stockOperationSchema>;
145
188
 
146
- export const operationSchema = (operation: OperationType): z.Schema => {
189
+ export const getStockOperationFormSchema = (operation: OperationType): z.Schema => {
147
190
  switch (operation) {
148
191
  case OperationType.OPENING_STOCK_OPERATION_TYPE:
149
- return stockOperationItemDtoSchema.omit({
150
- destinationUuid: true,
151
- reasonUuid: true,
152
- });
192
+ return stockOperationItemDtoSchema
193
+ .omit({
194
+ destinationUuid: true,
195
+ reasonUuid: true,
196
+ })
197
+ .merge(
198
+ z.object({
199
+ stockOperationItems: getStockOperationItemFormSchema(operation)
200
+ .array()
201
+ .nonempty('You must add atleast one stock item'),
202
+ }),
203
+ );
153
204
  case OperationType.STOCK_TAKE_OPERATION_TYPE:
154
205
  case OperationType.ADJUSTMENT_OPERATION_TYPE:
155
206
  case OperationType.DISPOSED_OPERATION_TYPE:
156
- return stockOperationItemDtoSchema.omit({ destinationUuid: true });
207
+ return stockOperationItemDtoSchema.omit({ destinationUuid: true }).merge(
208
+ z.object({
209
+ stockOperationItems: getStockOperationItemFormSchema(operation)
210
+ .array()
211
+ .nonempty('You must add atleast one stock item'),
212
+ }),
213
+ );
157
214
  case OperationType.TRANSFER_OUT_OPERATION_TYPE:
158
215
  case OperationType.STOCK_ISSUE_OPERATION_TYPE:
159
216
  return stockOperationItemDtoSchema.omit({ reasonUuid: true }).merge(
160
217
  z.object({
218
+ // Merged to overid initial one with error message having location instead of destination
161
219
  destinationUuid: z.string({ required_error: 'Destination Required' }).min(1, {
162
220
  message: 'Destination Required',
163
221
  }),
222
+ stockOperationItems: getStockOperationItemFormSchema(operation)
223
+ .array()
224
+ .nonempty('You must add atleast one stock item'),
164
225
  }),
165
226
  );
166
227
  case OperationType.RETURN_OPERATION_TYPE:
167
228
  case OperationType.REQUISITION_OPERATION_TYPE:
168
- return stockOperationItemDtoSchema.omit({ reasonUuid: true }).merge(
169
- z.object({
170
- sourceUuid: z.string({ required_error: 'Source Required' }).min(1, {
171
- message: 'Source Required',
172
- }),
173
- }),
174
- );
175
229
  case OperationType.RECEIPT_OPERATION_TYPE:
176
230
  return stockOperationItemDtoSchema.omit({ reasonUuid: true }).merge(
177
231
  z.object({
232
+ // Merged to overid initial one with error message having location instead of source
178
233
  sourceUuid: z.string({ required_error: 'Source Required' }).min(1, {
179
234
  message: 'Source Required',
180
235
  }),
236
+ stockOperationItems: getStockOperationItemFormSchema(operation)
237
+ .array()
238
+ .nonempty('You must add atleast one stock item'),
181
239
  }),
182
240
  );
183
241
  }