@openmrs/esm-stock-management-app 1.0.1-pre.783 → 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.
- package/__mocks__/index.ts +1 -0
- package/__mocks__/operation-type.mock.ts +532 -0
- package/dist/155.js +1 -0
- package/dist/155.js.map +1 -0
- package/dist/172.js +1 -1
- package/dist/20.js +1 -1
- package/dist/290.js +1 -1
- package/dist/493.js +2 -0
- package/dist/493.js.map +1 -0
- package/dist/606.js +1 -1
- package/dist/627.js +1 -1
- package/dist/914.js +1 -0
- package/dist/914.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 +75 -51
- package/dist/openmrs-esm-stock-management-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/core/utils/utils.ts +29 -0
- package/src/index.ts +4 -0
- package/src/routes.json +9 -0
- package/src/stock-items/add-stock-item/transactions/printout/transactions-stockcard-printout.component.tsx +8 -12
- package/src/stock-items/add-stock-item/transactions/transactions.component.tsx +8 -12
- package/src/stock-items/stock-items.resource.ts +5 -5
- package/src/stock-lookups/stock-lookups.resource.ts +2 -2
- package/src/stock-operations/edit-stock-operation/edit-stock-operation-action-menu.component.tsx +41 -16
- package/src/stock-operations/{add-stock-operation/received-items.component.tsx → received-items.component.tsx} +1 -1
- package/src/stock-operations/stock-operation-reference.component.tsx +64 -0
- package/src/stock-operations/stock-operation-status/stock-operation-status-row.tsx +77 -0
- package/src/stock-operations/stock-operation-status/stock-operation-status.scss +32 -0
- package/src/stock-operations/stock-operation-status/stock-operation-status.tsx +45 -0
- package/src/stock-operations/stock-operation-types-selector/stock-operation-types-selector.component.tsx +30 -29
- package/src/stock-operations/stock-operation.utils.tsx +16 -79
- package/src/stock-operations/stock-operations-dialog/stock-operations-issue-stock-button.component.tsx +27 -39
- package/src/stock-operations/stock-operations-dialog/stock-operations-print-button.component.tsx +51 -59
- package/src/stock-operations/{stock-item-selector/stock-item-selector.resource.tsx → stock-operations-forms/hooks/useFilterableStockItems.ts} +4 -4
- package/src/stock-operations/stock-operations-forms/hooks/useFilteredOperationTypesByRoles.ts +30 -0
- package/src/stock-operations/stock-operations-forms/hooks/useOperationTypePermisions.ts +29 -0
- package/src/stock-operations/stock-operations-forms/hooks/useParties.ts +73 -0
- package/src/stock-operations/{users-selector/users-selector.resource.tsx → stock-operations-forms/hooks/useSearchUser.ts} +9 -7
- package/src/stock-operations/{batch-no-selector/batch-no-selector.resource.tsx → stock-operations-forms/hooks/useStockItemBatchNumbers.ts} +3 -3
- package/src/stock-operations/stock-operations-forms/hooks/useStockOperationLinks.ts +20 -0
- package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.component.tsx +72 -0
- package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.test.tsx +90 -0
- 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
- package/src/stock-operations/stock-operations-forms/input-components/qty-uim-selector.test.tsx +157 -0
- package/src/stock-operations/stock-operations-forms/input-components/quantity-uom-selector.component.tsx +53 -0
- package/src/stock-operations/stock-operations-forms/input-components/stock-item-search.component.tsx +56 -0
- package/src/stock-operations/stock-operations-forms/input-components/stock-operation-reason-selector.component.tsx +59 -0
- package/src/stock-operations/stock-operations-forms/input-components/stock-operation-reason-selector.test.tsx +216 -0
- package/src/stock-operations/{batch-no-selector → stock-operations-forms/input-components}/unique-batch-no-entry-input.component.tsx +12 -7
- package/src/stock-operations/stock-operations-forms/input-components/user-selector.test.tsx +110 -0
- package/src/stock-operations/stock-operations-forms/input-components/users-selector.component.tsx +111 -0
- package/src/stock-operations/stock-operations-forms/step1.test.tsx +303 -0
- package/src/stock-operations/stock-operations-forms/step2.test.tsx +250 -0
- package/src/stock-operations/stock-operations-forms/step3.test.tsx +223 -0
- package/src/stock-operations/stock-operations-forms/steps/base-operation-details-form-step.tsx +241 -0
- package/src/stock-operations/stock-operations-forms/steps/quantity-uom-cell.component.tsx +33 -0
- package/src/stock-operations/stock-operations-forms/steps/stock-availability-cell.component.tsx +51 -0
- package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-batch-no-cell.component.tsx +40 -0
- package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-cell.component.tsx +38 -0
- package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-expiry-cell.component.tsx +41 -0
- package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.component.tsx +281 -0
- package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.scc.scss +64 -0
- package/src/stock-operations/stock-operations-forms/steps/stock-operation-submission-form-step.component.tsx +236 -0
- package/src/stock-operations/stock-operations-forms/stock-issue-form-initializer-with-related-requisition-operation.component.tsx +55 -0
- package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.scss +41 -0
- package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.workspace.tsx +197 -0
- package/src/stock-operations/stock-operations-forms/stock-operation-form-header.component.tsx +166 -0
- package/src/stock-operations/stock-operations-forms/stock-operation-form.component.tsx +200 -0
- package/src/stock-operations/stock-operations-forms/stock-operation-form.scss +111 -0
- package/src/stock-operations/stock-operations-forms/stock-operation-related-link.component.tsx +45 -0
- package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stepper.scss +41 -0
- package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stock-operation-stepper.component.tsx +52 -0
- package/src/stock-operations/stock-operations-forms/stock-operations-form-utils.ts +32 -0
- package/src/stock-operations/stock-operations-table.component.tsx +20 -56
- package/src/stock-operations/stock-operations.resource.ts +16 -13
- package/src/stock-operations/validation-schema.ts +72 -14
- package/dist/766.js +0 -2
- package/dist/766.js.map +0 -1
- package/dist/822.js +0 -1
- package/dist/822.js.map +0 -1
- package/src/stock-operations/add-stock-operation/add-stock-operation.component.tsx +0 -349
- package/src/stock-operations/add-stock-operation/add-stock-operation.resource.tsx +0 -27
- package/src/stock-operations/add-stock-operation/add-stock-operation.scss +0 -60
- package/src/stock-operations/add-stock-operation/add-stock-operation.test.tsx +0 -192
- package/src/stock-operations/add-stock-operation/add-stock-operation.utils.tsx +0 -152
- package/src/stock-operations/add-stock-operation/add-stock-utils.ts +0 -103
- package/src/stock-operations/add-stock-operation/base-operation-details.component.tsx +0 -439
- package/src/stock-operations/add-stock-operation/base-operation-details.scss +0 -30
- package/src/stock-operations/add-stock-operation/stock-item-search/stock-item-search.component.tsx +0 -70
- package/src/stock-operations/add-stock-operation/stock-items-addition-row.component.tsx +0 -357
- package/src/stock-operations/add-stock-operation/stock-items-addition-row.resource.tsx +0 -0
- package/src/stock-operations/add-stock-operation/stock-items-addition-row.scss +0 -12
- package/src/stock-operations/add-stock-operation/stock-items-addition-row.test.tsx +0 -10
- package/src/stock-operations/add-stock-operation/stock-items-addition.component.scss +0 -17
- package/src/stock-operations/add-stock-operation/stock-items-addition.component.tsx +0 -254
- package/src/stock-operations/add-stock-operation/stock-operation-context/useStockOperationContext.tsx +0 -16
- package/src/stock-operations/add-stock-operation/stock-operation-reference.component.tsx +0 -39
- package/src/stock-operations/add-stock-operation/stock-operation-related-link.component.tsx +0 -38
- package/src/stock-operations/add-stock-operation/stock-operation-status.component.tsx +0 -170
- package/src/stock-operations/add-stock-operation/stock-operation-submission.component.tsx +0 -189
- package/src/stock-operations/add-stock-operation/stock-operation-submission.test.tsx +0 -138
- package/src/stock-operations/add-stock-operation/types.ts +0 -55
- package/src/stock-operations/add-stock-operation/validationSchema.ts +0 -54
- package/src/stock-operations/batch-no-selector/batch-no-selector.component.tsx +0 -114
- package/src/stock-operations/batch-no-selector/batch-no-selector.scss +0 -0
- package/src/stock-operations/batch-no-selector/batch-no-selector.test.tsx +0 -101
- package/src/stock-operations/party-selector/party-selector.component.tsx +0 -59
- package/src/stock-operations/qty-uom-selector/qty-uom-selector.component.tsx +0 -65
- package/src/stock-operations/qty-uom-selector/qty-uom-selector.resource.tsx +0 -0
- package/src/stock-operations/qty-uom-selector/qty-uom-selector.scss +0 -0
- package/src/stock-operations/qty-uom-selector/qty-uom-selector.test.tsx +0 -10
- package/src/stock-operations/stock-item-selector/stock-item-selector.component.tsx +0 -69
- package/src/stock-operations/stock-item-selector/stock-item-selector.scss +0 -0
- package/src/stock-operations/stock-item-selector/stock-item-selector.test.tsx +0 -10
- package/src/stock-operations/stock-operation-reason-selector/stock-operation-reason-selector.component.tsx +0 -62
- package/src/stock-operations/users-selector/users-selector.component.tsx +0 -75
- /package/dist/{766.js.LICENSE.txt → 493.js.LICENSE.txt} +0 -0
@@ -1,152 +0,0 @@
|
|
1
|
-
/* eslint-disable prefer-const */
|
2
|
-
import { StockOperationDTO } from '../../core/api/types/stockOperation/StockOperationDTO';
|
3
|
-
import { initialStockOperationValue } from '../../core/utils/utils';
|
4
|
-
import { MAIN_STORE_LOCATION_TAG, today } from '../../constants';
|
5
|
-
import {
|
6
|
-
operationFromString,
|
7
|
-
StockOperationType,
|
8
|
-
StockOperationTypeCanCapturePurchasePrice,
|
9
|
-
StockOperationTypeHasPrint,
|
10
|
-
StockOperationTypeIsNegativeQtyAllowed,
|
11
|
-
StockOperationTypeIsQuantityOptional,
|
12
|
-
StockOperationTypeRequiresActualBatchInformation,
|
13
|
-
StockOperationTypeRequiresBatchUuid,
|
14
|
-
StockOperationTypeRequiresDispatchAcknowledgement,
|
15
|
-
StockOperationTypeRequiresStockAdjustmentReason,
|
16
|
-
} from '../../core/api/types/stockOperation/StockOperationType';
|
17
|
-
import { StockOperationItemDTO } from '../../core/api/types/stockOperation/StockOperationItemDTO';
|
18
|
-
import { InitializeResult } from './types';
|
19
|
-
import { LocationTypeLocation, LocationTypeOther } from '../../core/api/types/stockOperation/LocationType';
|
20
|
-
import { getParties, getStockOperationTypes } from '../../stock-lookups/stock-lookups.resource';
|
21
|
-
import { Party } from '../../core/api/types/Party';
|
22
|
-
|
23
|
-
export async function initializeNewStockOperation(
|
24
|
-
currentStockOperationType: StockOperationType,
|
25
|
-
stockOperation?: StockOperationDTO,
|
26
|
-
stockOperationTypes?: StockOperationType[],
|
27
|
-
): Promise<InitializeResult> {
|
28
|
-
let model: StockOperationDTO;
|
29
|
-
const isNew = !!stockOperation;
|
30
|
-
const newItemsToCopy: StockOperationItemDTO[] = [];
|
31
|
-
const showQuantityRequested = false;
|
32
|
-
|
33
|
-
let operationTypes = stockOperationTypes;
|
34
|
-
const canIssueStock = stockOperation?.permission?.isRequisitionAndCanIssueStock ?? false;
|
35
|
-
const sourceTags =
|
36
|
-
currentStockOperationType?.stockOperationTypeLocationScopes
|
37
|
-
?.filter((p) => currentStockOperationType?.hasSource && p.isSource)
|
38
|
-
.map((p) => p.locationTag) ?? [];
|
39
|
-
const shouldLockSource = sourceTags.length === 1 && sourceTags[0] === MAIN_STORE_LOCATION_TAG;
|
40
|
-
|
41
|
-
const destinationTags =
|
42
|
-
currentStockOperationType?.stockOperationTypeLocationScopes
|
43
|
-
?.filter((p) => currentStockOperationType?.hasDestination && p.isDestination)
|
44
|
-
.map((p) => p.locationTag) ?? [];
|
45
|
-
const shouldLockDestination = destinationTags.length === 1 && destinationTags[0] === MAIN_STORE_LOCATION_TAG;
|
46
|
-
let location: string | null | undefined = null;
|
47
|
-
let sourcePartyList: Party[] | null | undefined;
|
48
|
-
let destinationPartyList: Party[] | null | undefined;
|
49
|
-
|
50
|
-
const partyList = await getParties();
|
51
|
-
if (!partyList.ok) throw Error('Error loading parties');
|
52
|
-
sourcePartyList = partyList?.data?.results?.filter(
|
53
|
-
(p) =>
|
54
|
-
(p.locationUuid &&
|
55
|
-
currentStockOperationType?.sourceType === LocationTypeLocation &&
|
56
|
-
(sourceTags.length === 0 || (p.tags && sourceTags.some((x) => p.tags.includes(x))))) ||
|
57
|
-
(p.stockSourceUuid && currentStockOperationType?.sourceType === LocationTypeOther),
|
58
|
-
);
|
59
|
-
destinationPartyList = partyList?.data?.results?.filter(
|
60
|
-
(p) =>
|
61
|
-
(p.locationUuid &&
|
62
|
-
currentStockOperationType?.destinationType === LocationTypeLocation &&
|
63
|
-
(destinationTags.length === 0 || (p.tags && destinationTags.some((x) => p.tags.includes(x))))) ||
|
64
|
-
(p.stockSourceUuid && currentStockOperationType?.destinationType === LocationTypeOther),
|
65
|
-
);
|
66
|
-
|
67
|
-
if (isNew) {
|
68
|
-
model = structuredClone(initialStockOperationValue());
|
69
|
-
model = Object.assign(model, {
|
70
|
-
operationDate: today(),
|
71
|
-
operationTypeName: currentStockOperationType?.name,
|
72
|
-
operationTypeUuid: currentStockOperationType?.uuid,
|
73
|
-
operationType: currentStockOperationType?.operationType,
|
74
|
-
});
|
75
|
-
if (currentStockOperationType?.hasSource) {
|
76
|
-
if (isNew && shouldLockSource && sourcePartyList?.length > 0) {
|
77
|
-
const party = sourcePartyList[0];
|
78
|
-
model.sourceUuid = party.uuid;
|
79
|
-
model.sourceName = party.name;
|
80
|
-
location = party?.locationUuid;
|
81
|
-
}
|
82
|
-
}
|
83
|
-
|
84
|
-
if (currentStockOperationType?.hasDestination) {
|
85
|
-
if (isNew && shouldLockDestination && destinationPartyList?.length > 0) {
|
86
|
-
const party = destinationPartyList[0];
|
87
|
-
model.destinationUuid = party.uuid;
|
88
|
-
model.destinationName = party.name;
|
89
|
-
}
|
90
|
-
}
|
91
|
-
} else {
|
92
|
-
model = stockOperation!;
|
93
|
-
const response = await getStockOperationTypes();
|
94
|
-
if (response.ok) {
|
95
|
-
operationTypes = response.data.results;
|
96
|
-
} else {
|
97
|
-
throw Error('Error loading operation types');
|
98
|
-
}
|
99
|
-
}
|
100
|
-
|
101
|
-
const opType = operationFromString(currentStockOperationType.operationType);
|
102
|
-
return {
|
103
|
-
batchBalance: {},
|
104
|
-
batchNos: {},
|
105
|
-
itemUoM: {},
|
106
|
-
requisition: '',
|
107
|
-
showQuantityRequested: false,
|
108
|
-
dto: model,
|
109
|
-
stockItems: newItemsToCopy,
|
110
|
-
isNegativeQuantityAllowed: StockOperationTypeIsNegativeQtyAllowed(opType),
|
111
|
-
requiresBatchUuid: StockOperationTypeRequiresBatchUuid(opType),
|
112
|
-
requiresActualBatchInfo: StockOperationTypeRequiresActualBatchInformation(opType),
|
113
|
-
isQuantityOptional: StockOperationTypeIsQuantityOptional(opType),
|
114
|
-
canCaptureQuantityPrice: StockOperationTypeCanCapturePurchasePrice(opType),
|
115
|
-
requiresStockAdjustmentReason: StockOperationTypeRequiresStockAdjustmentReason(opType),
|
116
|
-
requiresDispatchAcknowledgement: StockOperationTypeRequiresDispatchAcknowledgement(opType),
|
117
|
-
allowExpiredBatchNumbers: currentStockOperationType?.allowExpiredBatchNumbers ?? false,
|
118
|
-
canEditModel: stockOperation?.permission?.canEdit ?? false,
|
119
|
-
canViewModel: stockOperation?.permission?.canView ?? false,
|
120
|
-
canApproveModel: stockOperation?.permission?.canApprove ?? false,
|
121
|
-
canIssueStock,
|
122
|
-
canReceiveItems: stockOperation?.permission?.canReceiveItems ?? false,
|
123
|
-
canDisplayReceivedItems: stockOperation?.permission?.canDisplayReceivedItems ?? false,
|
124
|
-
canUpdateItemsBatchInformation: stockOperation?.permission?.canUpdateBatchInformation ?? false,
|
125
|
-
canPrint: canIssueStock || StockOperationTypeHasPrint(opType),
|
126
|
-
sourceTags,
|
127
|
-
destinationTags,
|
128
|
-
shouldLockDestination,
|
129
|
-
shouldLockSource,
|
130
|
-
sourcePartyListFilter: (p) => {
|
131
|
-
return (
|
132
|
-
(p.locationUuid &&
|
133
|
-
currentStockOperationType?.sourceType === LocationTypeLocation &&
|
134
|
-
(sourceTags.length === 0 || (p.tags && sourceTags.some((x) => p.tags.includes(x))))) ||
|
135
|
-
(p.stockSourceUuid && currentStockOperationType?.sourceType === LocationTypeOther)
|
136
|
-
);
|
137
|
-
},
|
138
|
-
destinationPartyListFilter: (p) => {
|
139
|
-
return (
|
140
|
-
(p.locationUuid &&
|
141
|
-
currentStockOperationType?.destinationType === LocationTypeLocation &&
|
142
|
-
(destinationTags.length === 0 || (p.tags && destinationTags.some((x) => p.tags.includes(x))))) ||
|
143
|
-
(p.stockSourceUuid && currentStockOperationType?.destinationType === LocationTypeOther)
|
144
|
-
);
|
145
|
-
},
|
146
|
-
location,
|
147
|
-
sourcePartyList,
|
148
|
-
destinationPartyList,
|
149
|
-
stockOperationTypes: operationTypes,
|
150
|
-
hasQtyRequested: showQuantityRequested,
|
151
|
-
};
|
152
|
-
}
|
@@ -1,103 +0,0 @@
|
|
1
|
-
import { StockOperationDTO } from '../../core/api/types/stockOperation/StockOperationDTO';
|
2
|
-
import { OperationType } from '../../core/api/types/stockOperation/StockOperationType';
|
3
|
-
|
4
|
-
const OPERATION_TYPES_FOR_DESTINATION_NAME_DELETION = [
|
5
|
-
OperationType.ADJUSTMENT_OPERATION_TYPE,
|
6
|
-
OperationType.RECEIPT_OPERATION_TYPE,
|
7
|
-
OperationType.STOCK_ISSUE_OPERATION_TYPE,
|
8
|
-
OperationType.STOCK_TAKE_OPERATION_TYPE,
|
9
|
-
OperationType.RETURN_OPERATION_TYPE,
|
10
|
-
OperationType.DISPOSED_OPERATION_TYPE,
|
11
|
-
OperationType.OPENING_STOCK_OPERATION_TYPE,
|
12
|
-
OperationType.TRANSFER_OUT_OPERATION_TYPE,
|
13
|
-
];
|
14
|
-
|
15
|
-
const OPERATION_TYPES_FOR_DESTINATION_UUID_DELETION = [
|
16
|
-
OperationType.ADJUSTMENT_OPERATION_TYPE,
|
17
|
-
OperationType.DISPOSED_OPERATION_TYPE,
|
18
|
-
OperationType.STOCK_TAKE_OPERATION_TYPE,
|
19
|
-
OperationType.OPENING_STOCK_OPERATION_TYPE,
|
20
|
-
];
|
21
|
-
|
22
|
-
export function getRequisitionStockOperations(items: Array<StockOperationDTO> = []) {
|
23
|
-
// Extract stock issued requisition UUIDs
|
24
|
-
const stockIssuedRequisitionUuids =
|
25
|
-
items
|
26
|
-
?.filter((item) => item.operationType === OperationType.STOCK_ISSUE_OPERATION_TYPE)
|
27
|
-
.map((item) => item.requisitionStockOperationUuid) ?? [];
|
28
|
-
|
29
|
-
// Filter requisition stock operations
|
30
|
-
const requisitionStockOperations =
|
31
|
-
items?.filter(
|
32
|
-
(item) =>
|
33
|
-
item.operationType === OperationType.REQUISITION_OPERATION_TYPE &&
|
34
|
-
!stockIssuedRequisitionUuids.includes(item.uuid),
|
35
|
-
) ?? [];
|
36
|
-
|
37
|
-
return requisitionStockOperations;
|
38
|
-
}
|
39
|
-
|
40
|
-
function deleteProperties(req, properties) {
|
41
|
-
properties.forEach((prop) => {
|
42
|
-
delete req[prop];
|
43
|
-
});
|
44
|
-
}
|
45
|
-
|
46
|
-
function shouldDeleteDestinationName(operationType) {
|
47
|
-
return OPERATION_TYPES_FOR_DESTINATION_NAME_DELETION.includes(operationType);
|
48
|
-
}
|
49
|
-
|
50
|
-
function shouldDeleteDestinationUuid(operationType) {
|
51
|
-
return OPERATION_TYPES_FOR_DESTINATION_UUID_DELETION.includes(operationType);
|
52
|
-
}
|
53
|
-
|
54
|
-
export function createBaseOperationPayload(model, item, operationType) {
|
55
|
-
const req = Object.assign(model, item);
|
56
|
-
const propertiesToDelete = [
|
57
|
-
'submitted',
|
58
|
-
'cancelledByFamilyName',
|
59
|
-
'atLocationName',
|
60
|
-
'completedByGivenName',
|
61
|
-
'cancelledBy',
|
62
|
-
'submittedByFamilyName',
|
63
|
-
'operationOrder',
|
64
|
-
'dispatchedByGivenName',
|
65
|
-
'submittedByGivenName',
|
66
|
-
'returnedByGivenName',
|
67
|
-
'operationNumber',
|
68
|
-
'responsiblePersonFamilyName',
|
69
|
-
'returnReason',
|
70
|
-
'atLocationUuid',
|
71
|
-
'cancelReason',
|
72
|
-
'rejectedByGivenName',
|
73
|
-
'reasonName',
|
74
|
-
'submittedBy',
|
75
|
-
'creator',
|
76
|
-
'completedByFamilyName',
|
77
|
-
'operationTypeName',
|
78
|
-
'rejectedByFamilyName',
|
79
|
-
'responsiblePerson',
|
80
|
-
'creatorFamilyName',
|
81
|
-
'returnedByFamilyName',
|
82
|
-
'cancelledByGivenName',
|
83
|
-
'operationType',
|
84
|
-
'responsiblePersonGivenName',
|
85
|
-
'sourceName',
|
86
|
-
'rejectionReason',
|
87
|
-
'completedBy',
|
88
|
-
'creatorGivenName',
|
89
|
-
'dispatchedByFamilyName',
|
90
|
-
'uuid',
|
91
|
-
];
|
92
|
-
|
93
|
-
deleteProperties(req, propertiesToDelete);
|
94
|
-
|
95
|
-
if (shouldDeleteDestinationName(operationType)) {
|
96
|
-
delete req.destinationName;
|
97
|
-
}
|
98
|
-
|
99
|
-
if (shouldDeleteDestinationUuid(operationType)) {
|
100
|
-
delete req.destinationUuid;
|
101
|
-
}
|
102
|
-
return req;
|
103
|
-
}
|
@@ -1,439 +0,0 @@
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
2
|
-
import { useTranslation } from 'react-i18next';
|
3
|
-
import { StockOperationDTO } from '../../core/api/types/stockOperation/StockOperationDTO';
|
4
|
-
import { SaveStockOperation } from '../../stock-items/types';
|
5
|
-
import { operationFromString, StockOperationType } from '../../core/api/types/stockOperation/StockOperationType';
|
6
|
-
import { DATE_PICKER_CONTROL_FORMAT, DATE_PICKER_FORMAT, formatForDatePicker, today } from '../../constants';
|
7
|
-
import { Button, DatePicker, DatePickerInput, InlineLoading, TextInput } from '@carbon/react';
|
8
|
-
import { Controller, useForm } from 'react-hook-form';
|
9
|
-
import { zodResolver } from '@hookform/resolvers/zod';
|
10
|
-
import { operationSchema, StockOperationFormData } from '../validation-schema';
|
11
|
-
import { ArrowRight } from '@carbon/react/icons';
|
12
|
-
import PartySelector from '../party-selector/party-selector.component';
|
13
|
-
import UsersSelector from '../users-selector/users-selector.component';
|
14
|
-
import { otherUser } from '../../core/utils/utils';
|
15
|
-
import ControlledTextInput from '../../core/components/carbon/controlled-text-input/controlled-text-input.component';
|
16
|
-
import StockOperationReasonSelector from '../stock-operation-reason-selector/stock-operation-reason-selector.component';
|
17
|
-
import ControlledTextArea from '../../core/components/carbon/controlled-text-area/controlled-text-area.component';
|
18
|
-
import { InitializeResult } from './types';
|
19
|
-
import { ResourceRepresentation } from '../../core/api/api';
|
20
|
-
import { useStockOperationPages } from '../stock-operations-table.resource';
|
21
|
-
import { createBaseOperationPayload } from './add-stock-utils';
|
22
|
-
import { showSnackbar, useSession } from '@openmrs/esm-framework';
|
23
|
-
|
24
|
-
import { Party } from '../../core/api/types/Party';
|
25
|
-
import styles from '../add-stock-operation/base-operation-details.scss';
|
26
|
-
|
27
|
-
interface BaseOperationDetailsProps {
|
28
|
-
isEditing?: boolean;
|
29
|
-
canEdit?: boolean;
|
30
|
-
model?: StockOperationDTO;
|
31
|
-
onSave?: SaveStockOperation;
|
32
|
-
operation: StockOperationType;
|
33
|
-
setup: InitializeResult;
|
34
|
-
}
|
35
|
-
|
36
|
-
const BaseOperationDetails: React.FC<BaseOperationDetailsProps> = ({
|
37
|
-
model,
|
38
|
-
onSave,
|
39
|
-
operation,
|
40
|
-
canEdit,
|
41
|
-
isEditing,
|
42
|
-
setup: { requiresStockAdjustmentReason: showReason, sourcePartyList, destinationPartyList },
|
43
|
-
}) => {
|
44
|
-
const { t } = useTranslation();
|
45
|
-
const { isLoading } = useStockOperationPages({
|
46
|
-
v: ResourceRepresentation.Full,
|
47
|
-
totalCount: true,
|
48
|
-
});
|
49
|
-
const operationType = operationFromString(operation?.operationType);
|
50
|
-
const issueStockOperation = mapIssueStockLocations(model);
|
51
|
-
const { user } = useSession();
|
52
|
-
const defaultLoggedUserUuid = user.uuid;
|
53
|
-
|
54
|
-
const {
|
55
|
-
handleSubmit,
|
56
|
-
control,
|
57
|
-
formState: { errors },
|
58
|
-
setValue,
|
59
|
-
} = useForm<StockOperationFormData>({
|
60
|
-
defaultValues: operationType === 'stockissue' ? issueStockOperation : model,
|
61
|
-
mode: 'all',
|
62
|
-
resolver: zodResolver(operationSchema(operationType)),
|
63
|
-
});
|
64
|
-
|
65
|
-
const [isOtherUser, setIsOtherUser] = useState<boolean | null>();
|
66
|
-
const [isSaving, setIsSaving] = useState(false);
|
67
|
-
useEffect(() => {
|
68
|
-
if (defaultLoggedUserUuid) {
|
69
|
-
setValue('responsiblePersonUuid', defaultLoggedUserUuid);
|
70
|
-
}
|
71
|
-
}, [defaultLoggedUserUuid, setValue]);
|
72
|
-
|
73
|
-
if (isLoading) {
|
74
|
-
return (
|
75
|
-
<InlineLoading status="active" iconDescription="Loading" description={t('loadingData', 'Loading data...')} />
|
76
|
-
);
|
77
|
-
}
|
78
|
-
|
79
|
-
const handleSave = async (item: StockOperationDTO) => {
|
80
|
-
try {
|
81
|
-
setIsSaving(true);
|
82
|
-
const payload = createBaseOperationPayload(model, item, operationType);
|
83
|
-
await onSave(payload);
|
84
|
-
} catch (e) {
|
85
|
-
showSnackbar({
|
86
|
-
title: t('errorSavingBaseOperation', 'Error saving base operation'),
|
87
|
-
isLowContrast: true,
|
88
|
-
kind: 'error',
|
89
|
-
});
|
90
|
-
} finally {
|
91
|
-
setIsSaving(false);
|
92
|
-
}
|
93
|
-
};
|
94
|
-
const sourceTags =
|
95
|
-
operation?.stockOperationTypeLocationScopes
|
96
|
-
?.filter((p) => operation?.hasSource && p.isSource)
|
97
|
-
.map((p) => p.locationTag) ?? [];
|
98
|
-
|
99
|
-
const destinationTags =
|
100
|
-
operation?.stockOperationTypeLocationScopes
|
101
|
-
?.filter((p) => operation?.hasDestination && p.isDestination)
|
102
|
-
.map((p) => p.locationTag) ?? [];
|
103
|
-
|
104
|
-
const sourcePartyListFilter = (sourcePartyList: Party) => {
|
105
|
-
const isValid =
|
106
|
-
(sourcePartyList.locationUuid &&
|
107
|
-
operation?.sourceType === 'Location' &&
|
108
|
-
(sourceTags.length === 0 ||
|
109
|
-
(sourcePartyList.tags && sourceTags.some((x) => sourcePartyList.tags.includes(x))))) ||
|
110
|
-
(sourcePartyList.stockSourceUuid && operation?.sourceType === 'Other');
|
111
|
-
return isValid;
|
112
|
-
};
|
113
|
-
|
114
|
-
const destinationPartyListFilter = (destinationPartyList: Party) => {
|
115
|
-
const isValid =
|
116
|
-
(destinationPartyList.locationUuid &&
|
117
|
-
operation?.destinationType === 'Location' &&
|
118
|
-
(destinationTags.length === 0 ||
|
119
|
-
(destinationPartyList.tags && destinationTags.some((x) => destinationPartyList.tags.includes(x))))) ||
|
120
|
-
(destinationPartyList.stockSourceUuid && operation?.destinationType === 'Other');
|
121
|
-
return isValid;
|
122
|
-
};
|
123
|
-
return (
|
124
|
-
<div style={{ margin: '10px' }}>
|
125
|
-
<form className={`${styles.formContainer} ${styles.verticalForm}`}>
|
126
|
-
{!canEdit || operationType === 'stockissue' ? (
|
127
|
-
<>
|
128
|
-
{model?.operationDate && (
|
129
|
-
<TextInput
|
130
|
-
id="operationDateLbl"
|
131
|
-
value={formatForDatePicker(model.operationDate)}
|
132
|
-
readOnly={true}
|
133
|
-
labelText={t('operationDate', 'Operation Date')}
|
134
|
-
/>
|
135
|
-
)}
|
136
|
-
{model?.operationNumber && (
|
137
|
-
<TextInput
|
138
|
-
id="operationNoLbl"
|
139
|
-
value={model?.operationNumber}
|
140
|
-
readOnly={true}
|
141
|
-
labelText={t('operationNumber', 'Operation Number')}
|
142
|
-
/>
|
143
|
-
)}
|
144
|
-
{model?.atLocationName && (
|
145
|
-
<TextInput
|
146
|
-
id="sourceLbl"
|
147
|
-
value={operationType === 'stockissue' ? issueStockOperation.sourceName : model?.sourceName ?? ''}
|
148
|
-
readOnly={true}
|
149
|
-
labelText={t('source', 'Source')}
|
150
|
-
/>
|
151
|
-
)}
|
152
|
-
{model?.destinationName && (
|
153
|
-
<TextInput
|
154
|
-
id="destinationLbl"
|
155
|
-
value={
|
156
|
-
operationType === 'stockissue' ? issueStockOperation.destinationName : model?.destinationName ?? ''
|
157
|
-
}
|
158
|
-
readOnly={true}
|
159
|
-
labelText={t('destination', 'Destination')}
|
160
|
-
/>
|
161
|
-
)}
|
162
|
-
{model?.responsiblePersonGivenName && model?.responsiblePersonFamilyName && (
|
163
|
-
<TextInput
|
164
|
-
id="responsiblePersonLbl"
|
165
|
-
value={`${model.responsiblePersonGivenName} ${model.responsiblePersonFamilyName}`}
|
166
|
-
readOnly={true}
|
167
|
-
labelText={t('responsiblePerson', 'Responsible Person')}
|
168
|
-
/>
|
169
|
-
)}
|
170
|
-
{showReason && model?.reasonName && (
|
171
|
-
<TextInput id="reasonLbl" value={model.reasonName} readOnly={true} labelText={t('reason', 'Reason')} />
|
172
|
-
)}
|
173
|
-
{model?.remarks && (
|
174
|
-
<TextInput id="remarksLbl" value={model.remarks} readOnly={true} labelText={t('remarks', 'Remarks')} />
|
175
|
-
)}
|
176
|
-
{operationType === 'stockissue' && (
|
177
|
-
<div style={{ display: 'flex', flexDirection: 'row-reverse' }}>
|
178
|
-
<Button
|
179
|
-
name="save"
|
180
|
-
type="button"
|
181
|
-
className="submitButton"
|
182
|
-
onClick={handleSubmit(handleSave)}
|
183
|
-
kind="primary"
|
184
|
-
renderIcon={ArrowRight}
|
185
|
-
>
|
186
|
-
{isSaving ? <InlineLoading /> : t('next', 'Next')}
|
187
|
-
</Button>
|
188
|
-
</div>
|
189
|
-
)}
|
190
|
-
</>
|
191
|
-
) : (
|
192
|
-
<>
|
193
|
-
{canEdit && (
|
194
|
-
<Controller
|
195
|
-
control={control}
|
196
|
-
render={({ field: { onChange } }) => (
|
197
|
-
<DatePicker
|
198
|
-
datePickerType="single"
|
199
|
-
maxDate={formatForDatePicker(today())}
|
200
|
-
locale="en"
|
201
|
-
dateFormat={DATE_PICKER_CONTROL_FORMAT}
|
202
|
-
onChange={([newDate]) => {
|
203
|
-
onChange(newDate);
|
204
|
-
}}
|
205
|
-
>
|
206
|
-
<DatePickerInput
|
207
|
-
invalid={!!errors.operationDate}
|
208
|
-
invalidText={errors?.operationDate?.message}
|
209
|
-
id="operationDate"
|
210
|
-
name="operationDate"
|
211
|
-
placeholder={DATE_PICKER_FORMAT}
|
212
|
-
labelText={t('operationDate', 'Operation Date')}
|
213
|
-
defaultValue={formatForDatePicker(model?.operationDate)}
|
214
|
-
/>
|
215
|
-
</DatePicker>
|
216
|
-
)}
|
217
|
-
name="operationDate"
|
218
|
-
/>
|
219
|
-
)}
|
220
|
-
|
221
|
-
{!canEdit && (
|
222
|
-
<>
|
223
|
-
<TextInput
|
224
|
-
id="operationDateLbl"
|
225
|
-
value={formatForDatePicker(model?.operationDate)}
|
226
|
-
readOnly={true}
|
227
|
-
labelText="Operation Date"
|
228
|
-
/>
|
229
|
-
</>
|
230
|
-
)}
|
231
|
-
|
232
|
-
{isEditing && model?.operationNumber && (
|
233
|
-
<TextInput
|
234
|
-
id="operationNoLbl"
|
235
|
-
value={model?.operationNumber}
|
236
|
-
readOnly={true}
|
237
|
-
labelText={'Operation Number'}
|
238
|
-
/>
|
239
|
-
)}
|
240
|
-
|
241
|
-
{canEdit && (operation?.hasSource || model?.atLocationUuid) && (
|
242
|
-
<PartySelector
|
243
|
-
controllerName="sourceUuid"
|
244
|
-
name="sourceUuid"
|
245
|
-
control={control}
|
246
|
-
partyUuid={model?.atLocationUuid}
|
247
|
-
title={
|
248
|
-
operation?.hasDestination || model?.destinationUuid ? t('from', 'From') : t('location', 'Location')
|
249
|
-
}
|
250
|
-
placeholder={
|
251
|
-
operation.hasDestination || model?.destinationUuid
|
252
|
-
? t('chooseASource', 'Choose a source')
|
253
|
-
: t('chooseALocation', 'Choose a location')
|
254
|
-
}
|
255
|
-
invalid={!!errors.sourceUuid}
|
256
|
-
invalidText={errors.sourceUuid && errors?.sourceUuid?.message}
|
257
|
-
parties={sourcePartyList?.filter(sourcePartyListFilter) || []}
|
258
|
-
filterFunction={sourcePartyListFilter}
|
259
|
-
/>
|
260
|
-
)}
|
261
|
-
|
262
|
-
{!canEdit && isEditing && (
|
263
|
-
<PartySelector
|
264
|
-
controllerName="sourceUuid"
|
265
|
-
name="sourceUuid"
|
266
|
-
control={control}
|
267
|
-
partyUuid={model?.atLocationUuid}
|
268
|
-
title={operation?.hasDestination || model?.destinationUuid ? 'From' : 'Location'}
|
269
|
-
placeholder={
|
270
|
-
operation.hasDestination || model?.destinationUuid
|
271
|
-
? t('chooseASource', 'Choose a source')
|
272
|
-
: t('chooseALocation', 'Choose a location')
|
273
|
-
}
|
274
|
-
invalid={!!errors.sourceUuid}
|
275
|
-
invalidText={errors.sourceUuid && errors?.sourceUuid?.message}
|
276
|
-
parties={sourcePartyList?.filter(sourcePartyListFilter) || []}
|
277
|
-
filterFunction={sourcePartyListFilter}
|
278
|
-
/>
|
279
|
-
)}
|
280
|
-
{canEdit && (operation?.hasDestination || model?.destinationUuid) && (
|
281
|
-
<PartySelector
|
282
|
-
controllerName="destinationUuid"
|
283
|
-
name="destinationUuid"
|
284
|
-
control={control}
|
285
|
-
partyUuid={model?.destinationUuid}
|
286
|
-
title={operation?.hasSource || model?.atLocationUuid ? t('to', 'To') : t('location', 'Location')}
|
287
|
-
placeholder={
|
288
|
-
operation?.hasSource || model?.atLocationUuid
|
289
|
-
? t('chooseADestination', 'Choose a destination')
|
290
|
-
: 'Location'
|
291
|
-
}
|
292
|
-
invalid={!!errors.destinationUuid}
|
293
|
-
invalidText={errors.destinationUuid && errors?.destinationUuid?.message}
|
294
|
-
parties={destinationPartyList?.filter(destinationPartyListFilter) || []}
|
295
|
-
filterFunction={destinationPartyListFilter}
|
296
|
-
/>
|
297
|
-
)}
|
298
|
-
|
299
|
-
{!canEdit && isEditing && (
|
300
|
-
<PartySelector
|
301
|
-
controllerName="destinationUuid"
|
302
|
-
name="destinationUuid"
|
303
|
-
control={control}
|
304
|
-
partyUuid={model?.destinationUuid}
|
305
|
-
title={operation?.hasSource || model?.atLocationUuid ? t('to', 'To') : t('location', 'Location')}
|
306
|
-
placeholder={
|
307
|
-
operation?.hasSource || model?.atLocationUuid
|
308
|
-
? t('chooseADestination', 'Choose a destination')
|
309
|
-
: 'Location'
|
310
|
-
}
|
311
|
-
invalid={!!errors.destinationUuid}
|
312
|
-
invalidText={errors.destinationUuid && errors?.destinationUuid?.message}
|
313
|
-
parties={destinationPartyList?.filter(destinationPartyListFilter) || []}
|
314
|
-
filterFunction={destinationPartyListFilter}
|
315
|
-
/>
|
316
|
-
)}
|
317
|
-
|
318
|
-
{canEdit && (
|
319
|
-
<UsersSelector
|
320
|
-
controllerName="responsiblePersonUuid"
|
321
|
-
name="responsiblePersonUuid"
|
322
|
-
control={control}
|
323
|
-
userUuid={model?.responsiblePersonUuid}
|
324
|
-
title={t('responsiblePerson', 'Responsible Person')}
|
325
|
-
placeholder={t('filter', 'Filter ...')}
|
326
|
-
invalid={!!errors.responsiblePersonUuid}
|
327
|
-
invalidText={errors.responsiblePersonUuid && errors?.responsiblePersonUuid?.message}
|
328
|
-
onUserChanged={(user) => {
|
329
|
-
if (user?.uuid === otherUser.uuid) {
|
330
|
-
setIsOtherUser(true);
|
331
|
-
} else {
|
332
|
-
setIsOtherUser(false);
|
333
|
-
}
|
334
|
-
}}
|
335
|
-
/>
|
336
|
-
)}
|
337
|
-
|
338
|
-
{isOtherUser && (
|
339
|
-
<ControlledTextInput
|
340
|
-
id="responsiblePersonOther"
|
341
|
-
name="responsiblePersonOther"
|
342
|
-
control={control}
|
343
|
-
controllerName="responsiblePersonOther"
|
344
|
-
maxLength={255}
|
345
|
-
size={'md'}
|
346
|
-
value={`${model?.responsiblePersonOther ?? ''}`}
|
347
|
-
labelText={t('responsiblePerson', 'Responsible Person')}
|
348
|
-
placeholder={t('pleaseSpecify', 'Please Specify')}
|
349
|
-
invalid={!!errors.responsiblePersonOther}
|
350
|
-
invalidText={errors.responsiblePersonOther && errors?.responsiblePersonOther?.message}
|
351
|
-
/>
|
352
|
-
)}
|
353
|
-
|
354
|
-
{!canEdit && isEditing && (
|
355
|
-
<UsersSelector
|
356
|
-
controllerName="responsiblePersonUuid"
|
357
|
-
name="responsiblePersonUuid"
|
358
|
-
control={control}
|
359
|
-
userUuid={model?.responsiblePersonUuid}
|
360
|
-
title={t('responsiblePerson', 'Responsible Person')}
|
361
|
-
placeholder={t('filter', 'Filter ...')}
|
362
|
-
invalid={!!errors.responsiblePersonUuid}
|
363
|
-
invalidText={errors.responsiblePersonUuid && errors?.responsiblePersonUuid?.message}
|
364
|
-
onUserChanged={(user) => {
|
365
|
-
if (user?.uuid === otherUser.uuid) {
|
366
|
-
setIsOtherUser(true);
|
367
|
-
} else {
|
368
|
-
setIsOtherUser(false);
|
369
|
-
}
|
370
|
-
}}
|
371
|
-
/>
|
372
|
-
)}
|
373
|
-
|
374
|
-
{showReason && canEdit && (
|
375
|
-
<StockOperationReasonSelector
|
376
|
-
controllerName="reasonUuid"
|
377
|
-
name="reasonUuid"
|
378
|
-
control={control}
|
379
|
-
reasonUuid={model?.reasonUuid}
|
380
|
-
placeholder={t('chooseAReason', 'Choose a reason')}
|
381
|
-
title={t('reason', 'Reason')}
|
382
|
-
invalid={!!errors.reasonUuid}
|
383
|
-
invalidText={errors.reasonUuid && errors?.reasonUuid?.message}
|
384
|
-
onReasonChange={(reason) => {
|
385
|
-
setValue('reasonUuid', reason.uuid);
|
386
|
-
}}
|
387
|
-
/>
|
388
|
-
)}
|
389
|
-
|
390
|
-
{showReason && !canEdit && (
|
391
|
-
<TextInput id="reasonUuidLbl" value={model?.reasonName ?? ''} readOnly={true} labelText={'Reason:'} />
|
392
|
-
)}
|
393
|
-
|
394
|
-
<ControlledTextArea
|
395
|
-
id="remarks"
|
396
|
-
name="remarks"
|
397
|
-
control={control}
|
398
|
-
controllerName="remarks"
|
399
|
-
maxLength={255}
|
400
|
-
value={`${model?.remarks ?? ''}`}
|
401
|
-
labelText={t('remarks', 'Remarks')}
|
402
|
-
invalid={!!errors.remarks}
|
403
|
-
invalidText={errors.remarks && errors?.remarks?.message}
|
404
|
-
/>
|
405
|
-
|
406
|
-
<div style={{ display: 'flex', flexDirection: 'row-reverse' }}>
|
407
|
-
<Button
|
408
|
-
name="save"
|
409
|
-
type="button"
|
410
|
-
className="submitButton"
|
411
|
-
onClick={handleSubmit(handleSave)}
|
412
|
-
kind="primary"
|
413
|
-
renderIcon={ArrowRight}
|
414
|
-
>
|
415
|
-
{isSaving ? <InlineLoading /> : t('next', 'Next')}
|
416
|
-
</Button>
|
417
|
-
</div>
|
418
|
-
</>
|
419
|
-
)}
|
420
|
-
</form>
|
421
|
-
</div>
|
422
|
-
);
|
423
|
-
};
|
424
|
-
|
425
|
-
function mapIssueStockLocations(stockOperation) {
|
426
|
-
/** Since we are using requisition information to issue stock,
|
427
|
-
please note that the locations will be inverted: the destination listed on the requisition will become the issuing location.
|
428
|
-
*/
|
429
|
-
const { sourceUuid, sourceName, destinationUuid, destinationName } = stockOperation;
|
430
|
-
return {
|
431
|
-
...stockOperation,
|
432
|
-
sourceUuid: destinationUuid,
|
433
|
-
sourceName: destinationName,
|
434
|
-
destinationUuid: sourceUuid,
|
435
|
-
destinationName: sourceName,
|
436
|
-
};
|
437
|
-
}
|
438
|
-
|
439
|
-
export default BaseOperationDetails;
|