@openmrs/esm-stock-management-app 1.0.1-pre.694 → 1.0.1-pre.706

Sign up to get free protection for your applications and to get access to all the features.
@@ -134,10 +134,10 @@
134
134
  "initial": true,
135
135
  "entry": true,
136
136
  "recorded": false,
137
- "size": 5408005,
137
+ "size": 5408566,
138
138
  "sizes": {
139
139
  "consume-shared": 252,
140
- "javascript": 5386056,
140
+ "javascript": 5386617,
141
141
  "share-init": 252,
142
142
  "runtime": 21445
143
143
  },
@@ -154,7 +154,7 @@
154
154
  "auxiliaryFiles": [
155
155
  "main.js.map"
156
156
  ],
157
- "hash": "d3025a711f4fd2ad",
157
+ "hash": "bde00c76e90fc524",
158
158
  "childrenByOrder": {}
159
159
  },
160
160
  {
@@ -326,9 +326,9 @@
326
326
  "initial": false,
327
327
  "entry": false,
328
328
  "recorded": false,
329
- "size": 11501,
329
+ "size": 11531,
330
330
  "sizes": {
331
- "javascript": 11501
331
+ "javascript": 11531
332
332
  },
333
333
  "names": [],
334
334
  "idHints": [],
@@ -340,7 +340,7 @@
340
340
  "574.js"
341
341
  ],
342
342
  "auxiliaryFiles": [],
343
- "hash": "b881a6484ecb0d98",
343
+ "hash": "882eba03e470bb3e",
344
344
  "childrenByOrder": {}
345
345
  },
346
346
  {
@@ -372,9 +372,9 @@
372
372
  "initial": false,
373
373
  "entry": false,
374
374
  "recorded": false,
375
- "size": 9348,
375
+ "size": 9345,
376
376
  "sizes": {
377
- "javascript": 9348
377
+ "javascript": 9345
378
378
  },
379
379
  "names": [],
380
380
  "idHints": [],
@@ -388,7 +388,7 @@
388
388
  "auxiliaryFiles": [
389
389
  "627.js.map"
390
390
  ],
391
- "hash": "e44bfcef4206b456",
391
+ "hash": "0b31b4561c627de5",
392
392
  "childrenByOrder": {}
393
393
  },
394
394
  {
@@ -607,9 +607,9 @@
607
607
  "initial": false,
608
608
  "entry": false,
609
609
  "recorded": false,
610
- "size": 1749133,
610
+ "size": 1749694,
611
611
  "sizes": {
612
- "javascript": 1748923,
612
+ "javascript": 1749484,
613
613
  "consume-shared": 210
614
614
  },
615
615
  "names": [],
@@ -623,7 +623,7 @@
623
623
  "auxiliaryFiles": [
624
624
  "973.js.map"
625
625
  ],
626
- "hash": "d8fb187fbc310d76",
626
+ "hash": "4e40bb4e6400af3e",
627
627
  "childrenByOrder": {}
628
628
  }
629
629
  ]
