@openmrs/esm-stock-management-app 3.0.1-pre.818 → 3.0.1-pre.827

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 (47) hide show
  1. package/dist/10.js +1 -0
  2. package/dist/10.js.map +1 -0
  3. package/dist/165.js +1 -1
  4. package/dist/165.js.map +1 -1
  5. package/dist/20.js +1 -1
  6. package/dist/20.js.map +1 -1
  7. package/dist/642.js +1 -0
  8. package/dist/642.js.map +1 -0
  9. package/dist/675.js +1 -0
  10. package/dist/675.js.map +1 -0
  11. package/dist/{880.js → 727.js} +1 -1
  12. package/dist/727.js.map +1 -0
  13. package/dist/780.js +1 -0
  14. package/dist/780.js.map +1 -0
  15. package/dist/main.js +1 -1
  16. package/dist/main.js.map +1 -1
  17. package/dist/openmrs-esm-stock-management-app.js +1 -1
  18. package/dist/openmrs-esm-stock-management-app.js.buildmanifest.json +129 -56
  19. package/dist/openmrs-esm-stock-management-app.js.map +1 -1
  20. package/dist/routes.json +1 -1
  21. package/package.json +1 -1
  22. package/src/index.ts +8 -0
  23. package/src/routes.json +14 -0
  24. package/src/stock-items/add-stock-item/add-stock-action-button.component.tsx +2 -3
  25. package/src/stock-items/add-stock-item/add-stock-item.component.tsx +29 -20
  26. package/src/stock-items/add-stock-item/add-stock-item.scss +22 -3
  27. package/src/stock-items/add-stock-item/add-stock-item.test.tsx +11 -11
  28. package/src/stock-items/add-stock-item/packaging-units/packaging-units.component.tsx +9 -10
  29. package/src/stock-items/add-stock-item/packaging-units/packaging-units.resource.tsx +1 -1
  30. package/src/stock-items/add-stock-item/stock-item-details/stock-item-details.component.tsx +226 -214
  31. package/src/stock-items/add-stock-item/stock-item-details/stock-item-details.resource.tsx +7 -2
  32. package/src/stock-items/add-stock-item/stock-item-rules/add-stock-rule-button.component.tsx +6 -4
  33. package/src/stock-items/add-stock-item/stock-item-rules/add-stock-rules.component.tsx +162 -166
  34. package/src/stock-items/add-stock-item/stock-item-rules/add-stock-rules.scss +19 -11
  35. package/src/stock-items/add-stock-item/stock-item-rules/edit-stock-rule.component.tsx +8 -5
  36. package/src/stock-items/add-stock-item/transactions/printout/transactions-print-action.component.tsx +66 -3
  37. package/src/stock-items/add-stock-item/transactions/transactions.component.tsx +82 -71
  38. package/src/stock-items/add-stock-item/transactions/transactions.resource.tsx +7 -1
  39. package/src/stock-items/edit-stock-item/edit-stock-item-action-menu.component.tsx +2 -2
  40. package/src/stock-items/stock-item.utils.tsx +7 -50
  41. package/src/stock-items/stock-items-table.component.tsx +2 -2
  42. package/src/stock-items/stock-items-table.test.tsx +28 -23
  43. package/src/stock-items/stock-items.resource.ts +7 -5
  44. package/src/stock-operations/stock-operations-forms/stock-operation-stepper/stock-operation-stepper.component.tsx +1 -0
  45. package/dist/600.js +0 -1
  46. package/dist/600.js.map +0 -1
  47. package/dist/880.js.map +0 -1
@@ -1,8 +1,7 @@
1
1
  import { Button } from '@carbon/react';
2
+ import { launchWorkspace } from '@openmrs/esm-framework';
2
3
  import React, { useCallback } from 'react';
3
4
  import { useTranslation } from 'react-i18next';
4
- import { launchOverlay } from '../../../core/components/overlay/hook';
5
- import StockRulesAddOrUpdate from './add-stock-rules.component';
6
5
 
