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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/__mocks__/index.ts +1 -0
  2. package/__mocks__/operation-type.mock.ts +532 -0
  3. package/dist/155.js +1 -0
  4. package/dist/155.js.map +1 -0
  5. package/dist/172.js +1 -1
  6. package/dist/20.js +1 -1
  7. package/dist/290.js +1 -1
  8. package/dist/493.js +2 -0
  9. package/dist/493.js.map +1 -0
  10. package/dist/606.js +1 -1
  11. package/dist/627.js +1 -1
  12. package/dist/{400.js → 914.js} +1 -1
  13. package/dist/914.js.map +1 -0
  14. package/dist/main.js +1 -1
  15. package/dist/main.js.map +1 -1
  16. package/dist/openmrs-esm-stock-management-app.js +1 -1
  17. package/dist/openmrs-esm-stock-management-app.js.buildmanifest.json +81 -57
  18. package/dist/openmrs-esm-stock-management-app.js.map +1 -1
  19. package/dist/routes.json +1 -1
  20. package/package.json +1 -1
  21. package/src/core/utils/utils.ts +29 -0
  22. package/src/index.ts +4 -0
  23. package/src/routes.json +9 -0
  24. package/src/stock-items/add-stock-item/transactions/printout/transactions-stockcard-printout.component.tsx +8 -12
  25. package/src/stock-items/add-stock-item/transactions/transactions.component.tsx +8 -12
  26. package/src/stock-items/stock-items.resource.ts +5 -5
  27. package/src/stock-lookups/stock-lookups.resource.ts +2 -2
  28. package/src/stock-operations/edit-stock-operation/edit-stock-operation-action-menu.component.tsx +41 -16
  29. package/src/stock-operations/{add-stock-operation/received-items.component.tsx → received-items.component.tsx} +1 -1
  30. package/src/stock-operations/stock-operation-reference.component.tsx +64 -0
  31. package/src/stock-operations/stock-operation-status/stock-operation-status-row.tsx +77 -0
  32. package/src/stock-operations/stock-operation-status/stock-operation-status.scss +32 -0
  33. package/src/stock-operations/stock-operation-status/stock-operation-status.tsx +45 -0
  34. package/src/stock-operations/stock-operation-types-selector/stock-operation-types-selector.component.tsx +30 -29
  35. package/src/stock-operations/stock-operation.utils.tsx +16 -79
  36. package/src/stock-operations/stock-operations-dialog/stock-operations-issue-stock-button.component.tsx +27 -39
  37. package/src/stock-operations/stock-operations-dialog/stock-operations-print-button.component.tsx +51 -59
  38. package/src/stock-operations/{stock-item-selector/stock-item-selector.resource.tsx → stock-operations-forms/hooks/useFilterableStockItems.ts} +4 -4
  39. package/src/stock-operations/stock-operations-forms/hooks/useFilteredOperationTypesByRoles.ts +30 -0
  40. package/src/stock-operations/stock-operations-forms/hooks/useOperationTypePermisions.ts +29 -0
  41. package/src/stock-operations/stock-operations-forms/hooks/useParties.ts +73 -0
  42. package/src/stock-operations/{users-selector/users-selector.resource.tsx → stock-operations-forms/hooks/useSearchUser.ts} +9 -7
  43. package/src/stock-operations/{batch-no-selector/batch-no-selector.resource.tsx → stock-operations-forms/hooks/useStockItemBatchNumbers.ts} +3 -3
  44. package/src/stock-operations/stock-operations-forms/hooks/useStockOperationLinks.ts +20 -0
  45. package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.component.tsx +72 -0
  46. package/src/stock-operations/stock-operations-forms/input-components/batch-no-selector.test.tsx +90 -0
  47. package/src/stock-operations/{add-stock-operation/stock-item-search/stock-item-search.scss → stock-operations-forms/input-components/input-components-styles.scss} +2 -2
  48. package/src/stock-operations/stock-operations-forms/input-components/qty-uim-selector.test.tsx +157 -0
  49. package/src/stock-operations/stock-operations-forms/input-components/quantity-uom-selector.component.tsx +53 -0
  50. package/src/stock-operations/stock-operations-forms/input-components/stock-item-search.component.tsx +56 -0
  51. package/src/stock-operations/stock-operations-forms/input-components/stock-operation-reason-selector.component.tsx +59 -0
  52. package/src/stock-operations/stock-operations-forms/input-components/stock-operation-reason-selector.test.tsx +216 -0
  53. package/src/stock-operations/stock-operations-forms/input-components/unique-batch-no-entry-input.component.tsx +59 -0
  54. package/src/stock-operations/stock-operations-forms/input-components/user-selector.test.tsx +110 -0
  55. package/src/stock-operations/stock-operations-forms/input-components/users-selector.component.tsx +111 -0
  56. package/src/stock-operations/stock-operations-forms/step1.test.tsx +303 -0
  57. package/src/stock-operations/stock-operations-forms/step2.test.tsx +250 -0
  58. package/src/stock-operations/stock-operations-forms/step3.test.tsx +223 -0
  59. package/src/stock-operations/stock-operations-forms/steps/base-operation-details-form-step.tsx +241 -0
  60. package/src/stock-operations/stock-operations-forms/steps/quantity-uom-cell.component.tsx +33 -0
  61. package/src/stock-operations/stock-operations-forms/steps/stock-availability-cell.component.tsx +51 -0
  62. package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-batch-no-cell.component.tsx +40 -0
  63. package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-cell.component.tsx +38 -0
  64. package/src/stock-operations/stock-operations-forms/steps/stock-operation-item-expiry-cell.component.tsx +41 -0
  65. package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.component.tsx +281 -0
  66. package/src/stock-operations/stock-operations-forms/steps/stock-operation-items-form-step.scc.scss +64 -0
  67. package/src/stock-operations/stock-operations-forms/steps/stock-operation-submission-form-step.component.tsx +236 -0
  68. package/src/stock-operations/stock-operations-forms/stock-issue-form-initializer-with-related-requisition-operation.component.tsx +55 -0
  69. package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.scss +41 -0
  70. package/src/stock-operations/stock-operations-forms/stock-item-form/stock-item-form.workspace.tsx +197 -0
  71. package/src/stock-operations/stock-operations-forms/stock-operation-form-header.component.tsx +166 -0
  72. package/src/stock-operations/stock-operations-forms/stock-operation-form.component.tsx +200 -0
  73. package/src/stock-operations/stock-operations-forms/stock-operation-form.scss +111 -0
  74. package/src/stock-operations/stock-operations-forms/stock-operation-related-link.component.tsx +45 -0
  75. package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stepper.scss +41 -0
  76. package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stock-operation-stepper.component.tsx +52 -0
  77. package/src/stock-operations/stock-operations-forms/stock-operations-form-utils.ts +32 -0
  78. package/src/stock-operations/stock-operations-table.component.tsx +20 -56
  79. package/src/stock-operations/stock-operations.resource.ts +16 -13
  80. package/src/stock-operations/validation-schema.ts +72 -14
  81. package/dist/400.js.map +0 -1
  82. package/dist/766.js +0 -2
  83. package/dist/766.js.map +0 -1
  84. package/src/stock-operations/add-stock-operation/add-stock-operation.component.tsx +0 -349
  85. package/src/stock-operations/add-stock-operation/add-stock-operation.resource.tsx +0 -27
  86. package/src/stock-operations/add-stock-operation/add-stock-operation.scss +0 -60
  87. package/src/stock-operations/add-stock-operation/add-stock-operation.test.tsx +0 -192
  88. package/src/stock-operations/add-stock-operation/add-stock-operation.utils.tsx +0 -152
  89. package/src/stock-operations/add-stock-operation/add-stock-utils.ts +0 -103
  90. package/src/stock-operations/add-stock-operation/base-operation-details.component.tsx +0 -439
  91. package/src/stock-operations/add-stock-operation/base-operation-details.scss +0 -30
  92. package/src/stock-operations/add-stock-operation/stock-item-search/stock-item-search.component.tsx +0 -70
  93. package/src/stock-operations/add-stock-operation/stock-items-addition-row.component.tsx +0 -360
  94. package/src/stock-operations/add-stock-operation/stock-items-addition-row.resource.tsx +0 -0
  95. package/src/stock-operations/add-stock-operation/stock-items-addition-row.scss +0 -12
  96. package/src/stock-operations/add-stock-operation/stock-items-addition-row.test.tsx +0 -10
  97. package/src/stock-operations/add-stock-operation/stock-items-addition.component.scss +0 -17
  98. package/src/stock-operations/add-stock-operation/stock-items-addition.component.tsx +0 -254
  99. package/src/stock-operations/add-stock-operation/stock-operation-context/useStockOperationContext.tsx +0 -16
  100. package/src/stock-operations/add-stock-operation/stock-operation-reference.component.tsx +0 -39
  101. package/src/stock-operations/add-stock-operation/stock-operation-related-link.component.tsx +0 -38
  102. package/src/stock-operations/add-stock-operation/stock-operation-status.component.tsx +0 -170
  103. package/src/stock-operations/add-stock-operation/stock-operation-submission.component.tsx +0 -189
  104. package/src/stock-operations/add-stock-operation/stock-operation-submission.test.tsx +0 -138
  105. package/src/stock-operations/add-stock-operation/types.ts +0 -55
  106. package/src/stock-operations/add-stock-operation/validationSchema.ts +0 -54
  107. package/src/stock-operations/batch-no-selector/batch-no-selector.component.tsx +0 -114
  108. package/src/stock-operations/batch-no-selector/batch-no-selector.scss +0 -0
  109. package/src/stock-operations/batch-no-selector/batch-no-selector.test.tsx +0 -101
  110. package/src/stock-operations/party-selector/party-selector.component.tsx +0 -59
  111. package/src/stock-operations/qty-uom-selector/qty-uom-selector.component.tsx +0 -65
  112. package/src/stock-operations/qty-uom-selector/qty-uom-selector.resource.tsx +0 -0
  113. package/src/stock-operations/qty-uom-selector/qty-uom-selector.scss +0 -0
  114. package/src/stock-operations/qty-uom-selector/qty-uom-selector.test.tsx +0 -10
  115. package/src/stock-operations/stock-item-selector/stock-item-selector.component.tsx +0 -69
  116. package/src/stock-operations/stock-item-selector/stock-item-selector.scss +0 -0
  117. package/src/stock-operations/stock-item-selector/stock-item-selector.test.tsx +0 -10
  118. package/src/stock-operations/stock-operation-reason-selector/stock-operation-reason-selector.component.tsx +0 -62
  119. package/src/stock-operations/users-selector/users-selector.component.tsx +0 -75
  120. /package/dist/{766.js.LICENSE.txt → 493.js.LICENSE.txt} +0 -0