package/dist/routes.json CHANGED
@@ -1 +1 @@
1
- {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"fhir2":">=1.2","webservices.rest":"^2.24.0"},"extensions":[{"name":"stock-nav-menu","slot":"stock-sidebar-slot","component":"stockNavMenu","online":true,"offline":true},{"name":"overview-db-link","slot":"stock-page-dashboard-slot","component":"stockOverviewLink","meta":{"name":"overview","slot":"overview-dashboard-slot","title":"overview"},"order":0,"online":true,"offline":true},{"name":"stock-overview-db","slot":"overview-dashboard-slot","component":"stockOverview"},{"name":"operations-db-link","slot":"stock-page-dashboard-slot","component":"stockOperationsLink","meta":{"name":"operations","slot":"operations-dashboard-slot","title":"operations"},"order":2,"online":true,"offline":true},{"name":"stock-operations-db","slot":"operations-dashboard-slot","component":"stockOperations"},{"name":"items-db-link","slot":"stock-page-dashboard-slot","component":"stockItemsLink","meta":{"name":"items","slot":"items-dashboard-slot","title":"items"},"order":1,"online":true,"offline":true},{"name":"stock-items-db","slot":"items-dashboard-slot","component":"stockItems"},{"name":"user-scopes-db-link","slot":"stock-page-dashboard-slot","component":"stockUserScopesLink","meta":{"name":"user-scopes","slot":"user-scopes-dashboard-slot","title":"user-scopes"},"order":3,"online":true,"offline":true},{"name":"stock-user-scopes-db","slot":"user-scopes-dashboard-slot","component":"stockUserScopes"},{"name":"sources-db-link","slot":"stock-page-dashboard-slot","component":"stockSourcesLink","meta":{"name":"sources","slot":"sources-dashboard-slot","title":"Sources"},"order":2,"online":true,"offline":true},{"name":"stock-sources-db","slot":"sources-dashboard-slot","component":"stockSources"},{"name":"locations-db-link","slot":"stock-page-dashboard-slot","component":"stockLocationsLink","meta":{"name":"locations","slot":"locations-dashboard-slot","title":"Locations"},"order":4,"online":true,"offline":true},{"name":"stock-locations-db","slot":"locations-dashboard-slot","component":"stockLocations"},{"name":"reports-db-link","slot":"stock-page-dashboard-slot","component":"stockReportsLink","meta":{"name":"reports","slot":"reports-dashboard-slot","title":"Reports"},"order":5,"online":true,"offline":true},{"name":"stock-reports-db","slot":"reports-dashboard-slot","component":"stockReports"},{"name":"settings-db-link","slot":"stock-page-dashboard-slot","component":"stockSettingsLink","meta":{"name":"settings","slot":"settings-dashboard-slot","title":"Settings"},"order":6,"online":true,"offline":true},{"name":"stock-settings-db","slot":"settings-dashboard-slot","component":"stockSettings"},{"name":"stock-management-admin-card-link","slot":"system-admin-page-card-link-slot","component":"stockManagementAdminCardLink"},{"name":"stock-management-app-menu-item","component":"stockManagementAppMenuItem","slot":"app-menu-item-slot","meta":{"name":" Stock Management"}},{"name":"delete-packaging-unit-button","component":"deletePackagingUnitButton"}],"modals":[{"name":"delete-stock-modal","component":"deleteStockModal"},{"name":"delete-stock-user-scope-modal","component":"deleteUserScopeModal"},{"name":"delete-stock-rule-modal","component":"deleteStockRuleModal"},{"name":"delete-packaging-unit-modal","component":"deletePackagingUnitModal"},{"name":"import-bulk-stock-items","component":"importBulkStockItemsModal"},{"name":"stock-operation-dialog","component":"stockOperationModal"}],"pages":[{"component":"root","route":"stock-management"}],"version":"1.0.1-pre.694"}
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"fhir2":">=1.2","webservices.rest":"^2.24.0"},"extensions":[{"name":"stock-nav-menu","slot":"stock-sidebar-slot","component":"stockNavMenu","online":true,"offline":true},{"name":"overview-db-link","slot":"stock-page-dashboard-slot","component":"stockOverviewLink","meta":{"name":"overview","slot":"overview-dashboard-slot","title":"overview"},"order":0,"online":true,"offline":true},{"name":"stock-overview-db","slot":"overview-dashboard-slot","component":"stockOverview"},{"name":"operations-db-link","slot":"stock-page-dashboard-slot","component":"stockOperationsLink","meta":{"name":"operations","slot":"operations-dashboard-slot","title":"operations"},"order":2,"online":true,"offline":true},{"name":"stock-operations-db","slot":"operations-dashboard-slot","component":"stockOperations"},{"name":"items-db-link","slot":"stock-page-dashboard-slot","component":"stockItemsLink","meta":{"name":"items","slot":"items-dashboard-slot","title":"items"},"order":1,"online":true,"offline":true},{"name":"stock-items-db","slot":"items-dashboard-slot","component":"stockItems"},{"name":"user-scopes-db-link","slot":"stock-page-dashboard-slot","component":"stockUserScopesLink","meta":{"name":"user-scopes","slot":"user-scopes-dashboard-slot","title":"user-scopes"},"order":3,"online":true,"offline":true},{"name":"stock-user-scopes-db","slot":"user-scopes-dashboard-slot","component":"stockUserScopes"},{"name":"sources-db-link","slot":"stock-page-dashboard-slot","component":"stockSourcesLink","meta":{"name":"sources","slot":"sources-dashboard-slot","title":"Sources"},"order":2,"online":true,"offline":true},{"name":"stock-sources-db","slot":"sources-dashboard-slot","component":"stockSources"},{"name":"locations-db-link","slot":"stock-page-dashboard-slot","component":"stockLocationsLink","meta":{"name":"locations","slot":"locations-dashboard-slot","title":"Locations"},"order":4,"online":true,"offline":true},{"name":"stock-locations-db","slot":"locations-dashboard-slot","component":"stockLocations"},{"name":"reports-db-link","slot":"stock-page-dashboard-slot","component":"stockReportsLink","meta":{"name":"reports","slot":"reports-dashboard-slot","title":"Reports"},"order":5,"online":true,"offline":true},{"name":"stock-reports-db","slot":"reports-dashboard-slot","component":"stockReports"},{"name":"settings-db-link","slot":"stock-page-dashboard-slot","component":"stockSettingsLink","meta":{"name":"settings","slot":"settings-dashboard-slot","title":"Settings"},"order":6,"online":true,"offline":true},{"name":"stock-settings-db","slot":"settings-dashboard-slot","component":"stockSettings"},{"name":"stock-management-admin-card-link","slot":"system-admin-page-card-link-slot","component":"stockManagementAdminCardLink"},{"name":"stock-management-app-menu-item","component":"stockManagementAppMenuItem","slot":"app-menu-item-slot","meta":{"name":" Stock Management"}},{"name":"delete-packaging-unit-button","component":"deletePackagingUnitButton"}],"modals":[{"name":"delete-stock-modal","component":"deleteStockModal"},{"name":"delete-stock-user-scope-modal","component":"deleteUserScopeModal"},{"name":"delete-stock-rule-modal","component":"deleteStockRuleModal"},{"name":"delete-packaging-unit-modal","component":"deletePackagingUnitModal"},{"name":"import-bulk-stock-items","component":"importBulkStockItemsModal"},{"name":"stock-operation-dialog","component":"stockOperationModal"}],"pages":[{"component":"root","route":"stock-management"}],"version":"1.0.1-pre.706"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-stock-management-app",
3
- "version": "1.0.1-pre.694",
3
+ "version": "1.0.1-pre.706",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Stock management microfrontend for OpenMRS 3.x",
6
6
  "browser": "dist/openmrs-esm-stock-management-app.js",