7
6
  interface AddStockRuleActionButtonProps {
8
7
  stockItemUuid: string;
@@ -12,8 +11,11 @@ const AddStockRuleActionButton: React.FC<AddStockRuleActionButtonProps> = ({ sto
12
11
  const { t } = useTranslation();
13
12
 
14
13
  const handleClick = useCallback(() => {
15
- launchOverlay('Add Stock Rule', <StockRulesAddOrUpdate stockItemUuid={stockItemUuid} />);
16
- }, [stockItemUuid]);
14
+ launchWorkspace('stock-item-rules-form-workspace', {
15
+ workspaceTitle: t('addStockRule', 'Add Stock Rule'),
16
+ stockItemUuid,
17
+ });
18
+ }, [stockItemUuid, t]);
17
19
 
18
20
  return (
19
21
  <Button onClick={handleClick} size="md" kind="primary">
@@ -1,33 +1,30 @@
1
1
  import {
2
- ModalHeader,
3
- ModalBody,
4
- ModalFooter,
5
2
  Button,
3
+ ButtonSet,
4
+ Checkbox,
5
+ CheckboxGroup,
6
6
  Form,
7
+ FormGroup,
7
8
  Select,
8
- TextInput,
9
9
  SelectItem,
10
- FormGroup,
11
- Checkbox,
12
- CheckboxGroup,
10
+ TextInput,
13
11
  } from '@carbon/react';
14
- import React, { type ChangeEvent, useCallback, useState, useEffect } from 'react';
15
- import styles from './add-stock-rules.scss';
16
- import { useRoles, useStockTagLocations } from '../../../stock-lookups/stock-lookups.resource';
17
- import { createOrUpdateStockRule } from './stock-rules.resource';
18
- import { type StockRule } from '../../../core/api/types/stockItem/StockRule';
19
- import { showSnackbar } from '@openmrs/esm-framework';
12
+ import { type DefaultWorkspaceProps, showSnackbar } from '@openmrs/esm-framework';
13
+ import React, { type ChangeEvent, useCallback, useEffect, useState } from 'react';
20
14
  import { useTranslation } from 'react-i18next';
21
- import { closeOverlay } from '../../../core/components/overlay/hook';
22
15
  import { ResourceRepresentation } from '../../../core/api/api';
16
+ import { type StockRule } from '../../../core/api/types/stockItem/StockRule';
17
+ import { useRoles, useStockTagLocations } from '../../../stock-lookups/stock-lookups.resource';
23
18
  import { type StockItemInventoryFilter, useStockItemPackagingUOMs } from '../../stock-items.resource';
19
+ import styles from './add-stock-rules.scss';
20
+ import { createOrUpdateStockRule } from './stock-rules.resource';
24
21
 
25
- interface AddStockRuleProps {
22
+ interface AddStockRuleProps extends Partial<DefaultWorkspaceProps> {
26
23
  model?: StockRule;
27
24
  stockItemUuid?: string;
28
25
  }
29
26
 
30
- const StockRulesAddOrUpdate: React.FC<AddStockRuleProps> = ({ model, stockItemUuid }) => {
27
+ const StockRulesAddOrUpdate: React.FC<AddStockRuleProps> = ({ model, stockItemUuid, closeWorkspace }) => {
31
28
  const { t } = useTranslation();
32
29
 
33
30
  const [stockItemFilter, setStockItemFilter] = useState<StockItemInventoryFilter>({
@@ -99,7 +96,7 @@ const StockRulesAddOrUpdate: React.FC<AddStockRuleProps> = ({ model, stockItemUu
99
96
  const selectedQuantityUnit = dispensingUnits?.results.find((x) => x.uuid === evt.target.value);
100
97
  setFormModel({
101
98
  ...formModel,
102
- stockItemPackagingUOMUuid: selectedQuantityUnit.uuid,
99
+ stockItemPackagingUOMUuid: selectedQuantityUnit?.uuid,
103
100
  });
104
101
  };
105
102
 
@@ -142,7 +139,7 @@ const StockRulesAddOrUpdate: React.FC<AddStockRuleProps> = ({ model, stockItemUu
142
139
  kind: 'success',
143
140
  subtitle: t('stockRuleAddedSuccessfully', 'Stock Rule Added Successfully'),
144
141
  });
145
- closeOverlay();
142
+ closeWorkspace?.();
146
143
  },
147
144
  (error) => {
148
145
  showSnackbar({
@@ -155,179 +152,178 @@ const StockRulesAddOrUpdate: React.FC<AddStockRuleProps> = ({ model, stockItemUu
155
152
  )
156
153
  .catch();
157
154
  },
158
- [formModel, model, t, stockItemUuid],
155
+ [formModel, model, t, stockItemUuid, closeWorkspace],
159
156
  );
160
157
 
161
158
  return (
162
- <div>
163
- <Form onSubmit={onFormSubmit}>
164
- <ModalHeader />
165
- <ModalBody>
166
- <FormGroup>
167
- <section className={styles.section}>
168
- <section className={styles.section}>
169
- <Select
170
- name="location"
171
- className="select-field"
172
- labelText={t('location', 'Location')}
173
- id="location"
174
- value={formModel?.locationUuid ? formModel.locationUuid : ''}
175
- onChange={onLocationChange}
176
- >
177
- <SelectItem disabled hidden value="" text={t('chooseLocation', 'Choose the location')} />
178
- {stockLocations?.map((location) => {
179
- return <SelectItem key={location.id} value={location.id} text={location.name} />;
180
- })}
181
- </Select>
182
- </section>
183
-
184
- <section className={styles.section}>
185
- <TextInput
186
- id="name"
187
- type="text"
188
- labelText={t('name', 'Rule Name')}
189
- size="md"
190
- onChange={onNameChanged}
191
- value={model?.name}
192
- placeholder="e.g Panado Alert"
193
- />
194
- </section>
195
-
196
- <section className={styles.section}>
197
- <Select
198
- name="quantityUnit"
199
- className="select-field"
200
- labelText={t('quantityUnit', 'Quantity Unit')}
201
- id="quantityUnit"
202
- value={formModel?.stockItemPackagingUOMUuid ? formModel.stockItemPackagingUOMUuid : ''}
203
- onChange={onQuantityUnitChange}
204
- >
205
- <SelectItem disabled hidden value="" text={t('chooseQuantityUnit', 'Choose the Unit of Quantity')} />
206
- {dispensingUnits?.results.map((stockItemPackagingUOMUuid) => {
207
- return (
208
- <SelectItem
209
- key={stockItemPackagingUOMUuid.uuid}
210
- value={stockItemPackagingUOMUuid.uuid}
211
- text={stockItemPackagingUOMUuid.packagingUomName}
212
- />
213
- );
214
- })}
215
- </Select>
216
- </section>
217
-
218
- <section className={styles.section}>
219
- <TextInput
220
- id="quantity"
221
- type="number"
222
- labelText={t('quantity', 'Quantity Threshold')}
223
- size="md"
224
- onChange={onQuantityChanged}
225
- value={model?.quantity}
226
- placeholder="e.g 30 Boxes"
227
- />
228
- </section>
229
- </section>
230
- </FormGroup>
231
-
232
- <FormGroup>
159
+ <Form onSubmit={onFormSubmit} className={styles.formContainer}>
160
+ <div>
161
+ <FormGroup>
162
+ <section className={styles.section}>
233
163
  <section className={styles.section}>
234
164
  <Select
235
- name="alertRole"
165
+ name="location"
236
166
  className="select-field"
237
- labelText={t('alertRole', 'Alert Role')}
238
- id="alertRole"
239
- value={formModel?.alertRole ? formModel.alertRole : ''}
240
- onChange={onAlertRoleChange}
167
+ labelText={t('location', 'Location')}
168
+ id="location"
169
+ value={formModel?.locationUuid ? formModel.locationUuid : ''}
170
+ onChange={onLocationChange}
241
171
  >
242
- <SelectItem disabled hidden value="" text={t('chooseAlertRole', 'Choose an Alert Role')} />
243
- {rolesData?.results?.map((alertRole) => {
244
- return <SelectItem key={alertRole.display} value={alertRole.display} text={alertRole.display} />;
172
+ <SelectItem disabled hidden value="" text={t('chooseLocation', 'Choose the location')} />
173
+ {stockLocations?.map((location) => {
174
+ return <SelectItem key={location.id} value={location.id} text={location.name} />;
245
175
  })}
246
176
  </Select>
247
177
  </section>
178
+
179
+ <section className={styles.section}>
180
+ <TextInput
181
+ id="name"
182
+ type="text"
183
+ labelText={t('name', 'Rule Name')}
184
+ size="md"
185
+ onChange={onNameChanged}
186
+ value={model?.name}
187
+ placeholder="e.g Panado Alert"
188
+ />
189
+ </section>
190
+
248
191
  <section className={styles.section}>
249
192
  <Select
250
- name="mailRole"
193
+ name="quantityUnit"
251
194
  className="select-field"
252
- labelText={t('mailRole', 'Mail Role')}
253
- id="mailRole"
254
- value={formModel?.mailRole ? formModel.mailRole : ''}
255
- onChange={onMailRoleChange}
195
+ labelText={t('quantityUnit', 'Quantity Unit')}
196
+ id="quantityUnit"
197
+ value={formModel?.stockItemPackagingUOMUuid ? formModel.stockItemPackagingUOMUuid : ''}
198
+ onChange={onQuantityUnitChange}
256
199
  >
257
- <SelectItem disabled hidden value="" text={t('chooseMailRole', 'Choose a Mail Role')} />
258
- {rolesData?.results?.map((mailRole) => {
259
- return <SelectItem key={mailRole.display} value={mailRole.display} text={mailRole.display} />;
200
+ <SelectItem disabled hidden value="" text={t('chooseQuantityUnit', 'Choose the Unit of Quantity')} />
201
+ {dispensingUnits?.results?.map((stockItemPackagingUOMUuid) => {
202
+ return (
203
+ <SelectItem
204
+ key={stockItemPackagingUOMUuid.uuid}
205
+ value={stockItemPackagingUOMUuid.uuid}
206
+ text={stockItemPackagingUOMUuid.packagingUomName}
207
+ />
208
+ );
260
209
  })}
261
210
  </Select>
262
211
  </section>
212
+
263
213
  <section className={styles.section}>
264
214
  <TextInput
265
- id="evaluationFrequency"
215
+ id="quantity"
266
216
  type="number"
267
- labelText={t('evaluationFrequency', 'Frequency Check (Minutes)')}
217
+ labelText={t('quantity', 'Quantity Threshold')}
268
218
  size="md"
269
- onChange={onEvaluationFrequencyChanged}
270
- value={model?.evaluationFrequency}
271
- placeholder="e.g 30 Minutes"
272
- />
273
- <TextInput
274
- id="actionFrequency"
275
- type="number"
276
- labelText={t('actionFrequency', 'Notification Frequency (Minutes)')}
277
- size="md"
278
- onChange={onActionFrequencyChanged}
279
- value={model?.actionFrequency}
280
- placeholder="e.g 3600 Minutes"
219
+ onChange={onQuantityChanged}
220
+ value={model?.quantity}
221
+ placeholder="e.g 30 Boxes"
281
222
  />
282
223
  </section>
283
- </FormGroup>
224
+ </section>
225
+ </FormGroup>
284
226
 
285
- <div
286
- style={{
287
- display: 'grid',
288
- gridTemplateColumns: '1fr 1fr',
289
- justifyContent: 'center',
290
- }}
291
- >
292
- <FormGroup className="clear-margin-bottom">
293
- <CheckboxGroup className={styles.checkboxGrid}>
294
- <Checkbox
295
- onChange={onEnabledChanged}
296
- checked={formModel?.enabled}
297
- labelText={`Enabled ?`}
298
- value={model?.enabled}
299
- id="chk-ruleEnabled"
300
- />
301
- </CheckboxGroup>
302
- </FormGroup>
303
- <FormGroup className="clear-margin-bottom">
304
- <CheckboxGroup className={styles.checkboxGrid}>
305
- <Checkbox
306
- onChange={onAppliesToChildrenChanged}
307
- name="appliesToChildren"
308
- checked={formModel?.enableDescendants}
309
- value={model?.enableDescendants}
310
- labelText={`Applies to child locations?`}
311
- id="chk-ruleAppliesToChildren"
312
- />
313
- </CheckboxGroup>
314
- </FormGroup>
315
- </div>
227
+ <FormGroup>
228
+ <section className={styles.section}>
229
+ <Select
230
+ name="alertRole"
231
+ className="select-field"
232
+ labelText={t('alertRole', 'Alert Role')}
233
+ id="alertRole"
234
+ value={formModel?.alertRole ? formModel.alertRole : ''}
235
+ onChange={onAlertRoleChange}
236
+ >
237
+ <SelectItem disabled hidden value="" text={t('chooseAlertRole', 'Choose an Alert Role')} />
238
+ {rolesData?.results?.map((alertRole) => {
239
+ return <SelectItem key={alertRole.display} value={alertRole.display} text={alertRole.display} />;
240
+ })}
241
+ </Select>
242
+ </section>
243
+ <section className={styles.section}>
244
+ <Select
245
+ name="mailRole"
246
+ className="select-field"
247
+ labelText={t('mailRole', 'Mail Role')}
248
+ id="mailRole"
249
+ value={formModel?.mailRole ? formModel.mailRole : ''}
250
+ onChange={onMailRoleChange}
251
+ >
252
+ <SelectItem disabled hidden value="" text={t('chooseMailRole', 'Choose a Mail Role')} />
253
+ {rolesData?.results?.map((mailRole) => {
254
+ return <SelectItem key={mailRole.display} value={mailRole.display} text={mailRole.display} />;
255
+ })}
256
+ </Select>
257
+ </section>
258
+ <section className={styles.section}>
259
+ <TextInput
260
+ id="evaluationFrequency"
261
+ type="number"
262
+ labelText={t('evaluationFrequency', 'Frequency Check (Minutes)')}
263
+ size="md"
264
+ onChange={onEvaluationFrequencyChanged}
265
+ value={model?.evaluationFrequency}
266
+ placeholder="e.g 30 Minutes"
267
+ />
268
+ <TextInput
269
+ id="actionFrequency"
270
+ type="number"
271
+ labelText={t('actionFrequency', 'Notification Frequency (Minutes)')}
272
+ size="md"
273
+ onChange={onActionFrequencyChanged}
274
+ value={model?.actionFrequency}
275
+ placeholder="e.g 3600 Minutes"
276
+ />
277
+ </section>
278
+ </FormGroup>
279
+
280
+ <div
281
+ style={{
282
+ display: 'grid',
283
+ gridTemplateColumns: '1fr 1fr',
284
+ justifyContent: 'center',
285
+ }}
286
+ >
287
+ <FormGroup className="clear-margin-bottom">
288
+ <CheckboxGroup className={styles.checkboxGrid}>
289
+ <Checkbox
290
+ onChange={onEnabledChanged}
291
+ checked={formModel?.enabled}
292
+ labelText={`Enabled ?`}
293
+ value={model?.enabled}
294
+ id="chk-ruleEnabled"
295
+ />
296
+ </CheckboxGroup>
297
+ </FormGroup>
298
+ <FormGroup className="clear-margin-bottom">
299
+ <CheckboxGroup className={styles.checkboxGrid}>
300
+ <Checkbox
301
+ onChange={onAppliesToChildrenChanged}
302
+ name="appliesToChildren"
303
+ checked={formModel?.enableDescendants}
304
+ value={model?.enableDescendants}
305
+ labelText={`Applies to child locations?`}
306
+ id="chk-ruleAppliesToChildren"
307
+ />
308
+ </CheckboxGroup>
309
+ </FormGroup>
310
+ </div>
316
311
 
317
- <div>
318
- This stock rule will be evaluated by checking if the stock quantities have lowered to the threshold or below
319
- and a notification will be sent to the personnel with the specified role in the given location. The
320
- notification will only be sent once per specified notification frequency.
321
- </div>
322
- </ModalBody>
323
- <ModalFooter>
324
- <Button kind="secondary" onClick={closeOverlay}>
325
- {t('cancel', 'Cancel')}
326
- </Button>
327
- <Button type="submit">{t('save', 'Save')}</Button>
328
- </ModalFooter>
329
- </Form>
330
- </div>
312
+ <div>
313
+ This stock rule will be evaluated by checking if the stock quantities have lowered to the threshold or below
314
+ and a notification will be sent to the personnel with the specified role in the given location. The
315
+ notification will only be sent once per specified notification frequency.
316
+ </div>
317
+ </div>
318
+ <ButtonSet className={styles.buttonSet}>
319
+ <Button kind="secondary" onClick={closeWorkspace} className={styles.button}>
320
+ {t('cancel', 'Cancel')}
321
+ </Button>
322
+ <Button type="submit" className={styles.button}>
323
+ {t('save', 'Save')}
324
+ </Button>
325
+ </ButtonSet>
326
+ </Form>
331
327
  );
332
328
  };
333
329
 
@@ -1,17 +1,25 @@
1
- @use '@carbon/styles/scss/spacing';
2
- @use '@carbon/styles/scss/type';
3
- @use '@openmrs/esm-styleguide/src/vars' as *;
1
+ @use '@carbon/type';
2
+ @use '@carbon/layout';
3
+ @use '@carbon/colors';
4
4
 
5
- .section {
6
- margin: spacing.$spacing-03;
5
+ .formContainer {
6
+ display: flex;
7
+ flex-direction: column;
8
+ justify-content: space-between;
9
+ width: 100%;
10
+ height: 100%;
11
+ padding: layout.$spacing-03;
7
12
  }
8
13
 
9
- .sectionTitle {
10
- @include type.type-style('heading-compact-02');
11
- color: $text-02;
12
- margin-bottom: spacing.$spacing-04;
14
+ .button {
15
+ display: flex;
16
+ align-content: flex-start;
17
+ align-items: baseline;
18
+ min-width: 50%;
13
19
  }
14
20
 
15
- .modalBody {
16
- padding-bottom: spacing.$spacing-05;
21
+ .buttonSet {
22
+ display: flex;
23
+ justify-content: space-between;
24
+ width: 100%;
17
25
  }
@@ -1,10 +1,9 @@
1
- import React, { useCallback } from 'react';
2
1
  import { Button } from '@carbon/react';
3
2
  import { Edit } from '@carbon/react/icons';
3
+ import React, { useCallback } from 'react';
4
4
 
5
+ import { launchWorkspace } from '@openmrs/esm-framework';
5
6
  import { useTranslation } from 'react-i18next';
6
- import { launchOverlay } from '../../../core/components/overlay/hook';
7
- import StockRulesAddOrUpdate from './add-stock-rules.component';
8
7
  import { type StockRule } from '../../../core/api/types/stockItem/StockRule';
9
8
 
10
9
  interface EditStockRulesActionMenuProps {
@@ -15,8 +14,12 @@ interface EditStockRulesActionMenuProps {
15
14
  const EditStockRuleActionsMenu: React.FC<EditStockRulesActionMenuProps> = ({ data, stockItemUuid }) => {
16
15
  const { t } = useTranslation();
17
16
  const handleClick = useCallback(() => {
18
- launchOverlay('Edit Stock Rule', <StockRulesAddOrUpdate model={data} stockItemUuid={data.stockItemUuid} />);
19
- }, [data]);
17
+ launchWorkspace('stock-item-rules-form-workspace', {
18
+ workspaceTitle: t('editStockRule', 'Edit Stock Rule'),
19
+ stockItemUuid,
20
+ model: data,
21
+ });
22
+ }, [data, t, stockItemUuid]);
20
23
 
21
24
  return (
22
25
  <Button
@@ -2,7 +2,7 @@ import React, { useEffect, useMemo, useState } from 'react';
2
2
  import { Button, Stack, ComboButton, MenuItem } from '@carbon/react';
3
3
  import { Printer } from '@carbon/react/icons';
4
4
  import { useTranslation } from 'react-i18next';
5
- import { useStockItem } from '../../../stock-items.resource';
5
+ import { useStockItem, useStockItemInventory } from '../../../stock-items.resource';
6
6
  import { showModal, useConfig } from '@openmrs/esm-framework';
7
7
  import { type ConfigObject } from '../../../../config-schema';
8
8
  import styles from './printable-transaction.scss';
@@ -13,9 +13,10 @@ type Props = {
13
13
  itemUuid: string;
14
14
  columns: any;
15
15
  data: any;
16
+ filter?: StockItemInventoryFilter;
16
17
  };
17
18
 
18
- const TransactionsPrintAction: React.FC<Props> = ({ columns, data, itemUuid }) => {
19
+ const TransactionsPrintAction: React.FC<Props> = ({ columns, data, itemUuid, filter }) => {
19
20
  const { t } = useTranslation();
20
21
 
21
22
  const { enablePrintButton } = useConfig<ConfigObject>();
@@ -27,8 +28,66 @@ const TransactionsPrintAction: React.FC<Props> = ({ columns, data, itemUuid }) =
27
28
  isPatientTransaction: 'true',
28
29
  });
29
30
 
31
+ const [stockItemFilter, setStockItemFilter] = useState<StockItemInventoryFilter>({
32
+ startIndex: 0,
33
+ v: filter?.v || ResourceRepresentation.Default,
34
+ limit: 10,
35
+ q: filter?.q,
36
+ totalCount: true,
37
+ });
38
+
30
39
  const { item: stockItem, isLoading: isStockItemLoading } = useStockItem(itemUuid);
31
40
  const { items: stockCardData, isLoading: isStockCardLoading, error } = useStockItemTransactions(stockCardItemFilter);
41
+ const { items: inventoryBalance } = useStockItemInventory(stockItemFilter);
42
+
43
+ const [balances, setBalances] = useState<Record<string, { quantity: number; itemName: string }>>({});
44
+ const [currentIndex, setCurrentIndex] = useState(0);
45
+
46
+ useEffect(() => {
47
+ if (stockCardData?.results?.length) {
48
+ setCurrentIndex(0);
49
+ setBalances({});
50
+ }
51
+ }, [stockCardData?.results]);
52
+
53
+ useEffect(() => {
54
+ const currentItem = stockCardData?.results?.[currentIndex];
55
+ if (currentItem?.stockItemUuid) {
56
+ setStockItemFilter((prev) => ({
57
+ ...prev,
58
+ stockItemUuid: currentItem.stockItemUuid,
59
+ }));
60
+ }
61
+ }, [currentIndex, stockCardData]);
62
+
63
+ useEffect(() => {
64
+ const currentItem = stockCardData?.results?.[currentIndex];
65
+ const stockItemUuid = currentItem?.stockItemUuid;
66
+
67
+ if (inventoryBalance?.total && stockItemUuid) {
68
+ setBalances((prev) => ({
69
+ ...prev,
70
+ [stockItemUuid]: {
71
+ quantity: Number(inventoryBalance.total),
72
+ itemName: currentItem.packagingUomName ?? '',
73
+ },
74
+ }));
75
+
76
+ setCurrentIndex((prev) => prev + 1);
77
+ }
78
+ }, [inventoryBalance, currentIndex, stockCardData]);
79
+
80
+ const stockCardWithBalance = useMemo(() => {
81
+ return (
82
+ stockCardData?.results?.map((transaction) => {
83
+ const balance = balances[transaction.stockItemUuid];
84
+ return {
85
+ ...transaction,
86
+ balance: `${balance?.quantity ?? ''} ${balance?.itemName ?? ''}`,
87
+ };
88
+ }) ?? []
89
+ );
90
+ }, [stockCardData?.results, balances]);
32
91
 
33
92
  const stockCardHeaders = useMemo(
34
93
  () => [
@@ -56,6 +115,10 @@ const TransactionsPrintAction: React.FC<Props> = ({ columns, data, itemUuid }) =
56
115
  key: 'transaction',
57
116
  header: 'Transaction',
58
117
  },
118
+ {
119
+ key: 'balance',
120
+ header: 'Balance',
121
+ },
59
122
  {
60
123
  key: 'totalout',
61
124
  header: 'OUT',
@@ -82,7 +145,7 @@ const TransactionsPrintAction: React.FC<Props> = ({ columns, data, itemUuid }) =
82
145
  onClose: () => dispose(),
83
146
  title: stockItem.drugName || stockItem.conceptName || '',
84
147
  columns: stockCardHeaders,
85
- data: stockCardData.results,
148
+ data: stockCardWithBalance,
86
149
  });
87
150
  };
88
151