Skip to content

Commit

Permalink
UISACQCOMP-237 Exclude unsupported currencies (#844)
Browse files Browse the repository at this point in the history
* Exclude failed exchange rates

* Add change log

* Extract `value` from Promise array

* Add test case
  • Loading branch information
azizjonnurov authored Dec 27, 2024
1 parent ebd6659 commit 7f65603
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* Move reusable claiming code from `ui-receiving` to the shared library. Refs UISACQCOMP-236.
* Support `CLAIMS` export type in the `useIntegrationConfigs` hook. Refs UISACQCOMP-238.
* Claim locations from all members for locations filter when `crossTenant` equals `true`. Refs UISACQCOMP-239.
* Exclude unsupported currencies on `getInvoiceExportData`. Refs UISACQCOMP-237.

## [6.0.2](https://github.com/folio-org/stripes-acq-components/tree/v6.0.2) (2024-12-04)
[Full Changelog](https://github.com/folio-org/stripes-acq-components/compare/v6.0.1...v6.0.2)
Expand Down
5 changes: 4 additions & 1 deletion lib/utils/invoiceExport/getInvoiceExportData.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,12 @@ export const getInvoiceExportData = async ({ ky, intl, query, currency: to }) =>
});
const addresses = getAddresses(addressRecords);
const currencies = uniq(exportInvoices.map(({ currency }) => currency));
const exchangeRates = await Promise.all(
const allExchangeRates = await Promise.allSettled(
currencies.map(from => ky.get(EXCHANGE_RATE_API, { searchParams: { from, to } }).json()),
);
const exchangeRates = allExchangeRates
.filter(({ status }) => status === 'fulfilled')
.map(({ value }) => value);

return (createInvoiceExportReport({
acqUnitMap: keyBy(acqUnits, 'id'),
Expand Down
119 changes: 109 additions & 10 deletions lib/utils/invoiceExport/getInvoiceExportData.test.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,116 @@
import { renderHook } from '@testing-library/react-hooks';
import { useIntl } from 'react-intl';
/* Developed collaboratively using AI (ChatGPT) */

import { getInvoiceExportData } from './getInvoiceExportData';
import { fetchAllRecords } from '../fetchAllRecords';
import { fetchExportDataByIds } from '../fetchExportDataByIds';
import { getAddresses } from '../getAddresses';
import { createInvoiceExportReport } from './createInvoiceExportReport';

jest.mock('./createInvoiceExportReport', () => ({
createInvoiceExportReport: jest.fn().mockReturnValue('test report'),
}));
jest.mock('../fetchAllRecords');
jest.mock('../fetchExportDataByIds');
jest.mock('../getAddresses');
jest.mock('./createInvoiceExportReport');

test('should create export report', async () => {
const { result } = renderHook(() => useIntl());
const intl = result.current;
describe('getInvoiceExportData', () => {
const mockKy = {
get: jest.fn().mockImplementation(() => ({
json: jest.fn().mockResolvedValue({ from: 'USD', to: 'EUR', rate: 0.85 }),
})),
};

const report = await getInvoiceExportData({ intl });
const mockIntl = {};
const mockQuery = {};

expect(report).toEqual('test report');
beforeEach(() => {
jest.clearAllMocks();
});

it('should fetch and process invoice export data correctly', async () => {
fetchAllRecords.mockResolvedValue([{ id: '1', vendorId: 'v1', currency: 'USD' }]);
fetchExportDataByIds.mockResolvedValue([]);
getAddresses.mockReturnValue([]);
createInvoiceExportReport.mockReturnValue('Export Report');

const result = await getInvoiceExportData({
ky: mockKy,
intl: mockIntl,
query: mockQuery,
currency: 'USD',
});

expect(fetchAllRecords).toHaveBeenCalled();
expect(fetchExportDataByIds).toHaveBeenCalled();
expect(createInvoiceExportReport).toHaveBeenCalledWith(
expect.objectContaining({
invoiceMap: { '1': { id: '1', vendorId: 'v1', currency: 'USD' } },
}),
);
expect(result).toBe('Export Report');
});

it('should handle exchange rate fetching correctly', async () => {
const mockExportInvoices = [
{ id: '1', vendorId: 'v1', currency: 'GBP' },
{ id: '2', vendorId: 'v2', currency: 'PLN' },
];

fetchAllRecords.mockResolvedValue(mockExportInvoices);

mockKy.get
.mockImplementationOnce(() => ({
json: jest.fn().mockResolvedValue({ from: 'GBP', to: 'USD', rate: 1.26 }),
}))
.mockImplementationOnce(() => ({
json: jest.fn().mockResolvedValue({ from: 'PLN', to: 'USD', rate: 0.24 }),
}));

const result = await getInvoiceExportData({
ky: mockKy,
intl: mockIntl,
query: mockQuery,
currency: 'USD',
});

expect(result).toBe('Export Report');
expect(createInvoiceExportReport).toHaveBeenCalledWith(
expect.objectContaining({
exchangeRateMap: {
GBP: { from: 'GBP', rate: 1.26, to: 'USD' },
PLN: { from: 'PLN', rate: 0.24, to: 'USD' },
},
}),
);
});

it('should filter out failed exchange rate requests', async () => {
const mockExportInvoices = [
{ id: '1', vendorId: 'v1', currency: 'USD' },
{ id: '2', vendorId: 'v2', currency: 'TJS' },
];

fetchAllRecords.mockResolvedValue(mockExportInvoices);

mockKy.get.mockImplementationOnce(() => ({
json: jest.fn().mockResolvedValue({ from: 'USD', to: 'USD', rate: 1 }),
}));
mockKy.get.mockImplementationOnce(() => ({
json: jest.fn().mockRejectedValue(new Error('Cannot convert TJS into USD: Rate Provider did not return data though at check before data was flagged as available, provider=ECB, query=ConversionQuery (\n{Query.termCurrency=USD, Query.baseCurrency=TJS})')),
}));

const result = await getInvoiceExportData({
ky: mockKy,
intl: mockIntl,
query: mockQuery,
currency: 'USD',
});

expect(result).toBe('Export Report');
expect(createInvoiceExportReport).toHaveBeenCalledWith(
expect.objectContaining({
exchangeRateMap: {
USD: { from: 'USD', rate: 1, to: 'USD' },
},
}),
);
});
});

0 comments on commit 7f65603

Please sign in to comment.