@@ -64,7 +64,7 @@ const ImportDialogPopup: React.FC<ImportDialogPopupProps> = ({ closeModal }) =>
64
64
  labelDescription="Only .csv files at 2mb or less"
65
65
  filenameStatus="edit"
66
66
  labelTitle=""
67
- size="small"
67
+ size="sm"
68
68
  onChange={onFileChanged}
69
69
  />
70
70
  </ModalBody>
@@ -0,0 +1,105 @@
1
+ import React from 'react';
2
+ import { render, screen, waitFor } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import ImportDialogPopup from './stock-items-bulk-import.component';
5
+ import { showSnackbar } from '@openmrs/esm-framework';
6
+ import { UploadStockItems } from './stock-items-bulk-import.resource';
7
+
8
+ jest.mock('@openmrs/esm-framework', () => ({
9
+ showSnackbar: jest.fn(),
10
+ }));
11
+
12
+ jest.mock('./stock-items-bulk-import.resource', () => ({
13
+ UploadStockItems: jest.fn(),
14
+ }));
15
+
16
+ describe('ImportDialogPopup', () => {
17
+ const mockCloseModal = jest.fn();
18
+
19
+ beforeEach(() => {
20
+ jest.clearAllMocks();
21
+ });
22
+
23
+ it('renders with initial state and UI elements', () => {
24
+ render(<ImportDialogPopup closeModal={mockCloseModal} />);
25
+
26
+ expect(screen.getByText('Import Stock Items')).toBeInTheDocument();
27
+ expect(screen.getByRole('button', { name: 'Select file' })).toBeInTheDocument();
28
+ expect(screen.getByText('Only .csv files at 2mb or less')).toBeInTheDocument();
29
+ expect(screen.getByRole('button', { name: 'Cancel' })).toBeInTheDocument();
30
+ expect(screen.getByRole('button', { name: 'Upload StockItems' })).toBeInTheDocument();
31
+ });
32
+
33
+ it('allows only CSV files', async () => {
34
+ render(<ImportDialogPopup closeModal={mockCloseModal} />);
35
+
36
+ const fileInput = screen.getByLabelText('Select file') as HTMLInputElement;
37
+ expect(fileInput.accept).toBe('.csv');
38
+ });
39
+
40
+ it('closes modal when cancel button is clicked', async () => {
41
+ render(<ImportDialogPopup closeModal={mockCloseModal} />);
42
+
43
+ const cancelButton = screen.getByRole('button', { name: 'Cancel' });
44
+ await userEvent.click(cancelButton);
45
+
46
+ expect(mockCloseModal).toHaveBeenCalledTimes(1);
47
+ });
48
+
49
+ it('does nothing when upload is clicked without a file', async () => {
50
+ render(<ImportDialogPopup closeModal={mockCloseModal} />);
51
+
52
+ const uploadButton = screen.getByRole('button', { name: 'Upload StockItems' });
53
+ await userEvent.click(uploadButton);
54
+
55
+ expect(UploadStockItems).not.toHaveBeenCalled();
56
+ expect(showSnackbar).not.toHaveBeenCalled();
57
+ expect(mockCloseModal).not.toHaveBeenCalled();
58
+ });
59
+
60
+ it('uploads file successfully and shows success snackbar', async () => {
61
+ (UploadStockItems as jest.Mock).mockResolvedValue({});
62
+ render(<ImportDialogPopup closeModal={mockCloseModal} />);
63
+
64
+ const validFile = new File(['test content'], 'valid.csv', { type: 'text/csv' });
65
+ const fileInput = screen.getByLabelText('Select file') as HTMLInputElement;
66
+ await userEvent.upload(fileInput, validFile);
67
+
68
+ const uploadButton = screen.getByRole('button', { name: 'Upload StockItems' });
69
+ await userEvent.click(uploadButton);
70
+
71
+ await waitFor(() => expect(UploadStockItems).toHaveBeenCalled());
72
+ await waitFor(() =>
73
+ expect(showSnackbar).toHaveBeenCalledWith(
74
+ expect.objectContaining({
75
+ kind: 'success',
76
+ title: 'Uploaded Order',
77
+ }),
78
+ ),
79
+ );
80
+ await waitFor(() => expect(mockCloseModal).toHaveBeenCalledTimes(1));
81
+ });
82
+
83
+ it('shows error snackbar on upload failure', async () => {
84
+ (UploadStockItems as jest.Mock).mockRejectedValue(new Error('Upload failed'));
85
+ render(<ImportDialogPopup closeModal={mockCloseModal} />);
86
+
87
+ const validFile = new File(['test content'], 'valid.csv', { type: 'text/csv' });
88
+ const fileInput = screen.getByLabelText('Select file') as HTMLInputElement;
89
+ await userEvent.upload(fileInput, validFile);
90
+
91
+ const uploadButton = screen.getByRole('button', { name: 'Upload StockItems' });
92
+ await userEvent.click(uploadButton);
93
+
94
+ await waitFor(() => expect(UploadStockItems).toHaveBeenCalled());
95
+ await waitFor(() =>
96
+ expect(showSnackbar).toHaveBeenCalledWith(
97
+ expect.objectContaining({
98
+ kind: 'error',
99
+ title: 'An error occurred uploading stock items',
100
+ }),
101
+ ),
102
+ );
103
+ await waitFor(() => expect(mockCloseModal).not.toHaveBeenCalled());
104
+ });
105
+ });
@@ -133,48 +133,55 @@ const StockOperations: React.FC<StockOperationsTableProps> = () => {
133
133
  );
