@openmrs/esm-stock-management-app 1.0.1-pre.783 → 1.0.1-pre.788

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 (128) 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/922.js +1 -0
  13. package/dist/922.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 +75 -51
  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/config-schema.ts +6 -0
  22. package/src/core/utils/utils.ts +29 -0
  23. package/src/index.ts +4 -0
  24. package/src/routes.json +9 -0
  25. package/src/stock-items/add-stock-item/transactions/printout/transactions-stockcard-printout.component.tsx +8 -12
  26. package/src/stock-items/add-stock-item/transactions/transactions.component.tsx +8 -12
  27. package/src/stock-items/stock-items.resource.ts +5 -5
  28. package/src/stock-lookups/stock-lookups.resource.ts +2 -2
  29. package/src/stock-operations/add-stock-operation/stock-operations-expanded-row/stock-items-table.scss +34 -0
  30. package/src/stock-operations/add-stock-operation/stock-operations-expanded-row/stock-items-table.tsx +111 -0
  31. package/src/stock-operations/add-stock-operation/stock-operations-expanded-row/stock-operation-expanded-row.component.tsx +87 -0
  32. package/src/stock-operations/add-stock-operation/stock-operations-expanded-row/stock-operation-expanded-row.scss +31 -0
  33. package/src/stock-operations/add-stock-operation/stock-operations-expanded-row/stock-operations-status.tsx +45 -0
  34. package/src/stock-operations/edit-stock-operation/edit-stock-operation-action-menu.component.tsx +41 -16
  35. package/src/stock-operations/stock-operation-reference.component.tsx +64 -0
  36. package/src/stock-operations/stock-operation-status/stock-operation-status-row.tsx +77 -0
  37. package/src/stock-operations/stock-operation-status/stock-operation-status.scss +32 -0
  38. package/src/stock-operations/stock-operation-status/stock-operation-status.tsx +45 -0
  39. package/src/stock-operations/stock-operation-types-selector/stock-operation-types-selector.component.tsx +30 -29
  40. package/src/stock-operations/stock-operation.utils.tsx +16 -79
  41. package/src/stock-operations/stock-operations-dialog/stock-operations-issue-stock-button.component.tsx +27 -39
  42. package/src/stock-operations/stock-operations-dialog/stock-operations-print-button.component.tsx +51 -59
  43. package/src/stock-operations/{stock-item-selector/stock-item-selector.resource.tsx → stock-operations-forms/hooks/useFilterableStockItems.ts} +4 -4
  44. package/src/stock-operations/stock-operations-forms/hooks/useFilteredOperationTypesByRoles.ts +30 -0
  45. package/src/stock-operations/stock-operations-forms/hooks/useOperationTypePermisions.ts +29 -0
  46. package/src/stock-operations/stock-operations-forms/hooks/useParties.ts +73 -0
  47. package/src/stock-operations/{users-selector/users-selector.resource.tsx → stock-operations-forms/hooks/useSearchUser.ts} +9 -7
  48. package/src/stock-operations/{batch-no-selector/batch-no-selector.resource.tsx → stock-operations-forms/hooks/useStockItemBatchNumbers.ts} +3 -3
  49. package/src/stock-operations/stock-operations-forms/hooks/useStockOperationLinks.ts +20 -0
  50. package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.component.tsx +72 -0
  51. package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.test.tsx +90 -0
  52. 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
  53. package/src/stock-operations/stock-operations-forms/input-components/qty-uim-selector.test.tsx +157 -0
  54. package/src/stock-operations/stock-operations-forms/input-components/quantity-uom-selector.component.tsx +53 -0
  55. package/src/stock-operations/stock-operations-forms/input-components/stock-item-search.component.tsx +79 -0
  56. package/src/stock-operations/stock-operations-forms/input-components/stock-operation-reason-selector.component.tsx +59 -0
  57. package/src/stock-operations/stock-operations-forms/input-components/stock-operation-reason-selector.test.tsx +216 -0
  58. package/src/stock-operations/{batch-no-selector → stock-operations-forms/input-components}/unique-batch-no-entry-input.component.tsx +12 -7
  59. package/src/stock-operations/stock-operations-forms/input-components/user-selector.test.tsx +110 -0
  60. package/src/stock-operations/stock-operations-forms/input-components/users-selector.component.tsx +111 -0
  61. package/src/stock-operations/stock-operations-forms/step1.test.tsx +303 -0
  62. package/src/stock-operations/stock-operations-forms/step2.test.tsx +254 -0
  63. package/src/stock-operations/stock-operations-forms/step3.test.tsx +223 -0
  64. package/src/stock-operations/stock-operations-forms/steps/base-operation-details-form-step.tsx +241 -0
  65. package/src/stock-operations/stock-operations-forms/steps/quantity-uom-cell.component.tsx +33 -0
  66. package/src/stock-operations/stock-operations-forms/steps/received-items.component.tsx +110 -0
  67. package/src/stock-operations/stock-operations-forms/steps/stock-availability-cell.component.tsx +51 -0
  68. package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-batch-no-cell.component.tsx +40 -0
  69. package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-cell.component.tsx +50 -0
  70. package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-expiry-cell.component.tsx +41 -0
  71. package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.component.tsx +281 -0
  72. package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.scc.scss +64 -0
  73. package/src/stock-operations/stock-operations-forms/steps/stock-operation-submission-form-step.component.tsx +243 -0
  74. package/src/stock-operations/stock-operations-forms/stock-issue-form-initializer-with-related-requisition-operation.component.tsx +55 -0
  75. package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.scss +41 -0
  76. package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.workspace.tsx +211 -0
  77. package/src/stock-operations/stock-operations-forms/stock-operation-form-header.component.tsx +166 -0
  78. package/src/stock-operations/stock-operations-forms/stock-operation-form.component.tsx +205 -0
  79. package/src/stock-operations/stock-operations-forms/stock-operation-form.scss +111 -0
  80. package/src/stock-operations/stock-operations-forms/stock-operation-related-link.component.tsx +45 -0
  81. package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stepper.scss +41 -0
  82. package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stock-operation-stepper.component.tsx +52 -0
  83. package/src/stock-operations/stock-operations-forms/stock-operations-form-utils.ts +32 -0
  84. package/src/stock-operations/stock-operations-table.component.tsx +57 -92
  85. package/src/stock-operations/stock-operations.resource.ts +16 -13
  86. package/src/stock-operations/validation-schema.ts +72 -14
  87. package/dist/766.js +0 -2
  88. package/dist/766.js.map +0 -1
  89. package/dist/822.js +0 -1
  90. package/dist/822.js.map +0 -1
  91. package/src/stock-operations/add-stock-operation/add-stock-operation.component.tsx +0 -349
  92. package/src/stock-operations/add-stock-operation/add-stock-operation.resource.tsx +0 -27
  93. package/src/stock-operations/add-stock-operation/add-stock-operation.scss +0 -60
  94. package/src/stock-operations/add-stock-operation/add-stock-operation.test.tsx +0 -192
  95. package/src/stock-operations/add-stock-operation/add-stock-operation.utils.tsx +0 -152
  96. package/src/stock-operations/add-stock-operation/add-stock-utils.ts +0 -103
  97. package/src/stock-operations/add-stock-operation/base-operation-details.component.tsx +0 -439
  98. package/src/stock-operations/add-stock-operation/base-operation-details.scss +0 -30
  99. package/src/stock-operations/add-stock-operation/received-items.component.tsx +0 -93
  100. package/src/stock-operations/add-stock-operation/stock-item-search/stock-item-search.component.tsx +0 -70
  101. package/src/stock-operations/add-stock-operation/stock-items-addition-row.component.tsx +0 -357
  102. package/src/stock-operations/add-stock-operation/stock-items-addition-row.resource.tsx +0 -0
  103. package/src/stock-operations/add-stock-operation/stock-items-addition-row.scss +0 -12
  104. package/src/stock-operations/add-stock-operation/stock-items-addition-row.test.tsx +0 -10
  105. package/src/stock-operations/add-stock-operation/stock-items-addition.component.scss +0 -17
  106. package/src/stock-operations/add-stock-operation/stock-items-addition.component.tsx +0 -254
  107. package/src/stock-operations/add-stock-operation/stock-operation-context/useStockOperationContext.tsx +0 -16
  108. package/src/stock-operations/add-stock-operation/stock-operation-reference.component.tsx +0 -39
  109. package/src/stock-operations/add-stock-operation/stock-operation-related-link.component.tsx +0 -38
  110. package/src/stock-operations/add-stock-operation/stock-operation-status.component.tsx +0 -170
  111. package/src/stock-operations/add-stock-operation/stock-operation-submission.component.tsx +0 -189
  112. package/src/stock-operations/add-stock-operation/stock-operation-submission.test.tsx +0 -138
  113. package/src/stock-operations/add-stock-operation/types.ts +0 -55
  114. package/src/stock-operations/add-stock-operation/validationSchema.ts +0 -54
  115. package/src/stock-operations/batch-no-selector/batch-no-selector.component.tsx +0 -114
  116. package/src/stock-operations/batch-no-selector/batch-no-selector.scss +0 -0
  117. package/src/stock-operations/batch-no-selector/batch-no-selector.test.tsx +0 -101
  118. package/src/stock-operations/party-selector/party-selector.component.tsx +0 -59
  119. package/src/stock-operations/qty-uom-selector/qty-uom-selector.component.tsx +0 -65
  120. package/src/stock-operations/qty-uom-selector/qty-uom-selector.resource.tsx +0 -0
  121. package/src/stock-operations/qty-uom-selector/qty-uom-selector.scss +0 -0
  122. package/src/stock-operations/qty-uom-selector/qty-uom-selector.test.tsx +0 -10
  123. package/src/stock-operations/stock-item-selector/stock-item-selector.component.tsx +0 -69
  124. package/src/stock-operations/stock-item-selector/stock-item-selector.scss +0 -0
  125. package/src/stock-operations/stock-item-selector/stock-item-selector.test.tsx +0 -10
  126. package/src/stock-operations/stock-operation-reason-selector/stock-operation-reason-selector.component.tsx +0 -62
  127. package/src/stock-operations/users-selector/users-selector.component.tsx +0 -75
  128. /package/dist/{766.js.LICENSE.txt → 493.js.LICENSE.txt} +0 -0
