diff --git a/CHANGELOG.md b/CHANGELOG.md index 708a464d..70b67eeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ * Open version history pane on click changelog icon. Refs UINV-468. * Display all invoice versions in change log in fourth pane. Refs UINV-469. * Add external number extention to the csv export. Refs UINV-566. -* Invoices - Show in version history record view, which fields have been edited. Refs UINV-470. +* Display selected version in Invoice view. Refs UINV-470. +* Display selected version in Invoice line view. Refs UINV-553. ## [6.1.0](https://github.com/folio-org/ui-invoice/tree/v6.1.0) (2024-10-31) [Full Changelog](https://github.com/folio-org/ui-invoice/compare/v6.0.4...v6.1.0) diff --git a/src/common/constants/api.js b/src/common/constants/api.js index 118d82b2..5e3cc278 100644 --- a/src/common/constants/api.js +++ b/src/common/constants/api.js @@ -1,4 +1,5 @@ export const AUDIT_INVOICE_API = 'audit-data/acquisition/invoice'; +export const AUDIT_INVOICE_LINE_API = 'audit-data/acquisition/invoice-line'; export const BATCH_GROUPS_API = 'batch-groups'; export const BATCH_VOUCHERS_API = 'batch-voucher/batch-vouchers'; export const BATCH_VOUCHER_EXPORTS_API = 'batch-voucher/batch-voucher-exports'; diff --git a/src/common/constants/routes.js b/src/common/constants/routes.js index 385d9a8b..9c54a5c7 100644 --- a/src/common/constants/routes.js +++ b/src/common/constants/routes.js @@ -8,5 +8,6 @@ export const INVOICE_LINE_CREATE_ROUTE = `${INVOICE_LINE_ROUTE}/create`; export const INVOICE_LINE_EDIT_ROUTE = `${INVOICE_LINE_ROUTE}/:lineId/edit`; export const INVOICE_LINE_VIEW_ROUTE = `${INVOICE_LINE_ROUTE}/:lineId/view`; export const INVOICE_LINE_SEQUENCE_ROUTE = `${INVOICE_VIEW_ROUTE}/lines-sequence`; +export const INVOICE_LINE_VERSION_HISTORY_ROUTE = `${INVOICE_LINE_ROUTE}/:lineId/view/versions/:versionId?`; export const INVOICE_VOUCHER_ROUTE = `${INVOICE_VIEW_ROUTE}/voucher`; export const INVOICE_VOUCHER_EXPORT_ROUTE = `${INVOICE_ROUTE}/voucher-export`; diff --git a/src/common/hooks/index.js b/src/common/hooks/index.js index 075bfd85..40f5e6c9 100644 --- a/src/common/hooks/index.js +++ b/src/common/hooks/index.js @@ -9,11 +9,12 @@ export * from './useInvoice'; export * from './useInvoiceMutation'; export * from './useInvoiceLine'; export * from './useInvoiceLineMutation'; +export * from './useInvoiceLineVersions'; export * from './useInvoiceVersions'; -export * from './useOrderLine'; export * from './useOrderLines'; export * from './useOrders'; export * from './usePayableFiscalYears'; +export * from './useSelectedInvoiceLineVersion'; export * from './useSelectedInvoiceVersion'; export * from './useVendors'; export * from './useVoucherById'; diff --git a/src/common/hooks/useInvoice/useInvoice.js b/src/common/hooks/useInvoice/useInvoice.js index 6deb2d6d..b4d07b64 100644 --- a/src/common/hooks/useInvoice/useInvoice.js +++ b/src/common/hooks/useInvoice/useInvoice.js @@ -4,17 +4,19 @@ import { useOkapiKy } from '@folio/stripes/core'; import { INVOICES_API } from '@folio/stripes-acq-components'; +const DEFAULT_VALUE = {}; + export const useInvoice = (invoiceId) => { const ky = useOkapiKy(); - const { isLoading: isInvoiceLoading, data: invoice = {} } = useQuery( + const { isLoading, data } = useQuery( [INVOICES_API, invoiceId], () => ky.get(`${INVOICES_API}/${invoiceId}`).json(), { enabled: Boolean(invoiceId) }, ); return ({ - isInvoiceLoading, - invoice, + isLoading, + invoice: data || DEFAULT_VALUE, }); }; diff --git a/src/common/hooks/useInvoiceLine/useInvoiceLine.js b/src/common/hooks/useInvoiceLine/useInvoiceLine.js index 67c07468..68dd60bb 100644 --- a/src/common/hooks/useInvoiceLine/useInvoiceLine.js +++ b/src/common/hooks/useInvoiceLine/useInvoiceLine.js @@ -7,18 +7,24 @@ import { import { INVOICE_LINE_API } from '../../constants'; +const DEFAULT_VALUE = {}; + export const useInvoiceLine = (invoiceLineId) => { const ky = useOkapiKy(); const [namespace] = useNamespace({ key: 'invoice-line' }); - const { data: invoiceLine, isLoading, refetch } = useQuery( + const { + data, + isLoading, + refetch, + } = useQuery( [namespace, invoiceLineId], - () => ky.get(`${INVOICE_LINE_API}/${invoiceLineId}`).json(), + ({ signal }) => ky.get(`${INVOICE_LINE_API}/${invoiceLineId}`, { signal }).json(), { enabled: Boolean(invoiceLineId) }, ); return ({ - invoiceLine, + invoiceLine: data || DEFAULT_VALUE, isLoading, refetch, }); diff --git a/src/common/hooks/useInvoiceLineVersions/index.js b/src/common/hooks/useInvoiceLineVersions/index.js new file mode 100644 index 00000000..9edca475 --- /dev/null +++ b/src/common/hooks/useInvoiceLineVersions/index.js @@ -0,0 +1 @@ +export { useInvoiceLineVersions } from './useInvoiceLineVersions'; diff --git a/src/common/hooks/useInvoiceLineVersions/useInvoiceLineVersions.js b/src/common/hooks/useInvoiceLineVersions/useInvoiceLineVersions.js new file mode 100644 index 00000000..98864c8e --- /dev/null +++ b/src/common/hooks/useInvoiceLineVersions/useInvoiceLineVersions.js @@ -0,0 +1,34 @@ +import { useQuery } from 'react-query'; + +import { + useNamespace, + useOkapiKy, +} from '@folio/stripes/core'; + +import { AUDIT_INVOICE_LINE_API } from '../../constants'; + +const DEFAULT_VALUE = []; + +export const useInvoiceLineVersions = (invoiceLineId, options = {}) => { + const ky = useOkapiKy(); + const [namespace] = useNamespace({ key: 'invoice-line-versions' }); + + const searchParams = { + sortBy: 'event_date', + sortOrder: 'desc', + }; + + const { isLoading, data } = useQuery( + [namespace, invoiceLineId], + ({ signal }) => ky.get(`${AUDIT_INVOICE_LINE_API}/${invoiceLineId}`, { signal, searchParams }).json(), + { + enabled: Boolean(invoiceLineId), + ...options, + }, + ); + + return { + isLoading, + versions: data?.invoiceLineAuditEvents || DEFAULT_VALUE, + }; +}; diff --git a/src/common/hooks/useInvoiceLineVersions/useInvoiceVersions.test.js b/src/common/hooks/useInvoiceLineVersions/useInvoiceVersions.test.js new file mode 100644 index 00000000..d4409e24 --- /dev/null +++ b/src/common/hooks/useInvoiceLineVersions/useInvoiceVersions.test.js @@ -0,0 +1,50 @@ +import { + QueryClient, + QueryClientProvider, +} from 'react-query'; + +import { + renderHook, + waitFor, +} from '@folio/jest-config-stripes/testing-library/react'; +import { useOkapiKy } from '@folio/stripes/core'; + +import { useInvoiceLineVersions } from './useInvoiceLineVersions'; + +const queryClient = new QueryClient(); + +const wrapper = ({ children }) => ( + + {children} + +); + +const invoiceId = 'invoiceId'; +const invoiceLineAuditEvents = [ + { + id: '1', + invoiceId: 'invoiceId', + total: 100, + }, + { + id: '2', + invoiceId: 'invoiceId', + total: 200, + }, +]; + +describe('useInvoiceLineVersions', () => { + it('should return invoice versions', async () => { + useOkapiKy.mockClear().mockReturnValue({ + get: () => ({ + json: () => ({ invoiceLineAuditEvents }), + }), + }); + + const { result } = renderHook(() => useInvoiceLineVersions(invoiceId), { wrapper }); + + await waitFor(() => expect(result.current.isLoading).toBeFalsy()); + + expect(result.current.versions).toHaveLength(invoiceLineAuditEvents.length); + }); +}); diff --git a/src/common/hooks/useOrderLine/index.js b/src/common/hooks/useOrderLine/index.js deleted file mode 100644 index d787a40d..00000000 --- a/src/common/hooks/useOrderLine/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './useOrderLine'; diff --git a/src/common/hooks/useOrderLine/useOrderLine.js b/src/common/hooks/useOrderLine/useOrderLine.js deleted file mode 100644 index c6156759..00000000 --- a/src/common/hooks/useOrderLine/useOrderLine.js +++ /dev/null @@ -1,24 +0,0 @@ -import { useQuery } from 'react-query'; - -import { - useOkapiKy, - useNamespace, -} from '@folio/stripes/core'; - -import { LINES_API } from '@folio/stripes-acq-components'; - -export const useOrderLine = (orderLineId) => { - const ky = useOkapiKy(); - const [namespace] = useNamespace({ key: 'order-line' }); - - const { isLoading, data: orderLine } = useQuery( - [namespace, orderLineId], - () => ky.get(`${LINES_API}/${orderLineId}`).json(), - { enabled: Boolean(orderLineId) }, - ); - - return ({ - isLoading, - orderLine, - }); -}; diff --git a/src/common/hooks/useOrderLine/useOrderLine.test.js b/src/common/hooks/useOrderLine/useOrderLine.test.js deleted file mode 100644 index 6930bcba..00000000 --- a/src/common/hooks/useOrderLine/useOrderLine.test.js +++ /dev/null @@ -1,35 +0,0 @@ -import { QueryClient, QueryClientProvider } from 'react-query'; - -import { renderHook, waitFor } from '@folio/jest-config-stripes/testing-library/react'; -import { useOkapiKy } from '@folio/stripes/core'; - -import { useOrderLine } from './useOrderLine'; - -const queryClient = new QueryClient(); - -// eslint-disable-next-line react/prop-types -const wrapper = ({ children }) => ( - - {children} - -); - -const orderLineId = 'orderLineId'; - -describe('useOrderLine', () => { - it('should return order line', async () => { - useOkapiKy.mockClear().mockReturnValue({ - get: () => ({ - json: () => ({ - id: orderLineId, - }), - }), - }); - - const { result } = renderHook(() => useOrderLine(orderLineId), { wrapper }); - - await waitFor(() => expect(result.current.isLoading).toBeFalsy()); - - expect(result.current.orderLine.id).toBe(orderLineId); - }); -}); diff --git a/src/common/hooks/useSelectedInvoiceLineVersion/index.js b/src/common/hooks/useSelectedInvoiceLineVersion/index.js new file mode 100644 index 00000000..964d2dec --- /dev/null +++ b/src/common/hooks/useSelectedInvoiceLineVersion/index.js @@ -0,0 +1 @@ +export { useSelectedInvoiceLineVersion } from './useSelectedInvoiceLineVersion'; diff --git a/src/common/hooks/useSelectedInvoiceLineVersion/useSelectedInvoiceLineVersion.js b/src/common/hooks/useSelectedInvoiceLineVersion/useSelectedInvoiceLineVersion.js new file mode 100644 index 00000000..86b2e360 --- /dev/null +++ b/src/common/hooks/useSelectedInvoiceLineVersion/useSelectedInvoiceLineVersion.js @@ -0,0 +1,89 @@ +import get from 'lodash/get'; +import keyBy from 'lodash/keyBy'; +import uniq from 'lodash/uniq'; +import { useMemo } from 'react'; +import { useIntl } from 'react-intl'; +import { useQuery } from 'react-query'; + +import { useNamespace } from '@folio/stripes/core'; +import { getFullName } from '@folio/stripes/util'; +import { + getVersionMetadata, + useUsersBatch, +} from '@folio/stripes-acq-components'; + +import { useInvoice } from '../useInvoice'; +import { useInvoiceLine } from '../useInvoiceLine'; + +const DEFAULT_VALUE = []; + +export const useSelectedInvoiceLineVersion = ({ versionId, versions, snapshotPath }, options = {}) => { + const intl = useIntl(); + const [namespace] = useNamespace({ key: 'selected-invoice-line-version' }); + + const deletedRecordLabel = intl.formatMessage({ id: 'stripes-acq-components.versionHistory.deletedRecord' }); + const currentVersion = useMemo(() => versions?.find(({ id }) => id === versionId), [versionId, versions]); + const versionSnapshot = useMemo(() => get(currentVersion, snapshotPath), [snapshotPath, currentVersion]); + + const { + invoiceLine, + isLoading: isInvoiceLineLoading, + } = useInvoiceLine(currentVersion?.invoiceLineId); + const { + invoice, + isLoading: isInvoiceLoading, + } = useInvoice(currentVersion?.invoiceId); + + const metadata = useMemo(() => getVersionMetadata(currentVersion, invoiceLine), [currentVersion, invoiceLine]); + const createdByUserId = metadata?.createdByUserId; + const updatedByUserId = metadata?.updatedByUserId; + + const versionUserIds = useMemo(() => uniq([updatedByUserId, createdByUserId]), [updatedByUserId, createdByUserId]); + const { + users = DEFAULT_VALUE, + isLoading: isUsersLoading, + } = useUsersBatch(versionUserIds); + + const versionUsersMap = keyBy(users, 'id'); + + const { + isLoading: isVersionDataLoading, + data: selectedVersion = {}, + } = useQuery( + [namespace, versionId, versionSnapshot?.id], + async () => { + const createdByUser = versionUsersMap[createdByUserId] + ? getFullName(versionUsersMap[createdByUserId]) + : deletedRecordLabel; + + return { + ...versionSnapshot, + createdByUser: createdByUserId && createdByUser, + currency: invoice?.currency, + metadata, + }; + }, + { + enabled: Boolean( + versionId + && invoiceLine?.id + && !isInvoiceLoading + && !isInvoiceLineLoading + && !isUsersLoading, + ), + ...options, + }, + ); + + const isLoading = ( + isInvoiceLineLoading + || isVersionDataLoading + || isUsersLoading + || isInvoiceLoading + ); + + return { + selectedVersion, + isLoading, + }; +}; diff --git a/src/common/hooks/useSelectedInvoiceLineVersion/useSelectedInvoiceVersion.test.js b/src/common/hooks/useSelectedInvoiceLineVersion/useSelectedInvoiceVersion.test.js new file mode 100644 index 00000000..061981e0 --- /dev/null +++ b/src/common/hooks/useSelectedInvoiceLineVersion/useSelectedInvoiceVersion.test.js @@ -0,0 +1,103 @@ +import { + QueryClient, + QueryClientProvider, +} from 'react-query'; + +import { renderHook, waitFor } from '@folio/jest-config-stripes/testing-library/react'; +import { useOkapiKy } from '@folio/stripes/core'; +import { getFullName } from '@folio/stripes/util'; +import { + ACQUISITIONS_UNITS_API, + useUsersBatch, + VENDORS_API, +} from '@folio/stripes-acq-components'; +import { + acqUnit, + vendor, +} from '@folio/stripes-acq-components/test/jest/fixtures'; + +import { invoiceVersions, invoice } from 'fixtures'; +import { useInvoice } from '../useInvoice'; +import { useInvoiceLine } from '../useInvoiceLine'; +import { useSelectedInvoiceLineVersion } from './useSelectedInvoiceLineVersion'; + +jest.mock('@folio/stripes-acq-components/lib/hooks/useUsersBatch', () => ({ + useUsersBatch: jest.fn(() => ({ users: [], isLoading: false })), +})); + +jest.mock('../useInvoice', () => ({ + useInvoice: jest.fn(), +})); +jest.mock('../useInvoiceLine', () => ({ + useInvoiceLine: jest.fn(), +})); + +const invoiceData = { + ...invoice, +}; + +const user = { + id: 'd7b3f1f2-0d1b-4b3f-8e1b-3f1d7b3f1b3f', + personal: { firstName: 'Galt', lastName: 'John' }, +}; + +const kyMock = { + get: jest.fn((url) => ({ + json: async () => { + if (url.startsWith(ACQUISITIONS_UNITS_API)) { + return { acquisitionsUnits: [acqUnit] }; + } + if (url.startsWith(VENDORS_API)) { + return { organizations: [vendor] }; + } + + return {}; + }, + })), +}; + +const queryClient = new QueryClient(); + +// eslint-disable-next-line react/prop-types +const wrapper = ({ children }) => ( + + {children} + +); + +describe('useSelectedInvoiceLineVersion', () => { + beforeEach(() => { + kyMock.get.mockClear(); + useOkapiKy.mockClear().mockReturnValue(kyMock); + useInvoice.mockClear().mockReturnValue({ + invoice: invoiceData, + isLoading: false, + }); + useInvoiceLine.mockClear().mockReturnValue({ + invoiceLine: invoiceData, + isLoading: false, + }); + useUsersBatch.mockClear().mockReturnValue({ + isLoading: false, + users: [user], + }); + }); + + it('should return Invoice version data', async () => { + const { result } = renderHook(() => useSelectedInvoiceLineVersion({ + versionId: '4', + versions: invoiceVersions, + snapshotPath: 'invoiceLineSnapshot.map', + }), { wrapper }); + + await waitFor(() => expect(result.current.isLoading).toBeFalsy()); + + const { + currency, + createdByUser, + } = result.current.selectedVersion; + + expect(createdByUser).toEqual(getFullName(user)); + expect(currency).toEqual('USD'); + }); +}); diff --git a/src/invoices/InvoiceDetails/InvoiceDetails.js b/src/invoices/InvoiceDetails/InvoiceDetails.js index a250b3ce..c4c0dee0 100644 --- a/src/invoices/InvoiceDetails/InvoiceDetails.js +++ b/src/invoices/InvoiceDetails/InvoiceDetails.js @@ -9,7 +9,7 @@ import { FormattedMessage } from 'react-intl'; import { useHistory, useLocation, -} from 'react-router'; +} from 'react-router-dom'; import { TitleManager, @@ -267,9 +267,7 @@ function InvoiceDetails({ tagsQuantity={tags.length} tagsToggle={toggleTagsPane} /> - + ); const hasPOLineIsFullyPaid = orderlinesMap && diff --git a/src/invoices/InvoiceDetails/InvoiceDetails.test.js b/src/invoices/InvoiceDetails/InvoiceDetails.test.js index 2bee9177..5e905c12 100644 --- a/src/invoices/InvoiceDetails/InvoiceDetails.test.js +++ b/src/invoices/InvoiceDetails/InvoiceDetails.test.js @@ -1,8 +1,15 @@ -import { MemoryRouter } from 'react-router-dom'; -import { useHistory } from 'react-router'; +import { + MemoryRouter, + useHistory, +} from 'react-router-dom'; import user from '@folio/jest-config-stripes/testing-library/user-event'; -import { render, screen, act, waitFor } from '@folio/jest-config-stripes/testing-library/react'; +import { + render, + screen, + act, + waitFor, +} from '@folio/jest-config-stripes/testing-library/react'; import { HasCommand, expandAllSections, @@ -22,8 +29,8 @@ import InvoiceDetails from './InvoiceDetails'; import { VENDOR_STATUS } from './constants'; import { useHasPendingOrders } from './hooks'; -jest.mock('react-router', () => ({ - ...jest.requireActual('react-router'), +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), useHistory: jest.fn(), })); jest.mock('@folio/stripes-components/lib/Commander', () => ({ diff --git a/src/invoices/InvoiceForm/InvoiceFormContainer.js b/src/invoices/InvoiceForm/InvoiceFormContainer.js index 4970fdcf..b24cdceb 100644 --- a/src/invoices/InvoiceForm/InvoiceFormContainer.js +++ b/src/invoices/InvoiceForm/InvoiceFormContainer.js @@ -73,7 +73,7 @@ export function InvoiceFormContainerComponent({ adjustments: configAdjustments, isLoading: isConfigAdjustmentsLoading, } = useConfigsAdjustments(); - const { invoice, isInvoiceLoading } = useInvoice(id); + const { invoice, isLoading: isInvoiceLoading } = useInvoice(id); const { orders, isLoading: isOrdersLoading } = useOrders(orderIds?.length ? [orderIds[0]] : undefined); const { orderLines, isLoading: isOrderLinesLoading } = useOrderLines(orderIds); const invoiceVendorId = isCreate ? orders?.[0]?.vendor : invoice.vendorId; diff --git a/src/invoices/InvoiceForm/InvoiceFormContainer.test.js b/src/invoices/InvoiceForm/InvoiceFormContainer.test.js index f2a71c9b..f2cc909e 100644 --- a/src/invoices/InvoiceForm/InvoiceFormContainer.test.js +++ b/src/invoices/InvoiceForm/InvoiceFormContainer.test.js @@ -74,7 +74,7 @@ const renderInvoiceFormContainer = (props = defaultProps) => render( describe('InvoiceFormContainer', () => { beforeEach(() => { - useInvoice.mockClear().mockReturnValue({ isInvoiceLoading: false, invoice }); + useInvoice.mockClear().mockReturnValue({ isLoading: false, invoice }); useOrganization.mockClear().mockReturnValue({ isLoading: false, organization: vendor }); }); diff --git a/src/invoices/InvoiceLineDetails/InvoiceLineDetails.js b/src/invoices/InvoiceLineDetails/InvoiceLineDetails.js index 393f7b18..b990c2b8 100644 --- a/src/invoices/InvoiceLineDetails/InvoiceLineDetails.js +++ b/src/invoices/InvoiceLineDetails/InvoiceLineDetails.js @@ -1,10 +1,18 @@ -import React, { useRef } from 'react'; +import get from 'lodash/get'; import PropTypes from 'prop-types'; +import { + useCallback, + useRef, +} from 'react'; import { FormattedMessage, useIntl, } from 'react-intl'; -import { get } from 'lodash'; +import { + useHistory, + useParams, + useLocation, +} from 'react-router-dom'; import { TitleManager, @@ -32,8 +40,10 @@ import { handleKeyCommand, TagsBadge, useModalToggle, + VersionHistoryButton, } from '@folio/stripes-acq-components'; +import { INVOICE_ROUTE } from '../../common/constants'; import { isPayable, isPaid, @@ -57,10 +67,14 @@ const InvoiceLineDetails = ({ currency, poLine, }) => { - const [showConfirmDelete, toggleDeleteConfirmation] = useModalToggle(); - const accordionStatusRef = useRef(); + const history = useHistory(); + const { search } = useLocation(); const stripes = useStripes(); const intl = useIntl(); + const { id: invoiceId, lineId: invoiceLineId } = useParams(); + + const [showConfirmDelete, toggleDeleteConfirmation] = useModalToggle(); + const accordionStatusRef = useRef(); // eslint-disable-next-line react/prop-types const renderActionMenu = ({ onToggle }) => { @@ -87,6 +101,13 @@ const InvoiceLineDetails = ({ const total = get(invoiceLine, 'total', 0); const paneSubTitle = `${vendorInvoiceNo} - ${vendorCode}`; + const openVersionHistory = useCallback(() => { + history.push({ + pathname: `${INVOICE_ROUTE}/view/${invoiceId}/line/${invoiceLineId}/view/versions`, + search, + }); + }, [history, invoiceId, invoiceLineId, search]); + const paneTitle = ( + ); diff --git a/src/invoices/InvoiceLineDetails/InvoiceLineDetailsContainer.js b/src/invoices/InvoiceLineDetails/InvoiceLineDetailsContainer.js index 402161d9..06ebc72d 100644 --- a/src/invoices/InvoiceLineDetails/InvoiceLineDetailsContainer.js +++ b/src/invoices/InvoiceLineDetails/InvoiceLineDetailsContainer.js @@ -5,6 +5,7 @@ import { LoadingPane } from '@folio/stripes/components'; import { Tags, useModalToggle, + useOrderLine, useShowCallout, } from '@folio/stripes-acq-components'; @@ -12,7 +13,6 @@ import { useInvoice, useInvoiceLine, useInvoiceLineMutation, - useOrderLine, useVendors, } from '../../common/hooks'; import InvoiceLineDetails from './InvoiceLineDetails'; @@ -25,7 +25,7 @@ const InvoiceLineDetailsContainer = ({ const [isTagsPaneOpened, setTagsPaneOpened] = useModalToggle(); const showCallout = useShowCallout(); - const { invoice, isInvoiceLoading } = useInvoice(params?.id); + const { invoice, isLoading: isInvoiceLoading } = useInvoice(params?.id); const { invoiceLine, isLoading: isInvoiceLineLoading, diff --git a/src/invoices/InvoiceLineDetails/InvoiceLineDetailsContainer.test.js b/src/invoices/InvoiceLineDetails/InvoiceLineDetailsContainer.test.js index 1fab3d2d..c8b87154 100644 --- a/src/invoices/InvoiceLineDetails/InvoiceLineDetailsContainer.test.js +++ b/src/invoices/InvoiceLineDetails/InvoiceLineDetailsContainer.test.js @@ -68,14 +68,14 @@ const getMock = jest.fn(() => ({ describe('InvoiceLineDetailsContainer', () => { beforeEach(() => { - useInvoice.mockClear().mockReturnValue({ isInvoiceLoading: false, invoice: {} }); + useInvoice.mockClear().mockReturnValue({ isLoading: false, invoice: {} }); useOkapiKy.mockClear().mockReturnValue({ get: getMock, }); }); it('should not display InvoiceLineDetails when loading', async () => { - useInvoice.mockClear().mockReturnValue({ isInvoiceLoading: true }); + useInvoice.mockClear().mockReturnValue({ isLoading: true }); renderInvoiceLineDetailsContainer(); diff --git a/src/invoices/InvoiceLineForm/POLineField/POLineField.js b/src/invoices/InvoiceLineForm/POLineField/POLineField.js index 9feaac22..8e0ad6d3 100644 --- a/src/invoices/InvoiceLineForm/POLineField/POLineField.js +++ b/src/invoices/InvoiceLineForm/POLineField/POLineField.js @@ -11,8 +11,7 @@ import { IconButton, TextField, } from '@folio/stripes/components'; - -import { useOrderLine } from '../../../common/hooks'; +import { useOrderLine } from '@folio/stripes-acq-components'; export const POLineField = ({ isNonInteractive, poLineId, onSelect }) => { const intl = useIntl(); diff --git a/src/invoices/InvoiceLineForm/POLineField/POLineField.test.js b/src/invoices/InvoiceLineForm/POLineField/POLineField.test.js index 1c0fc79c..201c9a72 100644 --- a/src/invoices/InvoiceLineForm/POLineField/POLineField.test.js +++ b/src/invoices/InvoiceLineForm/POLineField/POLineField.test.js @@ -2,12 +2,11 @@ import { MemoryRouter } from 'react-router-dom'; import { render, screen, waitFor } from '@folio/jest-config-stripes/testing-library/react'; import stripesFinalForm from '@folio/stripes/final-form'; - -import { useOrderLine } from '../../../common/hooks'; +import { useOrderLine } from '@folio/stripes-acq-components'; import { POLineField } from './POLineField'; -jest.mock('../../../common/hooks', () => ({ +jest.mock('@folio/stripes-acq-components', () => ({ useOrderLine: jest.fn(), })); diff --git a/src/invoices/InvoicesList/InvoicesList.js b/src/invoices/InvoicesList/InvoicesList.js index dbb75b76..2f20f3a8 100644 --- a/src/invoices/InvoicesList/InvoicesList.js +++ b/src/invoices/InvoicesList/InvoicesList.js @@ -1,5 +1,12 @@ -import React, { useCallback, useMemo } from 'react'; import PropTypes from 'prop-types'; +import { + useCallback, + useMemo, +} from 'react'; +import { + FormattedMessage, + useIntl, +} from 'react-intl'; import { matchPath, Route, @@ -7,10 +14,6 @@ import { useLocation, useRouteMatch, } from 'react-router-dom'; -import { - FormattedMessage, - useIntl, -} from 'react-intl'; import { TitleManager, @@ -44,6 +47,7 @@ import { } from '@folio/stripes-acq-components'; import { + INVOICE_LINE_VERSION_HISTORY_ROUTE, INVOICE_LINE_VIEW_ROUTE, INVOICE_VERSION_HISTORY_ROUTE, INVOICE_VIEW_ROUTE, @@ -55,14 +59,16 @@ import { import { InvoiceDetailsContainer } from '../InvoiceDetails'; import { InvoiceLineDetailsContainer } from '../InvoiceLineDetails'; - +import { + InvoiceLineVersionHistory, + InvoiceVersionHistory, +} from '../VersionHistory'; import InvoicesListFilters from './InvoicesListFilters'; import { InvoicesListLastMenu } from './InvoicesListLastMenu'; import { searchableIndexes, } from './InvoicesListSearchConfig'; import { ExportSettingsModal } from './ExportSettingsModal'; -import { VersionHistory } from '../VersionHistory'; const resultsPaneTitle = ; const visibleColumns = ['vendorInvoiceNo', 'vendor', 'invoiceDate', 'status', 'invoiceTotal']; @@ -281,7 +287,12 @@ const InvoicesList = ({ /> + diff --git a/src/invoices/VersionHistory/InvoiceLineVersionHistory/InvoiceLineVersionHistory.js b/src/invoices/VersionHistory/InvoiceLineVersionHistory/InvoiceLineVersionHistory.js new file mode 100644 index 00000000..043fac59 --- /dev/null +++ b/src/invoices/VersionHistory/InvoiceLineVersionHistory/InvoiceLineVersionHistory.js @@ -0,0 +1,149 @@ +import get from 'lodash/get'; +import { + memo, + useCallback, +} from 'react'; +import { FormattedMessage } from 'react-intl'; +import ReactRouterPropTypes from 'react-router-prop-types'; + +import { TitleManager } from '@folio/stripes/core'; +import { + VersionHistoryPane, + VersionView, + VersionViewContextProvider, +} from '@folio/stripes-acq-components'; + +import { INVOICE_ROUTE } from '../../../common/constants'; +import { + useInvoice, + useInvoiceLine, + useInvoiceLineVersions, + useSelectedInvoiceLineVersion, + useVendors, +} from '../../../common/hooks'; +import { + HIDDEN_INVOICE_LINE_FIELDS, + INVOICE_LINE_FIELDS_LABEL_MAP, +} from '../constants'; +import { VersionHistoryView } from './VersionHistoryView'; + +const InvoiceLineVersionHistory = ({ + history, + location, + match, +}) => { + const { + id: invoiceId, + lineId, + versionId, + } = match.params; + const invoiceLinePath = `${INVOICE_ROUTE}/view/${invoiceId}/line/${lineId}/view`; + const snapshotPath = 'invoiceLineSnapshot.map'; + + const { + invoiceLine, + isLoading: isInvoiceLineLoading, + } = useInvoiceLine(lineId); + const { + invoice, + isLoading: isInvoiceLoading, + } = useInvoice(invoiceId); + const { + vendors, + isLoading: isVendorLoading, + } = useVendors([invoice?.vendorId]); + + const onHistoryClose = useCallback(() => history.push({ + pathname: invoiceLinePath, + search: location.search, + }), [history, invoiceLinePath, location.search]); + + const onVersionClose = useCallback(() => history.push({ + pathname: INVOICE_ROUTE, + search: location.search, + }), [history, location.search]); + + const onSelectVersion = useCallback((_versionId) => { + history.push({ + pathname: `${invoiceLinePath}/versions/${_versionId}`, + search: location.search, + }); + }, [history, location.search, invoiceLinePath]); + + const { + versions, + isLoading: isInvoiceLineVersionsLoading, + } = useInvoiceLineVersions( + lineId, + { + onSuccess: ({ invoiceLineAuditEvents }) => { + if (!versionId && invoiceLineAuditEvents[0]?.id) { + onSelectVersion(invoiceLineAuditEvents[0].id); + } + }, + }, + ); + + const { + isLoading: isSelectedVersionLoading, + selectedVersion, + } = useSelectedInvoiceLineVersion({ versionId, versions, snapshotPath }); + + const { invoiceLineNumber } = invoiceLine; + const paneSubTitle = `${invoice?.vendorInvoiceNo} - ${vendors?.[0]?.code}`; + + const isLoading = ( + isVendorLoading + || isInvoiceLineLoading + || isInvoiceLoading + || isInvoiceLineVersionsLoading + || isSelectedVersionLoading + ); + + return ( + + + + )} + tags={get(invoiceLine, 'tags.tagList', [])} + > + + + + + + ); +}; + +InvoiceLineVersionHistory.propTypes = { + history: ReactRouterPropTypes.history, + location: ReactRouterPropTypes.location, + match: ReactRouterPropTypes.match, +}; + +export default memo(InvoiceLineVersionHistory); diff --git a/src/invoices/VersionHistory/InvoiceLineVersionHistory/InvoiceLineVersionHistory.test.js b/src/invoices/VersionHistory/InvoiceLineVersionHistory/InvoiceLineVersionHistory.test.js new file mode 100644 index 00000000..da616e42 --- /dev/null +++ b/src/invoices/VersionHistory/InvoiceLineVersionHistory/InvoiceLineVersionHistory.test.js @@ -0,0 +1,153 @@ +import { + QueryClient, + QueryClientProvider, +} from 'react-query'; +import { + MemoryRouter, + Route, + Switch, + withRouter, +} from 'react-router-dom'; + +import user from '@folio/jest-config-stripes/testing-library/user-event'; +import { + render, + screen, +} from '@folio/jest-config-stripes/testing-library/react'; +import { useOkapiKy } from '@folio/stripes/core'; + +import { invoice, invoiceLine } from 'fixtures'; + +import { + AUDIT_INVOICE_LINE_API, + INVOICE_LINE_VERSION_HISTORY_ROUTE, + INVOICE_ROUTE, +} from '../../../common/constants'; +import { useInvoiceLineVersions } from '../../../common/hooks'; +import InvoiceLineVersionHistory from './InvoiceLineVersionHistory'; + +jest.mock('@folio/stripes-acq-components', () => ({ + ...jest.requireActual('@folio/stripes-acq-components'), + useOrderLine: jest.fn().mockReturnValue({ orderLine: { poLineNumber: '1' } }), +})); +jest.mock('../../../common/hooks', () => ({ + ...jest.requireActual('../../../common/hooks'), + useInvoiceLineVersions: jest.fn(() => {}), +})); + +const auditEvent = { + 'id': '037cab35-9a01-4d9f-88b4-e5bcdf3e1efb', + 'total': 5, + 'source': 'User', + 'status': 'Paid', + 'currency': 'USD', + 'subTotal': 5, + 'invoiceDate': '2024-11-12T00:00:00.000+00:00', + 'paymentDate': '2024-11-12T08:23:22.241+00:00', + 'paymentMethod': 'Credit Card', +}; + +const latestSnapshot = { + ...auditEvent, + total: 10, + subTotal: 10, +}; + +const versions = [ + { + id: 'testAuditEventId', + invoiceLineSnapshot: { map: latestSnapshot }, + }, + { + ...auditEvent, + invoiceLineSnapshot: { map: auditEvent }, + }, +]; + +const kyMock = { + get: jest.fn((url) => ({ + json: async () => { + const result = {}; + + if (url.startsWith(AUDIT_INVOICE_LINE_API)) { + result.invoiceLineSnapshot = versions; + } + + return Promise.resolve({ + isLoading: false, + ...result, + }); + }, + })), +}; + +const queryClient = new QueryClient(); + +const wrapper = ({ children }) => ( + + + {children} + + +); + +const Component = withRouter(InvoiceLineVersionHistory); +const mockDefaultContent = 'Hello world'; + +const renderComponent = (props = {}) => render( + + ( + + )} + /> + ( +
{mockDefaultContent}
+ )} + /> +
, + { wrapper }, +); + +describe('InvoiceLineVersionHistory', () => { + beforeEach(() => { + kyMock.get.mockClear(); + useOkapiKy.mockClear().mockReturnValue(kyMock); + useInvoiceLineVersions.mockClear().mockReturnValue({ + isLoading: false, + versions, + }); + }); + + it('should display Invoice version details', async () => { + renderComponent(); + + const versionBtns = await screen.findAllByRole('button', { name: 'stripes-acq-components.versionHistory.card.select.tooltip' }); + + await user.click(versionBtns[0]); + + expect(screen.queryByText('ui-invoice.invoiceLine.paneTitle.view')).toBeInTheDocument(); + }); + + it('should close version view when \'Version close\' button was clicked', async () => { + renderComponent(); + + await screen.findAllByRole('button', { name: 'stripes-acq-components.versionHistory.card.select.tooltip' }) + .then(async ([selectVersionBtn]) => user.click(selectVersionBtn)); + + await screen.findAllByRole('button', { name: 'stripes-components.closeItem' }) + .then(async ([closeVersionBtn]) => user.click(closeVersionBtn)); + + expect(screen.queryByText('ui-invoice.invoiceLine.paneTitle.view')).not.toBeInTheDocument(); + expect(screen.getByText(mockDefaultContent)).toBeInTheDocument(); + }); +}); diff --git a/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryFundDistributions/VersionHistoryFundDistributions.js b/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryFundDistributions/VersionHistoryFundDistributions.js new file mode 100644 index 00000000..0eb1d421 --- /dev/null +++ b/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryFundDistributions/VersionHistoryFundDistributions.js @@ -0,0 +1,23 @@ +import PropTypes from 'prop-types'; + +import { FundDistributionView } from '@folio/stripes-acq-components'; + +import { FUND_DISTRIBUTION_VISIBLE_COLUMNS } from '../../../constants'; + +export const VersionHistoryFundDistributions = ({ version }) => { + return ( + + ); +}; + +VersionHistoryFundDistributions.propTypes = { + version: PropTypes.object.isRequired, +}; diff --git a/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryFundDistributions/index.js b/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryFundDistributions/index.js new file mode 100644 index 00000000..fc1a6f4e --- /dev/null +++ b/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryFundDistributions/index.js @@ -0,0 +1 @@ +export { VersionHistoryFundDistributions } from './VersionHistoryFundDistributions'; diff --git a/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryView.js b/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryView.js new file mode 100644 index 00000000..142efc7a --- /dev/null +++ b/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryView.js @@ -0,0 +1,90 @@ +import get from 'lodash/get'; +import PropTypes from 'prop-types'; +import { useRef } from 'react'; +import { FormattedMessage } from 'react-intl'; + +import { + Accordion, + AccordionSet, + AccordionStatus, + checkScope, + Col, + collapseAllSections, + ExpandAllButton, + expandAllSections, + HasCommand, + Row, +} from '@folio/stripes/components'; + +import { VersionHistoryAdjustments } from '../../components'; +import { VersionHistoryFundDistributions } from './VersionHistoryFundDistributions'; +import { VersionHistoryViewInformation } from './VersionHistoryViewInformation'; + +export function VersionHistoryView({ version = {} }) { + const accordionStatusRef = useRef(); + + const shortcuts = [ + { + name: 'expandAllSections', + handler: (e) => expandAllSections(e, accordionStatusRef), + }, + { + name: 'collapseAllSections', + handler: (e) => collapseAllSections(e, accordionStatusRef), + }, + ]; + + const adjustments = get(version, 'adjustments', []); + const fundDistributions = get(version, 'fundDistributions', []); + + return ( + + + + + + + + + } + > + + + { + Boolean(adjustments.length) && ( + } + id="adjustments" + > + + + ) + } + { + Boolean(fundDistributions.length) && ( + } + id="fundDistributions" + > + + + ) + } + + + + ); +} + +VersionHistoryView.propTypes = { + version: PropTypes.object.isRequired, +}; diff --git a/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryView.test.js b/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryView.test.js new file mode 100644 index 00000000..df3c09a2 --- /dev/null +++ b/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryView.test.js @@ -0,0 +1,71 @@ +import { + QueryClient, + QueryClientProvider, +} from 'react-query'; + +import { + render, + screen, +} from '@folio/jest-config-stripes/testing-library/react'; + +import { VersionHistoryView } from './VersionHistoryView'; + +jest.mock('@folio/stripes-acq-components', () => ({ + ...jest.requireActual('@folio/stripes-acq-components'), + useOrderLine: jest.fn().mockReturnValue({ orderLine: { poLineNumber: '1' } }), +})); + +const queryClient = new QueryClient(); + +const wrapper = ({ children }) => ( + + {children} + +); + +const defaultProps = { + version: { + id: 'versionId', + invoiceId: 'invoiceId', + total: 10, + subTotal: 10, + poLineId: 'poLineId', + }, +}; + +const renderComponent = (props = defaultProps) => render( + , + { wrapper }, +); + +describe('VersionHistoryView', () => { + it('should render component', () => { + renderComponent(); + + expect(screen.getByText('ui-invoice.invoiceLineInformation')).toBeInTheDocument(); + }); + + it('should display adjustments and fundDistributions', () => { + renderComponent({ + version: { + id: 'versionId', + invoiceId: 'invoiceId', + adjustments: [ + { + description: 'description', + value: 10, + }, + ], + fundDistributions: [{ + id: 'fundDistributionId', + amount: 10, + value: 10, + expenseClassId: 'expenseClassId', + }], + }, + }); + + expect(screen.getByText('ui-invoice.invoice.details.accordion.adjustments')).toBeInTheDocument(); + expect(screen.getByText('ui-invoice.fundDistribution')).toBeInTheDocument(); + }); +}); diff --git a/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryViewInformation/VersionHistoryViewInformation.js b/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryViewInformation/VersionHistoryViewInformation.js new file mode 100644 index 00000000..c4ffad03 --- /dev/null +++ b/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryViewInformation/VersionHistoryViewInformation.js @@ -0,0 +1,165 @@ +import PropTypes from 'prop-types'; +import { FormattedMessage } from 'react-intl'; + +import { + Col, + Loading, + NoValue, + Row, +} from '@folio/stripes/components'; +import { + ViewMetaData, +} from '@folio/stripes/smart-components'; +import { + AmountWithCurrencyField, + FolioFormattedDate, + VendorReferenceNumbersDetails, + VersionCheckbox, + VersionKeyValue, + useOrderLine, +} from '@folio/stripes-acq-components'; + +export const VersionHistoryViewInformation = ({ version }) => { + const metadata = version.metadata; + + const { + orderLine = {}, + isLoading: isOrderLineLoading, + } = useOrderLine(version?.poLineId); + + const { poLineNumber } = orderLine; + + const { + currency, + subTotal, + description, + invoiceLineNumber, + invoiceLineStatus, + subscriptionInfo, + subscriptionStart, + subscriptionEnd, + comment, + accountNumber, + accountingCode, + quantity, + releaseEncumbrance, + referenceNumbers, + } = version; + + if (isOrderLineLoading) { + return ; + } + + return ( + <> + {metadata && } + + + + } + value={description} + /> + + + } + value={poLineNumber || } + /> + + + } + value={invoiceLineNumber} + /> + + + } + value={invoiceLineStatus} + /> + + + } + value={subscriptionInfo} + /> + + + } + value={} + /> + + + } + value={} + /> + + + } + value={comment} + /> + + + } + value={accountNumber} + /> + + + } + value={accountingCode} + /> + + + } + value={quantity} + /> + + + } + name="subTotal" + value={} + /> + + + } + type="checkbox" + name="releaseEncumbrance" + /> + + + } + value={} + /> + + + + ); +}; + +VersionHistoryViewInformation.propTypes = { + version: PropTypes.object.isRequired, +}; diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInformation/index.js b/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryViewInformation/index.js similarity index 100% rename from src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInformation/index.js rename to src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/VersionHistoryViewInformation/index.js diff --git a/src/invoices/VersionHistory/VersionHistoryView/index.js b/src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/index.js similarity index 100% rename from src/invoices/VersionHistory/VersionHistoryView/index.js rename to src/invoices/VersionHistory/InvoiceLineVersionHistory/VersionHistoryView/index.js diff --git a/src/invoices/VersionHistory/InvoiceLineVersionHistory/index.js b/src/invoices/VersionHistory/InvoiceLineVersionHistory/index.js new file mode 100644 index 00000000..d183a719 --- /dev/null +++ b/src/invoices/VersionHistory/InvoiceLineVersionHistory/index.js @@ -0,0 +1 @@ +export { default as InvoiceLineVersionHistory } from './InvoiceLineVersionHistory'; diff --git a/src/invoices/VersionHistory/VersionHistory.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistory.js similarity index 94% rename from src/invoices/VersionHistory/VersionHistory.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistory.js index 86925cfe..983aca6f 100644 --- a/src/invoices/VersionHistory/VersionHistory.js +++ b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistory.js @@ -13,16 +13,16 @@ import { VersionViewContextProvider, } from '@folio/stripes-acq-components'; -import { INVOICE_ROUTE } from '../../common/constants'; +import { INVOICE_ROUTE } from '../../../common/constants'; import { useInvoice, useInvoiceVersions, useSelectedInvoiceVersion, -} from '../../common/hooks'; +} from '../../../common/hooks'; import { HIDDEN_INVOICE_FIELDS, INVOICE_FIELDS_LABEL_MAP, -} from './constants'; +} from '../constants'; import { VersionHistoryView } from './VersionHistoryView'; const VersionHistory = ({ @@ -34,7 +34,7 @@ const VersionHistory = ({ const invoicePath = `${INVOICE_ROUTE}/view/${id}`; const snapshotPath = 'invoiceSnapshot.map'; - const { invoice, isInvoiceLoading } = useInvoice(id); + const { invoice, isLoading: isInvoiceLoading } = useInvoice(id); const onHistoryClose = useCallback(() => history.push({ pathname: invoicePath, diff --git a/src/invoices/VersionHistory/VersionHistory.test.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistory.test.js similarity index 89% rename from src/invoices/VersionHistory/VersionHistory.test.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistory.test.js index b4281df8..8c48d092 100644 --- a/src/invoices/VersionHistory/VersionHistory.test.js +++ b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistory.test.js @@ -22,12 +22,16 @@ import { AUDIT_INVOICE_API, INVOICE_ROUTE, INVOICE_VERSION_HISTORY_ROUTE, -} from '../../common/constants'; -import { useInvoiceVersions } from '../../common/hooks'; +} from '../../../common/constants'; +import { useInvoiceVersions } from '../../../common/hooks'; import VersionHistory from './VersionHistory'; -jest.mock('../../common/hooks', () => ({ - ...jest.requireActual('../../common/hooks'), +jest.mock('@folio/stripes-acq-components', () => ({ + ...jest.requireActual('@folio/stripes-acq-components'), + useOrderLine: jest.fn().mockReturnValue({ orderLine: { poLineNumber: '1' } }), +})); +jest.mock('../../../common/hooks', () => ({ + ...jest.requireActual('../../../common/hooks'), useInvoiceVersions: jest.fn(() => {}), })); diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryView.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryView.js similarity index 95% rename from src/invoices/VersionHistory/VersionHistoryView/VersionHistoryView.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryView.js index 6ca19bb8..22abe7ac 100644 --- a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryView.js +++ b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryView.js @@ -16,9 +16,9 @@ import { Row, } from '@folio/stripes/components'; -import { VersionHistoryViewAdjustments } from './VersionHistoryViewAdjustments'; import { VersionHistoryViewInformation } from './VersionHistoryViewInformation'; import { VersionHistoryViewInvoiceLine } from './VersionHistoryViewInvoiceLine'; +import { VersionHistoryAdjustments } from '../../components'; export function VersionHistoryView({ version = {} }) { const accordionStatusRef = useRef(); @@ -75,7 +75,7 @@ export function VersionHistoryView({ version = {} }) { label={} id="adjustments" > - diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryView.test.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryView.test.js similarity index 97% rename from src/invoices/VersionHistory/VersionHistoryView/VersionHistoryView.test.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryView.test.js index ca2b9157..1f2be65d 100644 --- a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryView.test.js +++ b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryView.test.js @@ -33,7 +33,7 @@ const renderComponent = (props = defaultProps) => render( { wrapper }, ); -describe('useOrdersByPoNumbers', () => { +describe('VersionHistoryView', () => { it('should render component', () => { renderComponent(); diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInformation/VersionHistoryViewInformation.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInformation/VersionHistoryViewInformation.js similarity index 97% rename from src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInformation/VersionHistoryViewInformation.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInformation/VersionHistoryViewInformation.js index e485e5dc..4acdedff 100644 --- a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInformation/VersionHistoryViewInformation.js +++ b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInformation/VersionHistoryViewInformation.js @@ -19,9 +19,9 @@ import { CalculatedExchangeAmount, FiscalYearValueContainer, StatusValue, -} from '../../../../common/components'; -import { isCancelled } from '../../../../common/utils'; -import BatchGroupValue from '../../../InvoiceDetails/BatchGroupValue'; +} from '../../../../../common/components'; +import { isCancelled } from '../../../../../common/utils'; +import BatchGroupValue from '../../../../InvoiceDetails/BatchGroupValue'; export const VersionHistoryViewInformation = ({ version = {} }) => { const { diff --git a/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInformation/index.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInformation/index.js new file mode 100644 index 00000000..fc4ac8c6 --- /dev/null +++ b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInformation/index.js @@ -0,0 +1 @@ +export { VersionHistoryViewInformation } from './VersionHistoryViewInformation'; diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.js similarity index 96% rename from src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.js index 2d7ab3b4..3eec40f9 100644 --- a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.js +++ b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.js @@ -10,8 +10,8 @@ import { FrontendSortingMCL } from '@folio/stripes-acq-components'; import { useOrderLines, useVendors, -} from '../../../../common/hooks'; -import { INVOICE_LINES_COLUMN_MAPPING } from '../../../constants'; +} from '../../../../../common/hooks'; +import { INVOICE_LINES_COLUMN_MAPPING } from '../../../../constants'; import { useInvoiceLinesByInvoiceId, useOrdersByPoNumbers, diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.test.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.test.js similarity index 95% rename from src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.test.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.test.js index 8e15ddf5..c69a7d8a 100644 --- a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.test.js +++ b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/VersionHistoryViewInvoiceLine.test.js @@ -12,7 +12,7 @@ import { invoiceLine, orderLine, vendor } from 'fixtures'; import { useOrderLines, useVendors, -} from '../../../../common/hooks'; +} from '../../../../../common/hooks'; import { useInvoiceLinesByInvoiceId, useOrdersByPoNumbers, @@ -25,8 +25,8 @@ jest.mock('@folio/stripes/components', () => ({ Loading: jest.fn(() => 'Loading'), })); -jest.mock('../../../../common/hooks', () => ({ - ...jest.requireActual('../../../../common/hooks'), +jest.mock('../../../../../common/hooks', () => ({ + ...jest.requireActual('../../../../../common/hooks'), useOrderLines: jest.fn(() => ({})), useVendors: jest.fn(() => ({})), })); diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/index.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/index.js similarity index 100% rename from src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/index.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/index.js diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/style.css b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/style.css similarity index 100% rename from src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/style.css rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/style.css diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/utils.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/utils.js similarity index 100% rename from src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/utils.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/VersionHistoryViewInvoiceLine/utils.js diff --git a/src/invoices/VersionHistory/VersionHistoryView/hooks/index.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/hooks/index.js similarity index 100% rename from src/invoices/VersionHistory/VersionHistoryView/hooks/index.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/hooks/index.js diff --git a/src/invoices/VersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId/index.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId/index.js similarity index 100% rename from src/invoices/VersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId/index.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId/index.js diff --git a/src/invoices/VersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId/useInvoiceLinesByInvoiceId.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId/useInvoiceLinesByInvoiceId.js similarity index 100% rename from src/invoices/VersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId/useInvoiceLinesByInvoiceId.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId/useInvoiceLinesByInvoiceId.js diff --git a/src/invoices/VersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId/useInvoiceLinesByInvoiceId.test.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId/useInvoiceLinesByInvoiceId.test.js similarity index 100% rename from src/invoices/VersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId/useInvoiceLinesByInvoiceId.test.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/hooks/useInvoiceLinesByInvoiceId/useInvoiceLinesByInvoiceId.test.js diff --git a/src/invoices/VersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers/index.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers/index.js similarity index 100% rename from src/invoices/VersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers/index.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers/index.js diff --git a/src/invoices/VersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers/useOrdersByPoNumbers.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers/useOrdersByPoNumbers.js similarity index 100% rename from src/invoices/VersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers/useOrdersByPoNumbers.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers/useOrdersByPoNumbers.js diff --git a/src/invoices/VersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers/useOrdersByPoNumbers.test.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers/useOrdersByPoNumbers.test.js similarity index 100% rename from src/invoices/VersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers/useOrdersByPoNumbers.test.js rename to src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/hooks/useOrdersByPoNumbers/useOrdersByPoNumbers.test.js diff --git a/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/index.js b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/index.js new file mode 100644 index 00000000..eff1a553 --- /dev/null +++ b/src/invoices/VersionHistory/InvoiceVersionHistory/VersionHistoryView/index.js @@ -0,0 +1 @@ +export { VersionHistoryView } from './VersionHistoryView'; diff --git a/src/invoices/VersionHistory/InvoiceVersionHistory/index.js b/src/invoices/VersionHistory/InvoiceVersionHistory/index.js new file mode 100644 index 00000000..44526a10 --- /dev/null +++ b/src/invoices/VersionHistory/InvoiceVersionHistory/index.js @@ -0,0 +1 @@ +export { default as InvoiceVersionHistory } from './VersionHistory'; diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/index.js b/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/index.js deleted file mode 100644 index 4eab1eed..00000000 --- a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/index.js +++ /dev/null @@ -1 +0,0 @@ -export { VersionHistoryViewAdjustments } from './VersionHistoryViewAdjustments'; diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/VersionHistoryViewAdjustments.js b/src/invoices/VersionHistory/components/VersionHistoryAdjustments/VersionHistoryAdjustments.js similarity index 88% rename from src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/VersionHistoryViewAdjustments.js rename to src/invoices/VersionHistory/components/VersionHistoryAdjustments/VersionHistoryAdjustments.js index 34703e02..a85c8c30 100644 --- a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/VersionHistoryViewAdjustments.js +++ b/src/invoices/VersionHistory/components/VersionHistoryAdjustments/VersionHistoryAdjustments.js @@ -14,7 +14,7 @@ import { } from './constants'; import { getResultsFormatter } from './utils'; -export const VersionHistoryViewAdjustments = ({ adjustments, currency }) => { +export const VersionHistoryAdjustments = ({ adjustments, currency }) => { const resultsFormatter = useMemo(() => getResultsFormatter({ currency }), [currency]); return ( @@ -35,7 +35,7 @@ export const VersionHistoryViewAdjustments = ({ adjustments, currency }) => { ); }; -VersionHistoryViewAdjustments.propTypes = { +VersionHistoryAdjustments.propTypes = { adjustments: PropTypes.arrayOf(PropTypes.object), currency: PropTypes.string, }; diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/constants.js b/src/invoices/VersionHistory/components/VersionHistoryAdjustments/constants.js similarity index 100% rename from src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/constants.js rename to src/invoices/VersionHistory/components/VersionHistoryAdjustments/constants.js diff --git a/src/invoices/VersionHistory/components/VersionHistoryAdjustments/index.js b/src/invoices/VersionHistory/components/VersionHistoryAdjustments/index.js new file mode 100644 index 00000000..4a17b764 --- /dev/null +++ b/src/invoices/VersionHistory/components/VersionHistoryAdjustments/index.js @@ -0,0 +1 @@ +export { VersionHistoryAdjustments } from './VersionHistoryAdjustments'; diff --git a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/utils.js b/src/invoices/VersionHistory/components/VersionHistoryAdjustments/utils.js similarity index 89% rename from src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/utils.js rename to src/invoices/VersionHistory/components/VersionHistoryAdjustments/utils.js index a3418b69..8c246635 100644 --- a/src/invoices/VersionHistory/VersionHistoryView/VersionHistoryViewAdjustments/utils.js +++ b/src/invoices/VersionHistory/components/VersionHistoryAdjustments/utils.js @@ -4,12 +4,7 @@ import { AmountWithCurrencyField, VersionKeyValue, } from '@folio/stripes-acq-components'; - -import { - ADJUSTMENT_PRORATE_LABELS, - ADJUSTMENT_RELATION_TO_TOTAL_LABELS, - ADJUSTMENT_TYPE_VALUES, -} from '../../../../common/constants'; +import { ADJUSTMENT_PRORATE_LABELS, ADJUSTMENT_RELATION_TO_TOTAL_LABELS, ADJUSTMENT_TYPE_VALUES } from '../../../../common/constants'; export const getResultsFormatter = ({ currency }) => ({ description: ({ rowIndex, description }) => ( diff --git a/src/invoices/VersionHistory/components/index.js b/src/invoices/VersionHistory/components/index.js new file mode 100644 index 00000000..4a17b764 --- /dev/null +++ b/src/invoices/VersionHistory/components/index.js @@ -0,0 +1 @@ +export { VersionHistoryAdjustments } from './VersionHistoryAdjustments'; diff --git a/src/invoices/VersionHistory/constants.js b/src/invoices/VersionHistory/constants.js index cfdd019c..0eb575df 100644 --- a/src/invoices/VersionHistory/constants.js +++ b/src/invoices/VersionHistory/constants.js @@ -37,6 +37,51 @@ export const INVOICE_FIELDS_LABEL_MAP = { 'voucherNumber': 'ui-invoice.invoice.voucherNumber', }; +export const INVOICE_LINE_FIELDS_LABEL_MAP = { + 'accountingCode': 'ui-invoice.invoice.accountingCode', + 'accountNumber': 'ui-invoice.invoice.accountNumber', + 'adjustments[\\d].description': 'ui-invoice.settings.adjustments.description', + 'adjustments[\\d].exportToAccounting': 'ui-invoice.settings.adjustments.exportToAccounting', + 'adjustments[\\d].id': 'ui-invoice.invoice.details.lines.list.adjustments', + 'adjustments[\\d].prorate': 'ui-invoice.settings.adjustments.prorate', + 'adjustments[\\d].relationToTotal': 'ui-invoice.settings.adjustments.relationToTotal', + 'adjustments[\\d].type': 'ui-invoice.settings.adjustments.type', + 'adjustments[\\d].value': 'ui-invoice.settings.adjustments.value', + 'adjustmentsTotal': 'ui-invoice.invoice.details.information.adjustment', + 'comment': 'ui-invoice.invoiceLine.comment', + 'description': 'ui-invoice.invoiceLine.description', + 'fundDistributions[\\d].id': 'stripes-acq-components.fundDistribution.id', + 'fundDistributions[\\d].amount': 'stripes-acq-components.fundDistribution.amount', + 'fundDistributions[\\d].code': 'ui-invoice.invoice.details.lines.list.fundCode', + 'fundDistributions[\\d].distributionType': 'stripes-acq-components.fundDistribution.type', + 'fundDistributions[\\d].fundId': 'ui-invoice.invoiceLine.fundId', + 'fundDistributions[\\d].value': 'stripes-acq-components.fundDistribution.value', + 'fundDistributions[\\d].expenseClassId': 'stripes-acq-components.fundDistribution.expenseClass', + 'fundDistributions[\\d].encumbrance': 'ui-invoice.invoiceLine.releaseEncumbrance', + 'invoiceId': 'ui-invoice.invoiceLine.invoiceId', + 'invoiceLineNumber': 'ui-invoice.invoice.invoiceLineNumber', + 'invoiceLineStatus': 'ui-invoice.invoiceLine.invoiceLineStatus', + 'poLineId': 'ui-invoice.invoiceLine.poLineId', + 'quantity': 'ui-invoice.invoiceLine.quantity', + 'referenceNumbers[\\d].refNumber': 'ui-invoice.invoice.details.lines.list.vendorRefNumber', + 'referenceNumbers[\\d].refNumberType': 'stripes-acq-components.referenceNumbers.refNumberType', + 'releaseEncumbrance': 'ui-invoice.invoiceLine.releaseEncumbrance', + 'subscriptionEnd': 'ui-invoice.invoiceLine.subscriptionEnd', + 'subscriptionInfo': 'ui-invoice.invoiceLine.subscriptionInfo', + 'subscriptionStart': 'ui-invoice.invoiceLine.subscriptionStart', + 'subTotal': 'ui-invoice.invoice.details.lines.list.subTotal', + 'total': 'ui-invoice.invoice.details.lines.list.total', +}; + +export const HIDDEN_INVOICE_LINE_FIELDS = []; + +export const FUND_DISTRIBUTION_VISIBLE_COLUMNS = [ + 'name', + 'expenseClass', + 'value', + 'amount', +]; + export const HIDDEN_INVOICE_FIELDS = [ 'nextInvoiceLineNumber', ]; diff --git a/src/invoices/VersionHistory/index.js b/src/invoices/VersionHistory/index.js index 01d26d54..de3ade6d 100644 --- a/src/invoices/VersionHistory/index.js +++ b/src/invoices/VersionHistory/index.js @@ -1 +1,2 @@ -export { default as VersionHistory } from './VersionHistory'; +export { InvoiceVersionHistory } from './InvoiceVersionHistory'; +export { InvoiceLineVersionHistory } from './InvoiceLineVersionHistory'; diff --git a/src/invoices/Voucher/useVoucher.js b/src/invoices/Voucher/useVoucher.js index c21a804f..a9b3fa42 100644 --- a/src/invoices/Voucher/useVoucher.js +++ b/src/invoices/Voucher/useVoucher.js @@ -9,7 +9,7 @@ export const useVoucher = (invoiceId, voucherId) => { const { isVoucherLinesLoading, voucherLines } = useVoucherLines(voucherId); - const { isInvoiceLoading, invoice } = useInvoice(invoiceId); + const { isLoading: isInvoiceLoading, invoice } = useInvoice(invoiceId); return ({ isLoading: isVoucherLoading || isVoucherLinesLoading || isInvoiceLoading,