134
134
 
135
135
  const tableRows = useMemo(() => {
136
- return items?.map((stockOperation, index) => ({
137
- ...stockOperation,
138
- id: stockOperation?.uuid,
139
- key: `key-${stockOperation?.uuid}`,
140
- operationTypeName: `${stockOperation?.operationTypeName}`,
141
- operationNumber: (
142
- <EditStockOperationActionMenu
143
- model={stockOperation}
144
- operations={operations}
145
- operationUuid={operation.uuid}
146
- operationNumber={''}
147
- onEdit={() => handleEditClick(stockOperation, true)}
148
- showIcon={false}
149
- showprops={true}
150
- />
151
- ),
152
- status: `${stockOperation?.status}`,
153
- source: `${stockOperation?.sourceName ?? ''}`,
154
- destination: `${stockOperation?.destinationName ?? ''}`,
155
- location: (
156
- <>
157
- {stockOperation?.sourceName ?? ''}
158
- {stockOperation?.sourceName && stockOperation?.destinationName ? <ArrowRight size={16} /> : ''}{' '}
159
- {stockOperation?.destinationName ?? ''}
160
- </>
161
- ),
162
- responsiblePerson: `${
163
- stockOperation?.responsiblePersonFamilyName ?? stockOperation?.responsiblePersonOther ?? ''
164
- } ${stockOperation?.responsiblePersonGivenName ?? ''}`,
165
- operationDate: formatDisplayDate(stockOperation?.operationDate),
166
- actions: (
167
- <EditStockOperationActionMenu
168
- model={stockOperation}
169
- operations={operations}
170
- operationUuid={operation.uuid}
171
- operationNumber={''}
172
- onEdit={() => handleEditClick(stockOperation, true)}
173
- showIcon={true}
174
- showprops={false}
175
- />
176
- ),
177
- }));
136
+ return items?.map((stockOperation, index) => {
137
+ const commonNames = stockOperation?.stockOperationItems
138
+ ? stockOperation?.stockOperationItems.map((item) => item.commonName).join(', ')
139
+ : '';
140
+
141
+ return {
142
+ ...stockOperation,
143
+ id: stockOperation?.uuid,
144
+ key: `key-${stockOperation?.uuid}`,
145
+ operationTypeName: `${stockOperation?.operationTypeName}`,
146
+ 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
+ />
156
+ ),
157
+ stockOperationItems: commonNames,
158
+ status: `${stockOperation?.status}`,
159
+ source: `${stockOperation?.sourceName ?? ''}`,
160
+ destination: `${stockOperation?.destinationName ?? ''}`,
161
+ location: (
162
+ <>
163
+ {stockOperation?.sourceName ?? ''}
164
+ {stockOperation?.sourceName && stockOperation?.destinationName ? <ArrowRight size={16} /> : ''}{' '}
165
+ {stockOperation?.destinationName ?? ''}
166
+ </>
167
+ ),
168
+ responsiblePerson: `${
169
+ stockOperation?.responsiblePersonFamilyName ?? stockOperation?.responsiblePersonOther ?? ''
170
+ } ${stockOperation?.responsiblePersonGivenName ?? ''}`,
171
+ 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
+ ),
183
+ };
184
+ });
178
185
  }, [items, operations, handleEditClick, operation]);