@@ -0,0 +1,166 @@
1
+ import React, { useMemo } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { StockOperationDTO } from '../../core/api/types/stockOperation/StockOperationDTO';
4
+ import {
5
+ operationFromString,
6
+ OperationType,
7
+ StockOperationType,
8
+ StockOperationTypeHasPrint,
9
+ } from '../../core/api/types/stockOperation/StockOperationType';
10
+ import StockOperationApprovalButton from '../stock-operations-dialog/stock-operations-approve-button.component';
11
+ import StockOperationApproveDispatchButton from '../stock-operations-dialog/stock-operations-approve-dispatch-button.component';
12
+ import StockOperationCancelButton from '../stock-operations-dialog/stock-operations-cancel-button.component';
13
+ import StockOperationCompleteDispatchButton from '../stock-operations-dialog/stock-operations-completed-dispatch-button.component';
14
+ import StockOperationIssueStockButton from '../stock-operations-dialog/stock-operations-issue-stock-button.component';
15
+ import StockOperationPrintButton from '../stock-operations-dialog/stock-operations-print-button.component';
16
+ import StockOperationRejectButton from '../stock-operations-dialog/stock-operations-reject-button.component';
17
+ import StockOperationReturnButton from '../stock-operations-dialog/stock-operations-return-button.component';
18
+ import { operationStatusColor } from '../stock-operations.resource';
19
+ import useOperationTypePermisions from './hooks/useOperationTypePermisions';
20
+ import useStockOperationLinks from './hooks/useStockOperationLinks';
21
+ import styles from './stock-operation-form.scss';
22
+ import StockOperationRelatedLink from './stock-operation-related-link.component';
23
+ import StockOperationStatusRow from '../stock-operation-status/stock-operation-status-row';
24
+
25
+ type Props = {
26
+ stockOperation: StockOperationDTO;
27
+ stockOperationType: StockOperationType;
28
+ };
29
+
30
+ const StockOperationFormHeader: React.FC<Props> = ({ stockOperationType, stockOperation }) => {
31
+ const operationTypePermision = useOperationTypePermisions(stockOperationType);
32
+ const operationType = useMemo(() => {
33
+ return operationFromString(stockOperationType.operationType);
34
+ }, [stockOperationType]);
35
+ const requisitionOperationUuid = useMemo(() => {
36
+ if (
37
+ stockOperationType?.operationType === OperationType.REQUISITION_OPERATION_TYPE ||
38
+ stockOperation?.operationType === OperationType.REQUISITION_OPERATION_TYPE ||
39
+ stockOperationType?.operationType === OperationType.STOCK_ISSUE_OPERATION_TYPE ||
40
+ stockOperation?.operationType === OperationType.STOCK_ISSUE_OPERATION_TYPE
41
+ ) {
42
+ return stockOperation.uuid;
43
+ }
44
+ return null;
45
+ }, [stockOperationType, stockOperation]);
46
+ const { error, isLoading, operationLinks } = useStockOperationLinks(requisitionOperationUuid);
47
+ const { t } = useTranslation();
48
+ if (isLoading || error) return null;
49
+
50
+ return (
51
+ <div>
52
+ <div className={styles.statusBody}>
53
+ <div className={styles.operationlinkscontainer}>
54
+ <div className={styles.statusLabel}>
55
+ <span className={styles.textHeading}>{t('status', 'Status ')}:</span>
56
+ <span
57
+ style={{
58
+ marginLeft: '2px',
59
+ color: `${operationStatusColor(stockOperation?.status)}`,
60
+ }}
61
+ >
62
+ {stockOperation?.status}
63
+ </span>
64
+ </div>
65
+ <StockOperationStatusRow stockOperation={stockOperation} />
66
+ </div>
67
+
68
+ {((!stockOperation.permission?.canEdit &&
69
+ (stockOperation.permission?.canApprove || stockOperation.permission?.canReceiveItems)) ||
70
+ stockOperation.permission?.canEdit ||
71
+ StockOperationTypeHasPrint(operationType) ||
72
+ (stockOperation?.permission?.isRequisitionAndCanIssueStock ?? false) ||
73
+ stockOperation.permission?.isRequisitionAndCanIssueStock) && (
74
+ <div className={styles.actionBtns}>
75
+ <>
76
+ {!stockOperation.permission?.canEdit && stockOperation.permission?.canApprove && (
77
+ <>
78
+ {!operationTypePermision.requiresDispatchAcknowledgement && (
79
+ <StockOperationApprovalButton operation={stockOperation} />
80
+ )}
81
+
82
+ {operationTypePermision.requiresDispatchAcknowledgement && (
83
+ <StockOperationApproveDispatchButton operation={stockOperation} />
84
+ )}
85
+
86
+ <StockOperationRejectButton operation={stockOperation} />
87
+ <StockOperationReturnButton operation={stockOperation} />
88
+ <StockOperationCancelButton operation={stockOperation} />
89
+ </>
90
+ )}
91
+
92
+ {!stockOperation.permission?.canEdit && stockOperation.permission?.canReceiveItems && (
93
+ <>
94
+ <StockOperationCompleteDispatchButton operation={stockOperation} reason={false} />
95
+ <StockOperationReturnButton operation={stockOperation} />
96
+ </>
97
+ )}
98
+
99
+ {stockOperation.permission?.canEdit && <StockOperationCancelButton operation={stockOperation} />}
100
+ {stockOperation.permission?.isRequisitionAndCanIssueStock && (
101
+ <StockOperationIssueStockButton operation={stockOperation} />
102
+ )}
103
+ {(stockOperation.permission?.isRequisitionAndCanIssueStock ||
104
+ stockOperation.operationType === OperationType.STOCK_ISSUE_OPERATION_TYPE ||
105
+ stockOperation.operationType === OperationType.REQUISITION_OPERATION_TYPE ||
106
+ stockOperation.operationType === OperationType.RECEIPT_OPERATION_TYPE ||
107
+ stockOperation.operationType === OperationType.TRANSFER_OUT_OPERATION_TYPE) && (
108
+ <StockOperationPrintButton operation={stockOperation} />
109
+ )}
110
+ </>
111
+ </div>
112
+ )}
113
+ </div>
114
+ {operationLinks && operationLinks.length > 0 && (
115
+ <div className={styles.operationlinkscontainer}>
116
+ <h6 className={styles.relatedTransactionHeader}>Related Transactions:</h6>
117
+ {operationLinks.map(
118
+ (item) =>
119
+ (stockOperation.uuid === item?.parentUuid || stockOperationType?.uuid === item?.parentUuid) && (
120
+ <React.Fragment key={item.uuid}>
121
+ <span>{item?.childOperationTypeName}</span>
122
+ <span className={item?.childVoided ? 'voided' : ''}>
123
+ {' '}
124
+ {item?.childVoided && item?.childOperationNumber}
125
+ {!item?.childVoided && (
126
+ <span className={styles.relatedLink}>
127
+ <StockOperationRelatedLink
128
+ stockOperationUuid={item?.childUuid}
129
+ operationNumber={item?.childOperationNumber}
130
+ />
131
+ </span>
132
+ )}
133
+ </span>{' '}
134
+ <span>[{item?.childStatus}]</span>
135
+ </React.Fragment>
136
+ ),
137
+ )}
138
+ <span> </span>
139
+ {operationLinks.map(
140
+ (item) =>
141
+ (stockOperation.uuid === item?.childUuid || stockOperationType.uuid === item?.childUuid) && (
142
+ <React.Fragment key={item.uuid}>
143
+ <span>{item?.parentOperationTypeName}</span>
144
+ <span className={item?.parentVoided ? 'voided' : ''}>
145
+ {' '}
146
+ {item?.parentVoided && item?.parentOperationNumber}
147
+ {!item?.parentVoided && (
148
+ <span className={styles.relatedLink}>
149
+ <StockOperationRelatedLink
150
+ stockOperationUuid={item?.parentUuid}
151
+ operationNumber={item?.parentOperationNumber}
152
+ />
153
+ </span>
154
+ )}
155
+ </span>{' '}
156
+ <span>[{item?.parentStatus}]</span>
157
+ </React.Fragment>
158
+ ),
159
+ )}
160
+ </div>
161
+ )}
162
+ </div>
163
+ );
164
+ };
165
+
166
+ export default StockOperationFormHeader;
@@ -0,0 +1,205 @@
1
+ import { CircleDash } from '@carbon/react/icons';
2
+ import { zodResolver } from '@hookform/resolvers/zod';
3
+ import { parseDate, showSnackbar, useConfig, useSession } from '@openmrs/esm-framework';
4
+ import React, { useEffect, useMemo, useState } from 'react';
5
+ import { FieldError, FormProvider, useForm } from 'react-hook-form';
6
+ import { useTranslation } from 'react-i18next';
7
+ import { ConfigObject } from '../../config-schema';
8
+ import { today } from '../../constants';
9
+ import { StockOperationDTO } from '../../core/api/types/stockOperation/StockOperationDTO';
10
+ import {
11
+ operationFromString,
12
+ OperationType,
13
+ StockOperationType,
14
+ StockOperationTypeIsStockIssue,
15
+ } from '../../core/api/types/stockOperation/StockOperationType';
16
+ import { TabItem } from '../../core/components/tabs/types';
17
+ import { otherUser, pick } from '../../core/utils/utils';
18
+ import ReceivedItems from './steps/received-items.component';
19
+ import {
20
+ getStockOperationFormSchema,
21
+ getStockOperationItemFormSchema,
22
+ StockOperationItemDtoSchema,
23
+ } from '../validation-schema';
24
+ import useOperationTypePermisions from './hooks/useOperationTypePermisions';
25
+ import BaseOperationDetailsFormStep from './steps/base-operation-details-form-step';
26
+ import StockOperationItemsFormStep from './steps/stock-operation-items-form-step.component';
27
+ import StockOperationSubmissionFormStep from './steps/stock-operation-submission-form-step.component';
28
+ import StockOperationFormHeader from './stock-operation-form-header.component';
29
+ import StockOperationStepper from './stock-operation-stepper/stock-operation-stepper.component';
30
+ import StockIssueFormInitializerWithRelatedRequisitionOperation from './stock-issue-form-initializer-with-related-requisition-operation.component';
31
+
32
+ /**
33
+ * Props interface for the StockOperationForm component
34
+ * @interface StockOperationFormProps
35
+ * @property {StockOperationType} [stockOperationType] - The stock operation type being created or edited.
36
+ * @property {StockOperationDTO} [stockOperation] - The stock operation data transfer object.
37
+ * @property {string} [stockRequisitionUuid] - Requisition operation uuid used in stock issue stockOperation type
38
+ * When undefined or null, the form will be in creation mode.
39
+ */
40
+ type StockOperationFormProps = {
41
+ stockOperation?: StockOperationDTO;
42
+ stockOperationType: StockOperationType;
43
+ stockRequisitionUuid?: string;
44
+ };
45
+
46
+ const StockOperationForm: React.FC<StockOperationFormProps> = ({
47
+ stockOperation,
48
+ stockOperationType,
49
+ stockRequisitionUuid,
50
+ }) => {
51
+ const { t } = useTranslation();
52
+ const operationType = useMemo(() => {
53
+ return operationFromString(stockOperationType.operationType);
54
+ }, [stockOperationType]);
55
+ const operationTypePermision = useOperationTypePermisions(stockOperationType);
56
+ const stockOperationItemFormSchema = useMemo(() => {
57
+ return getStockOperationItemFormSchema(operationType);
58
+ }, [operationType]);
59
+ const formschema = useMemo(() => {
60
+ return getStockOperationFormSchema(operationType);
61
+ }, [operationType]);
62
+ const showReceivedItems = useMemo(() => {
63
+ return (
64
+ (StockOperationTypeIsStockIssue(stockOperation?.operationType as OperationType) ||
65
+ stockOperation?.permission?.canDisplayReceivedItems) &&
66
+ (stockOperation.status === 'DISPATCHED' || stockOperation.status === 'COMPLETED')
67
+ );
68
+ }, [stockOperation]);
69
+ const steps: TabItem[] = useMemo(() => {
70
+ return [
71
+ {
72
+ name: stockOperation ? `${stockOperationType?.name} Details` : `${stockOperationType?.name} Details`,
73
+ component: (
74
+ <BaseOperationDetailsFormStep
75
+ stockOperation={stockOperation}
76
+ stockOperationType={stockOperationType}
77
+ onNext={() => setSelectedIndex(1)}
78
+ />
79
+ ),
80
+ disabled: true,
81
+ },
82
+ {
83
+ name: t('stockItems', 'Stock Items'),
84
+ component: (
85
+ <StockOperationItemsFormStep
86
+ stockOperation={stockOperation}
87
+ stockOperationType={stockOperationType}
88
+ onNext={() => setSelectedIndex(2)}
89
+ onPrevious={() => setSelectedIndex(0)}
90
+ />
91
+ ),
92
+ disabled: true,
93
+ },
94
+ {
95
+ name: operationTypePermision?.requiresDispatchAcknowledgement ? 'Submit/Dispatch' : 'Submit/Complete',
96
+ component: (
97
+ <StockOperationSubmissionFormStep
98
+ stockOperation={stockOperation}
99
+ stockOperationType={stockOperationType}
100
+ onPrevious={() => setSelectedIndex(1)}
101
+ onNext={showReceivedItems ? () => setSelectedIndex(3) : undefined}
102
+ />
103
+ ),
104
+ disabled: true,
105
+ },
106
+ ].concat(
107
+ showReceivedItems
108
+ ? [
109
+ {
110
+ name: t('receivedItems', 'Received Items'),
111
+ component: <ReceivedItems stockOperation={stockOperation} onPrevious={() => setSelectedIndex(2)} />,
112
+ disabled: true,
113
+ },
114
+ ]
115
+ : [],
116
+ ) as TabItem[];
117
+ }, [stockOperation, stockOperationType, t, operationTypePermision, showReceivedItems]);
118
+ const {
119
+ user: { uuid: defaultLoggedUserUuid },
120
+ } = useSession();
121
+ const { autoPopulateResponsiblePerson } = useConfig<ConfigObject>();
122
+ const [selectedIndex, setSelectedIndex] = useState(0);
123
+ const form = useForm<StockOperationItemDtoSchema>({
124
+ // defaultValues: operationType === OperationType.STOCK_ISSUE_OPERATION_TYPE ? issueStockOperation : model,
125
+ defaultValues: {
126
+ responsiblePersonUuid:
127
+ stockOperation?.responsiblePersonUuid ?? // if person uuid exist, make it default
128
+ (stockOperation?.responsiblePersonOther ? otherUser.uuid : undefined) ?? // if other resp person exist, default other user uuid
129
+ (autoPopulateResponsiblePerson ? defaultLoggedUserUuid : undefined), //Else default login user if configured
130
+ operationDate: stockOperation?.operationDate ? parseDate(stockOperation!.operationDate as any) : today(),
131
+ remarks: stockOperation?.remarks ?? '',
132
+
133
+ operationTypeUuid: stockOperation?.operationTypeUuid ?? stockOperationType?.uuid,
134
+ reasonUuid: stockOperation?.reasonUuid ?? '',
135
+ responsiblePersonOther: stockOperation?.responsiblePersonOther ?? '',
136
+ stockOperationItems:
137
+ stockOperation?.stockOperationItems?.map((item) =>
138
+ pick(
139
+ { ...item, expiration: item.expiration ? parseDate(item.expiration as any) : undefined },
140
+ stockOperationItemFormSchema.keyof().options,
141
+ ),
142
+ ) ?? [],
143
+ sourceUuid: stockOperation?.sourceUuid ?? '',
144
+ destinationUuid: stockOperation?.destinationUuid ?? '',
145
+ },
146
+ mode: 'all',
147
+ resolver: zodResolver(formschema),
148
+ });
149
+
150
+ useEffect(() => {
151
+ // Show error snackbar
152
+ Object.entries(form.formState.errors ?? {}).forEach(([key, val]) => {
153
+ if (['stockOperationItems', 'operationTypeUuid'].includes(key)) {
154
+ showSnackbar({ kind: 'error', title: key, subtitle: (val[key] as FieldError)?.message });
155
+ }
156
+ });
157
+ // Navigate to step where the error is
158
+ const fieldSteps = [
159
+ [
160
+ 'responsiblePersonUuid',
161
+ 'operationDate',
162
+ 'remarks',
163
+ 'sourceUuid',
164
+ 'destinationUuid',
165
+ 'reasonUuid',
166
+ 'responsiblePersonOther',
167
+ ],
168
+ ['stockOperationItems'],
169
+ ];
170
+ for (let step = 0; step < fieldSteps.length; step++) {
171
+ const hasError = fieldSteps[step].some((field) => field in form.formState.errors);
172
+ if (hasError) {
173
+ setSelectedIndex(step);
174
+ break;
175
+ }
176
+ }
177
+ }, [form.formState.errors]);
178
+
179
+ return (
180
+ <FormProvider {...form}>
181
+ {stockOperation && (
182
+ <StockOperationFormHeader stockOperationType={stockOperationType} stockOperation={stockOperation} />
183
+ )}
184
+ {stockOperationType.operationType === OperationType.STOCK_ISSUE_OPERATION_TYPE && (
185
+ <StockIssueFormInitializerWithRelatedRequisitionOperation
186
+ stockRequisitionUuid={stockRequisitionUuid as string}
187
+ stockOperationType={stockOperationType}
188
+ />
189
+ )}
190
+ <StockOperationStepper
191
+ steps={steps.map((tab, index) => ({
192
+ title: tab.name,
193
+ component: tab.component,
194
+ disabled: tab.disabled,
195
+ // subTitle: `Subtitle for ${tab.name}`,
196
+ icon: <CircleDash />,
197
+ }))}
198
+ selectedIndex={selectedIndex}
199
+ onChange={setSelectedIndex}
200
+ />
201
+ </FormProvider>
202
+ );
203
+ };
204
+
205
+ export default StockOperationForm;
@@ -0,0 +1,111 @@
1
+ @use '@carbon/type';
2
+ @use '@carbon/layout';
3
+ @use '@carbon/colors';
4
+ @import '~@openmrs/esm-styleguide/src/vars';
5
+
6
+ .form {
7
+ display: flex;
8
+ flex-direction: column;
9
+ justify-content: space-between;
10
+ width: 100%;
11
+ height: 100%;
12
+ }
13
+
14
+ .grid {
15
+ margin: layout.$spacing-05 layout.$spacing-05;
16
+ padding: layout.$spacing-05 0 0 0;
17
+ }
18
+
19
+ .button {
20
+ display: flex;
21
+ align-content: flex-start;
22
+ align-items: baseline;
23
+ min-width: 50%;
24
+ }
25
+
26
+ .buttonSet {
27
+ display: flex;
28
+ justify-content: space-between;
29
+ width: 100%;
30
+ }
31
+
32
+ .datePickerInput span,
33
+ .datePickerInput div,
34
+ .datePickerInput input,
35
+ .datePickerInput {
36
+ min-width: 100%;
37
+ }
38
+
39
+ .title {
40
+ @include type.type-style('heading-02');
41
+ padding: layout.$spacing-03;
42
+ }
43
+
44
+ .heading {
45
+ text-align: left;
46
+ text-transform: capitalize;
47
+ display: flex;
48
+ flex-direction: row;
49
+ justify-content: space-between;
50
+ align-items: center;
51
+ margin: layout.$spacing-03 0 layout.$spacing-03 0;
52
+
53
+ h4 {
54
+ @include type.type-style('heading-compact-02');
55
+ color: colors.$gray-70;
56
+
57
+ &:after {
58
+ content: '';
59
+ display: block;
60
+ width: 2rem;
61
+ padding-top: 3px;
62
+ border-bottom: 0.375rem solid;
63
+ @include brand-03(border-bottom-color);
64
+ }
65
+ }
66
+ }
67
+
68
+ .btnSet {
69
+ display: flex;
70
+ flex-direction: row;
71
+ gap: layout.$spacing-03;
72
+ align-items: center;
73
+ }
74
+
75
+ .relatedLink {
76
+ margin-left: layout.$spacing-02;
77
+ color: colors.$blue-60;
78
+ }
79
+
80
+ .textHeading {
81
+ font-weight: bold;
82
+ }
83
+
84
+ .statusLabel {
85
+ display: flex;
86
+ flex-direction: row;
87
+ margin-bottom: layout.$spacing-05;
88
+ }
89
+
90
+ .statusBody {
91
+ display: flex;
92
+ justify-content: space-between;
93
+ margin: layout.$spacing-02;
94
+ }
95
+
96
+ .actionBtns {
97
+ margin: layout.$spacing-03;
98
+ display: flex;
99
+ flex-direction: row;
100
+ gap: layout.$spacing-03;
101
+ flex-wrap: wrap;
102
+ height: fit-content;
103
+ }
104
+
105
+ .operationlinkscontainer {
106
+ margin: layout.$spacing-05;
107
+ }
108
+
109
+ .relatedTransactionHeader {
110
+ color: colors.$green-50;
111
+ }
@@ -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
+ };