Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: settle bills on correct cash point #469

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions __mocks__/bills.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -662,3 +662,57 @@ export const mockPaymentModes = [
},
{ uuid: 'eb6173cb-9678-4614-bbe1-0ccf7ed9d1d4', name: 'Waiver', description: 'Waiver payment', retired: false },
];

export const mockedActiveSheet = {
uuid: 'cbf56e9a-5db1-41d3-8d34-e228aa2e31c0',
display: '14 Nov 2024, 08:11 to open',
voided: false,
voidReason: null,
auditInfo: {
creator: {
uuid: 'e02c40e5-04e7-11e5-ae3c-a0b3cc4f922f',
display: 'admin',
links: [
{
rel: 'self',
uri: 'http://dev.kenyahmis.org/openmrs/ws/rest/v1/user/e02c40e5-04e7-11e5-ae3c-a0b3cc4f922f',
resourceAlias: 'user',
},
],
},
dateCreated: '2024-11-14T08:11:27.000+0300',
changedBy: null,
dateChanged: null,
},
cashier: {
uuid: '48b55692-e061-4ffa-b1f2-fd4aaf506224',
display: 'admin - Barbara Stewart Lopez',
links: [
{
rel: 'self',
uri: 'http://dev.kenyahmis.org/openmrs/ws/rest/v1/provider/48b55692-e061-4ffa-b1f2-fd4aaf506224',
resourceAlias: 'provider',
},
],
},
cashPoint: {
uuid: '65dd568e-4124-4e89-a4f8-0b07c58ec6fe',
name: 'MNCH Pay Point',
description: 'Payment done at the MNCH department',
retired: false,
location: {
uuid: '233de33e-2778-4f9a-a398-fa09da9daa14',
display: 'Wamagana Health Centre',
links: [
{
rel: 'self',
uri: 'http://dev.kenyahmis.org/openmrs/ws/rest/v1/location/233de33e-2778-4f9a-a398-fa09da9daa14',
resourceAlias: 'location',
},
],
},
},
clockIn: '2024-11-14T08:11:27.000+0300',
clockOut: null,
resourceVersion: '1.8',
};
10 changes: 8 additions & 2 deletions packages/esm-billing-app/src/hooks/useRequestStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import { processBillPayment, usePaymentModes } from '../billing.resource';
import { BillingConfig } from '../config-schema';
import { processBillItem } from '../invoice/payments/utils';
import { getErrorMessage, getRequestStatus, readableStatusMap } from '../m-pesa/mpesa-resource';
import { LineItem, MappedBill, PaymentStatus, RequestStatus } from '../types';
import { useClockInStatus } from '../payment-points/use-clock-in-status';
import { LineItem, MappedBill, PaymentStatus, RequestStatus, Timesheet } from '../types';
import { extractErrorMessagesFromResponse, waitForASecond } from '../utils';