179
186
 
180
187
  if (isLoading && !filterApplied) {
@@ -8,6 +8,7 @@ export function useStockOperationPages(filter: StockOperationFilter) {
8
8
 
9
9
  const pageSizes = [10, 20, 30, 40, 50];
10
10
  const [currentPageSize, setPageSize] = useState(10);
11
+ console.log(items.results);
11
12
 
12
13
  const { goTo, results: paginatedItems, currentPage } = usePagination(items.results, currentPageSize);
13
14
 
@@ -27,26 +28,31 @@ export function useStockOperationPages(filter: StockOperationFilter) {
27
28
  },
28
29
  {
29
30
  id: 2,
31
+ header: t('stockOperationItems', 'Items'),
32
+ key: 'stockOperationItems',
33
+ },
34
+ {
35
+ id: 3,
30
36
  header: t('status', 'Status'),
31
37
  key: 'status',
32
38
  },
33
39
  {
34
- id: 3,
40
+ id: 4,
35
41
  header: t('location', 'Location'),
36
42
  key: 'location',
37
43
  },
38
44
  {
39
- id: 4,
45
+ id: 5,
40
46
  header: t('responsiblePerson', 'Responsible Person'),
41
47
  key: 'responsiblePerson',
42
48
  },
43
49
  {
44
- id: 5,
50
+ id: 6,
45
51
  header: t('date', 'Date'),
46
52
  key: 'operationDate',
47
53
  },
48
54
  {
49
- id: 6,
55
+ id: 7,
50
56
  key: 'details',
51
57
  },
52
58
  { key: 'actions', header: '' },
@@ -298,5 +298,6 @@
298
298
  "user": "User",
299
299
  "view": "View",
300
300
  "whoIsThePreferredVendor": "Who is the preferred vendor?",
301
- "yes": "Yes"
301
+ "yes": "Yes",
302
+ "stockOperationItems": "Items"
302
303
  }