@@ -0,0 +1,110 @@
1
+ import { fireEvent, render, screen, waitFor } from '@testing-library/react';
2
+ import React from 'react';
3
+ import { useFormContext } from 'react-hook-form';
4
+ import { useUser } from '../../../stock-lookups/stock-lookups.resource';
5
+ import useSearchUser from '../hooks/useSearchUser';
6
+ import UsersSelector from './users-selector.component';
7
+ import { otherUser } from '../../../core/utils/utils';
8
+ import userEvent from '@testing-library/user-event';
9
+
10
+ jest.mock('../hooks/useSearchUser');
11
+ jest.mock('../../../stock-lookups/stock-lookups.resource');
12
+ jest.mock('react-hook-form', () => ({
13
+ useFormContext: jest.fn(),
14
+ Controller: ({ render }) => render({ field: {}, fieldState: {} }),
15
+ }));
16
+ jest.mock('react-i18next', () => ({
17
+ useTranslation: () => ({ t: (key: string) => key }),
18
+ }));
19
+
20
+ const mockUseSearchUser = useSearchUser as jest.Mock;
21
+ const mockUseUser = useUser as jest.Mock;
22
+ const mockUseFormContext = useFormContext as jest.Mock;
23
+
24
+ describe('UsersSelector', () => {
25
+ beforeEach(() => {
26
+ jest.clearAllMocks();
27
+ mockUseFormContext.mockReturnValue({
28
+ control: {},
29
+ watch: jest.fn().mockImplementation((field) => {
30
+ if (field === 'responsiblePersonUuid') return 'responsibleperson.uuid';
31
+ if (field === 'responsiblePersonOther') return 'responsiblepersonother.uuid';
32
+ return '';
33
+ }),
34
+ resetField: jest.fn(),
35
+ });
36
+ });
37
+
38
+ it('renders loading state', async () => {
39
+ mockUseSearchUser.mockReturnValue({ isLoading: true, userList: [], setSearchString: jest.fn() });
40
+ mockUseUser.mockReturnValue({ isLoading: true, data: null, error: null });
41
+
42
+ render(<UsersSelector />);
43
+
44
+ expect(screen.getByRole('progressbar')).toBeInTheDocument();
45
+ });
46
+
47
+ it('renders error state', () => {
48
+ const errorMessage = 'Error message';
49
+ mockUseSearchUser.mockReturnValue({ isLoading: false, userList: [], setSearchString: jest.fn() });
50
+ mockUseUser.mockReturnValue({ isLoading: false, data: null, error: new Error(errorMessage) });
51
+ render(<UsersSelector />);
52
+ expect(screen.getByText('responsiblePersonError')).toBeInTheDocument();
53
+ expect(screen.getByText(errorMessage)).toBeInTheDocument();
54
+ });
55
+
56
+ it('renders ComboBox with user list', async () => {
57
+ mockUseSearchUser.mockReturnValue({
58
+ isLoading: false,
59
+ userList: [
60
+ { uuid: '1', person: { display: 'User 1' } },
61
+ { uuid: '2', person: { display: 'User 2' } },
62
+ ],
63
+ setSearchString: jest.fn(),
64
+ });
65
+
66
+ mockUseUser.mockReturnValue({ isLoading: false, data: null, error: null });
67
+ render(<UsersSelector />);
68
+ expect(screen.getByText('responsiblePerson')).toBeInTheDocument();
69
+ const combobox = screen.getByRole('combobox');
70
+ fireEvent.click(combobox);
71
+ expect(screen.getByText('User 1')).toBeInTheDocument();
72
+ expect(screen.getByText('User 2')).toBeInTheDocument();
73
+ });
74
+
75
+ it('renders TextInput for other user', async () => {
76
+ mockUseSearchUser.mockReturnValue({ isLoading: false, userList: [], setSearchString: jest.fn() });
77
+ mockUseFormContext.mockReturnValue({
78
+ control: {},
79
+ watch: jest.fn().mockImplementation((field) => {
80
+ if (field === 'responsiblePersonUuid') return otherUser.uuid;
81
+ if (field === 'responsiblePersonOther') return '';
82
+ return '';
83
+ }),
84
+ resetField: jest.fn(),
85
+ });
86
+ mockUseUser.mockReturnValue({ isLoading: false, data: null, error: null });
87
+
88
+ render(<UsersSelector />);
89
+ expect(screen.getByRole('textbox')).toBeInTheDocument();
90
+ expect(screen.getByPlaceholderText('pleaseSpecify')).toBeInTheDocument();
91
+ });
92
+
93
+ it('calls setSearchString on input change after delay simulating debounce timout', async () => {
94
+ const setSearchString = jest.fn();
95
+ mockUseSearchUser.mockReturnValue({
96
+ isLoading: false,
97
+ userList: [],
98
+ setSearchString,
99
+ });
100
+
101
+ mockUseUser.mockReturnValue({ isLoading: false, data: null, error: null });
102
+
103
+ render(<UsersSelector />);
104
+ const combobox = screen.getByRole('combobox');
105
+ await userEvent.click(combobox);
106
+ await userEvent.type(combobox, 'test');
107
+ await new Promise((resolve) => setTimeout(resolve, 2000)); // Simulate debounce
108
+ expect(setSearchString).toHaveBeenCalledWith('test');
109
+ });
110
+ });
@@ -0,0 +1,111 @@
1
+ import { ComboBox, InlineNotification, SelectSkeleton } from '@carbon/react';
2
+ import React, { useEffect } from 'react';
3
+ import { Controller, useFormContext } from 'react-hook-form';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { User } from '../../../core/api/types/identity/User';
6
+ import { useDebounce } from '../../../core/hooks/debounce-hook';
7
+ import { otherUser } from '../../../core/utils/utils';
8
+ import { useUser } from '../../../stock-lookups/stock-lookups.resource';
9
+ import useSearchUser from '../hooks/useSearchUser';
10
+ import { Column } from '@carbon/react';
11
+ import { TextInput } from '@carbon/react';
12
+
13
+ const UsersSelector = () => {
14
+ const { isLoading, userList, setSearchString } = useSearchUser();
15
+ const { t } = useTranslation();
16
+ const debouncedSearch = useDebounce((query: string) => {
17
+ setSearchString(query);
18
+ }, 1000);
19
+
20
+ const form = useFormContext<{ responsiblePersonUuid: string; responsiblePersonOther: string }>();
21
+ const observableresponsiblePersonUuid = form.watch('responsiblePersonUuid');
22
+ const observableresponsiblePersonOther = form.watch('responsiblePersonOther');
23
+ const {
24
+ data,
25
+ isLoading: isLoadingUser,
26
+ error: userError,
27
+ } = useUser(observableresponsiblePersonUuid ?? null, 'custom:(uuid,display,person:(uuid,display))');
28
+ useEffect(() => {
29
+ // Whenever person uuid changes and not equal to other person, the other is reset to initial default value
30
+ if (observableresponsiblePersonUuid && observableresponsiblePersonUuid !== otherUser.uuid) {
31
+ form.resetField('responsiblePersonOther');
32
+ }
33
+ }, [observableresponsiblePersonUuid, form]);
34
+
35
+ if (isLoadingUser && observableresponsiblePersonUuid !== otherUser.uuid && observableresponsiblePersonUuid)
36
+ return <SelectSkeleton role="progressbar" />;
37
+
38
+ if (observableresponsiblePersonUuid && observableresponsiblePersonUuid !== otherUser.uuid && userError)
39
+ return (
40
+ <InlineNotification
41
+ lowContrast
42
+ title={t('responsiblePersonError', 'Error loading responsible person')}
43
+ subtitle={userError?.message}
44
+ />
45
+ );
46
+
47
+ return (
48
+ <React.Fragment>
49
+ <Column>
50
+ <Controller
51
+ name={'responsiblePersonUuid'}
52
+ control={form.control}
53
+ render={({ field, fieldState: { error } }) => (
54
+ <ComboBox
55
+ readOnly={field.disabled}
56
+ titleText={t('responsiblePerson', 'Responsible Person')}
57
+ name={'responsiblePersonUuid'}
58
+ id={'responsiblePersonUuid'}
59
+ size={'xl'}
60
+ items={[...(userList || []), otherUser]}
61
+ onChange={(data: { selectedItem: User }) => {
62
+ field.onChange(data.selectedItem?.uuid);
63
+ }}
64
+ initialSelectedItem={
65
+ field.value
66
+ ? field.value === otherUser.uuid
67
+ ? otherUser
68
+ : data
69
+ : observableresponsiblePersonOther && !observableresponsiblePersonUuid
70
+ ? otherUser
71
+ : ''
72
+ }
73
+ itemToString={(item) => item?.person?.display || ''}
74
+ onInputChange={debouncedSearch}
75
+ placeholder={t('filter', 'Filter ...')}
76
+ invalid={error?.message}
77
+ invalidText={error?.message}
78
+ ref={field.ref}
79
+ />
80
+ )}
81
+ />
82
+ </Column>
83
+ {(observableresponsiblePersonUuid === otherUser.uuid ||
84
+ (observableresponsiblePersonOther && !observableresponsiblePersonUuid)) && (
85
+ <Column>
86
+ <Controller
87
+ control={form.control}
88
+ name="responsiblePersonOther"
89
+ render={({ field, fieldState: { error } }) => (
90
+ <TextInput
91
+ {...field}
92
+ readOnly={field.disabled}
93
+ disabled={false}
94
+ id="responsiblePersonOther"
95
+ name="responsiblePersonOther"
96
+ size={'xl'}
97
+ labelText={t('responsiblePerson', 'Responsible Person')}
98
+ placeholder={t('pleaseSpecify', 'Please Specify')}
99
+ invalid={error?.message}
100
+ invalidText={error?.message}
101
+ />
102
+ )}
103
+ />
104
+ </Column>
105
+ )}
106
+ </React.Fragment>
107
+ // {isLoading && <InlineLoading status="active" iconDescription="Searching" description="Searching..." />}
108
+ );
109
+ };
110
+
111
+ export default UsersSelector;
@@ -0,0 +1,303 @@
1
+ import { useConfig } from '@openmrs/esm-framework';
2
+ import { render, screen } from '@testing-library/react';
3
+ import React from 'react';
4
+ import { StockOperationType } from '../../core/api/types/stockOperation/StockOperationType';
5
+ import { useStockOperationTypes } from '../../stock-lookups/stock-lookups.resource';
6
+ import { useStockOperations } from '../stock-operations.resource';
7
+ import useParties from './hooks/useParties';
8
+ import StockOperationForm from './stock-operation-form.component';
9
+ import { MAIN_STORE_LOCATION_TAG } from '../../constants';
10
+ import {
11
+ adjustmentOpeationTypeMock,
12
+ disposalOperationTypeMock,
13
+ openingStockOperationTypeMock,
14
+ receiptOperationTypeMock,
15
+ requisitionOperationTypeMock,
16
+ returnOperationTypeMock,
17
+ stockIssueOperationtypeMock,
18
+ stockTakeOperationTypeMock,
19
+ tranferOutOperationTypeMock,
20
+ } from '../../../__mocks__';
21
+ jest.mock('react-i18next', () => ({
22
+ useTranslation: jest.fn().mockReturnValue({ t: (key) => key }),
23
+ }));
24
+
25
+ jest.mock('@openmrs/esm-framework', () => ({
26
+ ActionMenu: jest.fn(() => null),
27
+ showSnackbar: jest.fn(),
28
+ useDebounce: jest.fn((x) => x),
29
+ getGlobalStore: jest.fn(() => ({
30
+ getState: jest.fn(),
31
+ subscribe: jest.fn(),
32
+ setState: jest.fn(),
33
+ })),
34
+ parseDate: jest.fn((date) => new Date(date)),
35
+ showNotification: jest.fn(),
36
+ usePagination: jest.fn(() => ({ currentPage: 1, setPage: jest.fn() })),
37
+ useSession: jest.fn(() => ({ user: { display: 'Test User' } })),
38
+ useConfig: jest.fn(),
39
+ ErrorState: jest.fn(({ error }: { error: any }) => <div>{error}</div>),
40
+ launchWorkspace: jest.fn(),
41
+ }));
42
+
43
+ jest.mock('../../stock-lookups/stock-lookups.resource', () => ({
44
+ useStockOperationTypes: jest.fn(),
45
+ useUsers: jest.fn().mockReturnValue({ items: { results: [] }, isLoading: false }),
46
+ useUser: jest.fn().mockReturnValue({ data: { display: 'Test User' }, isLoading: false, error: null }),
47
+ useConcept: jest.fn().mockReturnValue({ items: { answers: [] }, isLoading: false, error: null }),
48
+ }));
49
+
50
+ jest.mock('../stock-operations.resource', () => ({
51
+ operationStatusColor: jest.fn(() => 'some-color'),
52
+ getStockOperationLinks: jest.fn(),
53
+ useStockOperations: jest.fn().mockReturnValue({
54
+ items: { results: [] },
55
+ isLoading: false,
56
+ error: null,
57
+ }),
58
+ useStockOperation: jest.fn().mockReturnValue({
59
+ items: undefined,
60
+ isLoading: false,
61
+ error: null,
62
+ }),
63
+ }));
64
+
65
+ jest.mock('./hooks/useParties', () => jest.fn());
66
+
67
+ describe('Stock Operation step 1 (baseoperation details)', () => {
68
+ beforeEach(() => {
69
+ const mockStockOperationTypes = { results: [] };
70
+ (useStockOperationTypes as jest.Mock).mockReturnValue(mockStockOperationTypes);
71
+ (useStockOperations as jest.Mock).mockReturnValue({ items: { results: [] }, isLoading: false, error: null });
72
+ (useConfig as jest.Mock).mockReturnValue({ autoPopulateResponsiblePerson: true });
73
+ });
74
+
75
+ it('should render loading state when loading parties info', async () => {
76
+ (useParties as jest.Mock).mockReturnValue({
77
+ destinationParties: [],
78
+ sourceParties: [],
79
+ isLoading: true,
80
+ error: null,
81
+ sourceTags: [],
82
+ destinationTags: [],
83
+ });
84
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
85
+ expect(screen.getByRole('progressbar')).toBeInTheDocument();
86
+ });
87
+
88
+ it('should render error state when parties loading fails', async () => {
89
+ (useParties as jest.Mock).mockReturnValue({
90
+ destinationParties: [],
91
+ sourceParties: [],
92
+ isLoading: false,
93
+ error: 'error',
94
+ sourceTags: [],
95
+ destinationTags: [],
96
+ });
97
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
98
+ expect(screen.getByText('error')).toBeInTheDocument();
99
+ });
100
+
101
+ it('should have only next btn and not previous btn', async () => {
102
+ (useParties as jest.Mock).mockReturnValue({
103
+ destinationParties: [],
104
+ sourceParties: [],
105
+ isLoading: false,
106
+ error: undefined,
107
+ sourceTags: [],
108
+ destinationTags: [],
109
+ });
110
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
111
+ expect(screen.getByRole('button', { name: /next/i })).toBeInTheDocument();
112
+ expect(screen.queryByRole('button', { name: /previous/i })).not.toBeInTheDocument();
113
+ });
114
+ it('should render operation type in title', async () => {
115
+ (useParties as jest.Mock).mockReturnValue({
116
+ destinationParties: [],
117
+ sourceParties: [],
118
+ isLoading: false,
119
+ error: undefined,
120
+ sourceTags: [],
121
+ destinationTags: [],
122
+ });
123
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
124
+ expect(screen.getByText(`${receiptOperationTypeMock.name} details`)).toBeInTheDocument();
125
+ });
126
+
127
+ it("should render combobox with 'from' name and 'chooseAsource' placeholder for receipt operation", async () => {
128
+ (useParties as jest.Mock).mockReturnValue({
129
+ destinationParties: [],
130
+ sourceParties: [],
131
+ isLoading: false,
132
+ error: undefined,
133
+ sourceTags: [],
134
+ destinationTags: [],
135
+ });
136
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
137
+ const sourceInput = screen.getByRole('combobox', {
138
+ name: (_, element) =>
139
+ element.getAttribute('placeholder') === 'chooseASource' && element.getAttribute('name') === 'sourceUuid',
140
+ });
141
+ expect(sourceInput).toBeInTheDocument();
142
+ expect(screen.getByLabelText('from')).toBeInTheDocument();
143
+ });
144
+ it("should render combobox with 'to' name and defaulted to 'main store' location in receipt operation", async () => {
145
+ (useParties as jest.Mock).mockReturnValue({
146
+ destinationParties: [],
147
+ sourceParties: [],
148
+ isLoading: false,
149
+ error: undefined,
150
+ sourceTags: [],
151
+ destinationTags: [],
152
+ });
153
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
154
+ expect(screen.getByLabelText('to')).toBeInTheDocument();
155
+ });
156
+
157
+ it("should render combobox with 'destinationUuid' name and 'chooseADestination' placeholder", async () => {
158
+ (useParties as jest.Mock).mockReturnValue({
159
+ destinationParties: [],
160
+ sourceParties: [],
161
+ isLoading: false,
162
+ error: undefined,
163
+ sourceTags: [],
164
+ destinationTags: [],
165
+ });
166
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
167
+ expect(
168
+ screen.getByRole('combobox', {
169
+ name: (_, element) =>
170
+ element.getAttribute('placeholder') === 'chooseADestination' &&
171
+ element.getAttribute('name') === 'destinationUuid',
172
+ }),
173
+ ).toBeInTheDocument();
174
+ expect(screen.getByLabelText('to')).toBeInTheDocument();
175
+ });
176
+ it("should render combobox with 'sourceUuid' name and 'chooseALocation' placeholder for disposal opertaion", async () => {
177
+ (useParties as jest.Mock).mockReturnValue({
178
+ destinationParties: [],
179
+ sourceParties: [],
180
+ isLoading: false,
181
+ error: undefined,
182
+ sourceTags: [],
183
+ destinationTags: [],
184
+ });
185
+ render(<StockOperationForm stockOperationType={disposalOperationTypeMock as any} />);
186
+ expect(
187
+ screen.getByRole('combobox', {
188
+ name: (_, element) =>
189
+ element.getAttribute('placeholder') === 'chooseALocation' && element.getAttribute('name') === 'sourceUuid',
190
+ }),
191
+ ).toBeInTheDocument();
192
+ expect(screen.getByLabelText('location')).toBeInTheDocument();
193
+ });
194
+
195
+ it('should not render reason input field for receipt operation', async () => {
196
+ (useParties as jest.Mock).mockReturnValue({
197
+ destinationParties: [],
198
+ sourceParties: [],
199
+ isLoading: false,
200
+ error: undefined,
201
+ sourceTags: [],
202
+ destinationTags: [],
203
+ });
204
+ render(<StockOperationForm stockOperationType={receiptOperationTypeMock as any} />);
205
+ expect(screen.queryByLabelText(/.*reason.*/i)).not.toBeInTheDocument();
206
+ });
207
+ it('should render reason input field for adjustment operation', async () => {
208
+ (useParties as jest.Mock).mockReturnValue({
209
+ destinationParties: [],
210
+ sourceParties: [],
211
+ isLoading: false,
212
+ error: undefined,
213
+ sourceTags: [],
214
+ destinationTags: [],
215
+ });
216
+ render(<StockOperationForm stockOperationType={adjustmentOpeationTypeMock as any} />);
217
+ expect(screen.getByLabelText(/.*reason.*/i)).toBeInTheDocument();
218
+ });
219
+ it('should not render reason input field for opening stock operation', async () => {
220
+ (useParties as jest.Mock).mockReturnValue({
221
+ destinationParties: [],
222
+ sourceParties: [],
223
+ isLoading: false,
224
+ error: undefined,
225
+ sourceTags: [],
226
+ destinationTags: [],
227
+ });
228
+ render(<StockOperationForm stockOperationType={openingStockOperationTypeMock as any} />);
229
+ expect(screen.queryByLabelText(/.*reason.*/i)).not.toBeInTheDocument();
230
+ });
231
+ it('should not render reason input field for requisition operation', async () => {
232
+ (useParties as jest.Mock).mockReturnValue({
233
+ destinationParties: [],
234
+ sourceParties: [],
235
+ isLoading: false,
236
+ error: undefined,
237
+ sourceTags: [],
238
+ destinationTags: [],
239
+ });
240
+ render(<StockOperationForm stockOperationType={requisitionOperationTypeMock as any} />);
241
+ expect(screen.queryByLabelText(/.*reason.*/i)).not.toBeInTheDocument();
242
+ });
243
+ it('should not render reason input field for return operation', async () => {
244
+ (useParties as jest.Mock).mockReturnValue({
245
+ destinationParties: [],
246
+ sourceParties: [],
247
+ isLoading: false,
248
+ error: undefined,
249
+ sourceTags: [],
250
+ destinationTags: [],
251
+ });
252
+ render(<StockOperationForm stockOperationType={returnOperationTypeMock as any} />);
253
+ expect(screen.queryByLabelText(/.*reason.*/i)).not.toBeInTheDocument();
254
+ });
255
+ it('should not render reason input field for issue operation', async () => {
256
+ (useParties as jest.Mock).mockReturnValue({
257
+ destinationParties: [],
258
+ sourceParties: [],
259
+ isLoading: false,
260
+ error: undefined,
261
+ sourceTags: [],
262
+ destinationTags: [],
263
+ });
264
+ render(<StockOperationForm stockOperationType={stockIssueOperationtypeMock as any} />);
265
+ expect(screen.queryByLabelText(/.*reason.*/i)).not.toBeInTheDocument();
266
+ });
267
+ it('should not render reason input field for tranfer out operation', async () => {
268
+ (useParties as jest.Mock).mockReturnValue({
269
+ destinationParties: [],
270
+ sourceParties: [],
271
+ isLoading: false,
272
+ error: undefined,
273
+ sourceTags: [],
274
+ destinationTags: [],
275
+ });
276
+ render(<StockOperationForm stockOperationType={tranferOutOperationTypeMock as any} />);
277
+ expect(screen.queryByLabelText(/.*reason.*/i)).not.toBeInTheDocument();
278
+ });
279
+ it('should render reason input field for disposal operation', async () => {
280
+ (useParties as jest.Mock).mockReturnValue({
281
+ destinationParties: [],
282
+ sourceParties: [],
283
+ isLoading: false,
284
+ error: undefined,
285
+ sourceTags: [],
286
+ destinationTags: [],
287
+ });
288
+ render(<StockOperationForm stockOperationType={disposalOperationTypeMock as any} />);
289
+ expect(screen.getByLabelText(/.*reason.*/i)).toBeInTheDocument();
290
+ });
291
+ it('should render reason input field for stock take operation', async () => {
292
+ (useParties as jest.Mock).mockReturnValue({
293
+ destinationParties: [],
294
+ sourceParties: [],
295
+ isLoading: false,
296
+ error: undefined,
297
+ sourceTags: [],
298
+ destinationTags: [],
299
+ });
300
+ render(<StockOperationForm stockOperationType={stockTakeOperationTypeMock as any} />);
301
+ expect(screen.getByLabelText(/.*reason.*/i)).toBeInTheDocument();
302
+ });
303
+ });