export const createMobileMoneyPaymentPayload = (
bill: MappedBill,
amount: number,
mobileMoneyInstanceTypeUUID: string,
paymentReference: { uuid: string; value: string },
timesheet?: Timesheet,
) => {
const { cashier } = bill;
const totalAmount = bill?.totalAmount;
Expand Down Expand Up @@ -72,7 +74,7 @@ export const createMobileMoneyPaymentPayload = (
: PaymentStatus.PAID;

const processedPayment = {
cashPoint: bill.cashPointUuid,
cashPoint: timesheet ? timesheet.cashPoint.uuid : bill.cashPointUuid,
cashier: cashier.uuid,
lineItems: updatedLineItems,
payments: updatedPayments,
Expand Down Expand Up @@ -112,6 +114,8 @@ export const useRequestStatus = (
amount: null,
});

const { globalActiveSheet } = useClockInStatus();

useEffect(() => {
let interval: NodeJS.Timeout;

Expand Down Expand Up @@ -139,6 +143,7 @@ export const useRequestStatus = (
parseInt(requestData.amount),
mobileMoneyPaymentMethodInstanceTypeUUID,
{ uuid: paymentReferenceUUID, value: referenceCode },
globalActiveSheet,
);

processBillPayment(mobileMoneyPayload, bill.uuid).then(
Expand Down Expand Up @@ -199,6 +204,7 @@ export const useRequestStatus = (
setNotification,
t,
isPDSLFacility,
globalActiveSheet,
]);

return [requestData, setRequestData];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import { Button } from '@carbon/react';
import { zodResolver } from '@hookform/resolvers/zod';
import { navigate, showSnackbar } from '@openmrs/esm-framework';
import { CardHeader } from '@openmrs/esm-patient-common-lib';
import React, { useState } from 'react';
import { FormProvider, useFieldArray, useForm, useWatch } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { mutate } from 'swr';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { navigate, showSnackbar } from '@openmrs/esm-framework';
import { Button } from '@carbon/react';
import { CardHeader } from '@openmrs/esm-patient-common-lib';
import { LineItem, PaymentFormValue, type MappedBill } from '../../types';
import { convertToCurrency } from '../../helpers';
import { createPaymentPayload } from './utils';
import { processBillPayment } from '../../billing.resource';
import { convertToCurrency } from '../../helpers';
import { useClockInStatus } from '../../payment-points/use-clock-in-status';
import { LineItem, PaymentFormValue, type MappedBill } from '../../types';
import { computeTotalPrice, extractErrorMessagesFromResponse } from '../../utils';
import { InvoiceBreakDown } from './invoice-breakdown/invoice-breakdown.component';
import PaymentHistory from './payment-history/payment-history.component';
import PaymentForm from './payment-form/payment-form.component';
import PaymentHistory from './payment-history/payment-history.component';
import styles from './payments.scss';
import { computeTotalPrice, extractErrorMessagesFromResponse } from '../../utils';
import { mutate } from 'swr';
import { createPaymentPayload } from './utils';

type PaymentProps = {
bill: MappedBill;
Expand All @@ -31,6 +32,7 @@ const Payments: React.FC<PaymentProps> = ({ bill, selectedLineItems }) => {
.lte(bill.totalAmount - bill.tenderedAmount, { message: 'Amount paid should not be greater than amount due' }),
referenceCode: z.union([z.number(), z.string()]).optional(),
});
const { globalActiveSheet } = useClockInStatus();

const methods = useForm<PaymentFormValue>({
mode: 'all',
Expand All @@ -47,7 +49,7 @@ const Payments: React.FC<PaymentProps> = ({ bill, selectedLineItems }) => {

const hasMoreThanOneLineItem = bill?.lineItems?.length > 1;
const computedTotal = hasMoreThanOneLineItem ? computeTotalPrice(selectedLineItems) : bill.totalAmount ?? 0;
const totalAmountTendered = formValues?.reduce((curr: number, prev) => curr + Number(prev.amount) ?? 0, 0) ?? 0;
const totalAmountTendered = formValues?.reduce((curr: number, prev) => curr + Number(prev.amount), 0) ?? 0;
const amountDue = Number(bill.totalAmount) - (Number(bill.tenderedAmount) + Number(totalAmountTendered));

const handleNavigateToBillingDashboard = () =>
Expand All @@ -57,7 +59,14 @@ const Payments: React.FC<PaymentProps> = ({ bill, selectedLineItems }) => {

const handleProcessPayment = () => {
const { remove } = formArrayMethods;
const paymentPayload = createPaymentPayload(bill, bill.patientUuid, formValues, amountDue, selectedLineItems);
const paymentPayload = createPaymentPayload(
bill,
bill.patientUuid,
formValues,
amountDue,
selectedLineItems,
globalActiveSheet,
);
remove();
processBillPayment(paymentPayload, bill.uuid).then(
(resp) => {
Expand Down Expand Up @@ -104,13 +113,13 @@ const Payments: React.FC<PaymentProps> = ({ bill, selectedLineItems }) => {
<InvoiceBreakDown label={t('totalAmount', 'Total Amount')} value={convertToCurrency(bill.totalAmount)} />
<InvoiceBreakDown
label={t('totalTendered', 'Total Tendered')}
value={convertToCurrency(bill.tenderedAmount + totalAmountTendered ?? 0)}
value={convertToCurrency(bill.tenderedAmount + totalAmountTendered)}
/>
<InvoiceBreakDown label={t('discount', 'Discount')} value={'--'} />
<InvoiceBreakDown
hasBalance={amountDue < 0 ?? false}
hasBalance={amountDue < 0}
label={amountDueDisplay(amountDue)}
value={convertToCurrency(amountDue ?? 0)}
value={convertToCurrency(amountDue)}
/>
<div className={styles.processPayments}>
<Button onClick={handleNavigateToBillingDashboard} kind="secondary">
Expand Down
27 changes: 20 additions & 7 deletions packages/esm-billing-app/src/invoice/payments/payments.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React from 'react';
import { showSnackbar } from '@openmrs/esm-framework';
import { render, screen } from '@testing-library/react';
import Payments from './payments.component';
import { mockBill, mockLineItems, mockPaymentModes } from '../../../../../__mocks__/bills.mock';
import { processBillPayment, usePaymentModes } from '../../billing.resource';
import userEvent from '@testing-library/user-event';
import { showSnackbar } from '@openmrs/esm-framework';

import React from 'react';
import { mockBill, mockedActiveSheet, mockLineItems, mockPaymentModes } from '../../../../../__mocks__/bills.mock';
import { processBillPayment, usePaymentModes } from '../../billing.resource';
import { useClockInStatus } from '../../payment-points/use-clock-in-status';
import Payments from './payments.component';
const mockProcessBillPayment = processBillPayment as jest.MockedFunction<typeof processBillPayment>;
const mockUsePaymentModes = usePaymentModes as jest.MockedFunction<typeof usePaymentModes>;
const mockShowSnackbar = showSnackbar as jest.MockedFunction<typeof showSnackbar>;
Expand All @@ -15,6 +15,9 @@ jest.mock('../../billing.resource', () => ({
usePaymentModes: jest.fn(),
}));

jest.mock('../../payment-points/use-clock-in-status');
const mockedUseClockInStatus = useClockInStatus as jest.Mock;

describe('Payment', () => {
test('should display error when posting payment fails', async () => {
const user = userEvent.setup();
Expand All @@ -35,6 +38,16 @@ describe('Payment', () => {
error: null,
mutate: jest.fn(),
});

mockedUseClockInStatus.mockReturnValue({
globalActiveSheet: mockedActiveSheet,
localActiveSheet: undefined,
isClockedInSomewhere: true,
error: null,
isLoading: false,
isClockedInCurrentPaymentPoint: false,
});

render(<Payments bill={mockBill as any} selectedLineItems={mockLineItems} />);
const addPaymentMethod = screen.getByRole('button', { name: /Add payment option/i });
await user.click(addPaymentMethod);
Expand All @@ -51,7 +64,7 @@ describe('Payment', () => {
expect(mockProcessBillPayment).toHaveBeenCalledTimes(1);
expect(mockProcessBillPayment).toHaveBeenCalledWith(
{
cashPoint: '54065383-b4d4-42d2-af4d-d250a1fd2590',
cashPoint: mockedActiveSheet.cashPoint.uuid,
cashier: 'fe00dd43-4c39-4ce9-9832-bc3620c80c6c',
lineItems: [
{
Expand Down
5 changes: 3 additions & 2 deletions packages/esm-billing-app/src/invoice/payments/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FormPayment, LineItem, MappedBill } from '../../types';
import { FormPayment, LineItem, MappedBill, Timesheet } from '../../types';

export const hasLineItem = (lineItems: Array<LineItem>, item: LineItem) => {
if (lineItems?.length === 0) {
Expand All @@ -14,6 +14,7 @@ export const createPaymentPayload = (
formValues: Array<FormPayment>,
amountDue: number,
selectedLineItems: Array<LineItem>,
timesheet: Timesheet,
) => {
const { cashier } = bill;
const totalAmount = bill?.totalAmount;
Expand Down Expand Up @@ -51,7 +52,7 @@ export const createPaymentPayload = (
updatedLineItems.filter((item) => item.paymentStatus === 'PENDING').length === 0 ? 'PAID' : 'PENDING';

const processedPayment = {
cashPoint: bill.cashPointUuid,
cashPoint: timesheet?.cashPoint?.uuid,
cashier: cashier.uuid,
lineItems: updatedLineItems,
payments: [...updatedPayments],
Expand Down
Loading