Skip to content
Closed
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
5 changes: 5 additions & 0 deletions public/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1301,6 +1301,7 @@
"confirm_removing_member_description": "Are you sure you want to remove {{member}} from the care team?",
"confirm_selection": "Confirm Selection",
"confirm_submission": "Confirm Submission",
"confirm_to_proceed_with_payment": "Are you sure you want to proceed with this payment?",
"confirm_transfer_complete": "Confirm Transfer Complete!",
"confirm_unavailability": "Confirm Unavailability",
"confirmation_dialog_input_label": "To confirm, please type <code>{{ confirmationText }}</code> below.",
Expand Down Expand Up @@ -1733,6 +1734,7 @@
"didnt_receive_a_message": "Didn't receive a message?",
"diet": "Diet",
"diet_preference": "Diet Preference",
"difference": "Difference",
"differential": "Differential",
"differential_diagnosis": "Differential diagnosis",
"direct_deposit": "Direct Deposit",
Expand Down Expand Up @@ -3983,13 +3985,15 @@
"pause_request": "Pause Request",
"payment": "Payment",
"payment_amount": "Payment Amount",
"payment_amount_exceeds_invoice_warning": "The payment amount you entered is greater than the invoice total. This may result in an overpayment or advance payment for this invoice.",
"payment_cancelled": "Payment Cancelled",
"payment_cancelled_successfully": "Payment cancelled successfully",
"payment_date": "Payment Date",
"payment_date_cannot_be_in_future": "Payment date cannot be in the future",
"payment_details": "Payment Details",
"payment_due": "Payment Due",
"payment_due_message": "A payment of {{amount}} is due by {{date}}",
"payment_exceeds_invoice_amount": "Payment Exceeds Invoice Amount",
"payment_history": "Payment History",
"payment_id": "Payment ID",
"payment_may_not_exist": "The payment you are looking for may not exist.",
Expand Down Expand Up @@ -6162,6 +6166,7 @@
"yes": "Yes",
"yes_cancel_invoice": "Yes, Cancel Invoice",
"yes_cancel_payment": "Yes, Cancel Payment",
"yes_proceed": "Yes, Proceed",
"yesterday": "Yesterday",
"yet_to_be_decided": "Yet to be decided",
"you_cannot_change_once_submitted": "You cannot change once submitted.",
Expand Down
85 changes: 84 additions & 1 deletion src/pages/Facility/billing/PaymentReconciliationSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
import { format } from "date-fns";
import { t } from "i18next";
import { useAtom } from "jotai";
import { useEffect, useMemo } from "react";
import { useEffect, useMemo, useState } from "react";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
Expand All @@ -15,6 +15,7 @@ import CareIcon from "@/CAREUI/icons/CareIcon";

import careConfig from "@careConfig";

import ConfirmActionDialog from "@/components/Common/ConfirmActionDialog";
import { Button } from "@/components/ui/button";
import {
Form,
Expand Down Expand Up @@ -187,6 +188,10 @@ export function PaymentReconciliationSheet({
const [selectedLocationObject, setSelectedLocationObject] = useAtom(
paymentReconcilationLocationAtom(facilityId),
);
const [showExceedsWarning, setShowExceedsWarning] = useState(false);
const [pendingFormData, setPendingFormData] = useState<z.infer<
typeof formSchema
> | null>(null);
Comment on lines +191 to +194
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider extracting the form schema type for clarity.

The type z.infer<typeof formSchema> references formSchema which is defined below (line 187). While TypeScript resolves this correctly at compile time, it reduces readability. Consider extracting the type near createFormSchema:

type PaymentReconciliationFormData = z.infer<ReturnType<typeof createFormSchema>>;

Then use PaymentReconciliationFormData | null for pendingFormData.

🤖 Prompt for AI Agents
In `@src/pages/Facility/billing/PaymentReconciliationSheet.tsx` around lines 181 -
184, Extract a named type for the form schema and use it for pendingFormData to
improve readability: define a type alias like PaymentReconciliationFormData
using z.infer<ReturnType<typeof createFormSchema>> (place this alias near the
createFormSchema definition) and then change the pendingFormData state to use
PaymentReconciliationFormData | null instead of z.infer<typeof formSchema>;
update any other references to the anonymous inferred type to use the new alias
(symbols to touch: createFormSchema, formSchema, pendingFormData).

useShortcutSubContext();

const { getExtensions, isLoading: isExtensionsLoading } =
Expand Down Expand Up @@ -291,6 +296,17 @@ export function PaymentReconciliationSheet({
formExtensions as NamespacedExtensionData,
);

// Check if payment exceeds invoice amount
if (
invoice &&
data.amount &&
new Decimal(data.amount).greaterThan(new Decimal(invoice.total_gross))
) {
setPendingFormData(data);
setShowExceedsWarning(true);
return;
}

// Convert form data to PaymentReconciliationCreate type
const submissionData: PaymentReconciliationCreate = {
...restData,
Expand All @@ -301,6 +317,24 @@ export function PaymentReconciliationSheet({
submitPayment(submissionData);
});

const handleConfirmExceedingPayment = () => {
if (pendingFormData) {
const { extensions: formExtensions, ...restData } = pendingFormData;
const cleanedExtensions = extensions.prepareForSubmit(
formExtensions as NamespacedExtensionData,
);
const submissionData: PaymentReconciliationCreate = {
...restData,
is_credit_note: isCreditNote,
location: restData.location,
extensions: cleanedExtensions,
};
submitPayment(submissionData);
setShowExceedsWarning(false);
setPendingFormData(null);
}
};

useEffect(() => {
if (open) {
const initialAmount = invoice?.total_gross
Expand Down Expand Up @@ -712,6 +746,55 @@ export function PaymentReconciliationSheet({
</form>
</Form>
</SheetContent>

<ConfirmActionDialog
open={showExceedsWarning}
onOpenChange={(open) => {
setShowExceedsWarning(open);
if (!open) {
setPendingFormData(null);
}
}}
title={t("payment_exceeds_invoice_amount")}
description={
<div className="space-y-2">
<p>{t("payment_amount_exceeds_invoice_warning")}</p>
<div className="rounded-md bg-yellow-50 border border-yellow-200 p-3 space-y-1">
<div className="flex justify-between text-sm">
<span className="text-gray-700">{t("invoice_total")}:</span>
<span className="font-semibold text-gray-900">
<MonetaryDisplay amount={invoice?.total_gross} />
</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-700">{t("payment_amount")}:</span>
<span className="font-semibold text-gray-900">
<MonetaryDisplay amount={pendingFormData?.amount} />
</span>
</div>
<div className="flex justify-between text-sm border-t border-yellow-300 pt-1 mt-1">
<span className="text-gray-700">{t("difference")}:</span>
<span className="font-bold text-yellow-900">
<MonetaryDisplay
amount={
pendingFormData?.amount && invoice?.total_gross
? new Decimal(pendingFormData.amount)
.minus(new Decimal(invoice.total_gross))
.toString()
: "0"
}
/>
</span>
</div>
</div>
<p className="text-sm font-medium">
{t("confirm_to_proceed_with_payment")}
</p>
</div>
}
onConfirm={handleConfirmExceedingPayment}
confirmText={t("yes_proceed")}
/>
</Sheet>
);
}
Expand Down
Loading