diff --git a/web-app/app/lib/actions/billActions.ts b/web-app/app/lib/actions/billActions.ts index ef7ee0b..a60ea3a 100644 --- a/web-app/app/lib/actions/billActions.ts +++ b/web-app/app/lib/actions/billActions.ts @@ -13,6 +13,7 @@ import { unstable_noStore, revalidatePath } from 'next/cache'; import { extractShareId, validateShareChecksum } from '@evidencija-rezija/shared-code'; import { validatePdfFile } from '../validators/pdfValidator'; import { checkUploadRateLimit } from '../uploadRateLimiter'; +import { shouldUpdateBillFwdStatusWhenAttached, shouldUpdateBillFwdStatusWhenPayed } from '../billForwardingHelpers'; export type State = { errors?: { @@ -72,102 +73,6 @@ const FormSchema = (t: IntlTemplateFn) => z.object({ }), }); -/** - * Checks if billFwdStatus should be updated to "pending" based on attachment conditions - * @param location - The billing location containing the bill - * @param currentBillId - The ID of the bill being updated (to exclude from check) - * @param hasNewAttachment - Whether a new attachment is being added - * @returns true if billFwdStatus should be set to "pending" - */ -const shouldUpdateBillFwdStatusWhenAttached = ( - location: BillingLocation, - currentBillId: string | undefined, - hasNewAttachment: boolean -): boolean => { - // Only proceed if a new attachment is being added - if (!hasNewAttachment) { - return false; - } - - // Check billFwdEnabled is true - if (location.billFwdEnabled !== true) { - return false; - } - - // Check billFwdStrategy is "when-attached" - if (location.billFwdStrategy !== "when-attached") { - return false; - } - - // Check bills have already been sent or are pending -> don't sent them again - if (location.billFwdStatus === "pending" || location.billFwdStatus === "sent") { - return false; - } - - // Check if ALL other bills have attachments - const otherBills = location.bills.filter(bill => bill._id !== currentBillId); - // filter only bills billed to tenant - // because bills billed to landlord should not trigger forwarding - const billsPayedByTenant = otherBills.filter(bill => bill.billedTo === BilledTo.Tenant); - - if(billsPayedByTenant.length === 0) { - // No other bills billed to tenant exist, so do not trigger forwarding - return false; - } - - const allOtherBillsHaveAttachments = billsPayedByTenant.every(bill => bill.attachment !== null); - - return allOtherBillsHaveAttachments; -}; - -/** - * Checks if billFwdStatus should be updated to "pending" based on paid status - * @param location - The billing location containing the bill - * @param currentBillId - The ID of the bill being updated (to exclude from check) - * @param isPaid - Whether the current bill is being marked as paid - * @returns true if billFwdStatus should be set to "pending" - */ -const shouldUpdateBillFwdStatusWhenPayed = ( - location: BillingLocation, - currentBillId: string | undefined, - isPaid: boolean -): boolean => { - // Only proceed if the bill is being marked as paid - if (!isPaid) { - return false; - } - - // Check billFwdEnabled is true - if (location.billFwdEnabled !== true) { - return false; - } - - // Check billFwdStrategy is "when-payed" - if (location.billFwdStrategy !== "when-payed") { - return false; - } - - // Check bills have already been sent or are pending -> don't sent them again - if (location.billFwdStatus === "pending" || location.billFwdStatus === "sent") { - return false; - } - - // Check if ALL other bills are paid - const otherBills = location.bills.filter(bill => bill._id !== currentBillId); - // filter only bills billed to tenant - // because bills billed to landlord should not trigger forwarding - const billsPayedByTenant = otherBills.filter(bill => bill.billedTo === BilledTo.Tenant); - - if(billsPayedByTenant.length === 0) { - // No other bills billed to tenant exist, so do not trigger forwarding - return false; - } - - const allOtherBillsPaid = billsPayedByTenant.every(bill => bill.paid === true); - - return allOtherBillsPaid; -}; - /** * converts the file to a format stored in the database * @param billAttachment diff --git a/web-app/app/lib/actions/monthActions.ts b/web-app/app/lib/actions/monthActions.ts index dd9b70d..e4b72e7 100644 --- a/web-app/app/lib/actions/monthActions.ts +++ b/web-app/app/lib/actions/monthActions.ts @@ -8,6 +8,7 @@ import { withUser } from '../auth'; import { unstable_noStore as noStore, unstable_noStore, revalidatePath } from 'next/cache'; import { getLocale } from 'next-intl/server'; import { gotoHomeWithMessage } from './navigationActions'; +import { shouldUpdateBillFwdStatusWhenPayed } from '../billForwardingHelpers'; /** * Server-side action which adds a new month to the database @@ -206,6 +207,46 @@ export const updateMonth = withUser(async ( await Promise.all(updatePromises); + // Check if bill forwarding should be triggered for any locations + const forwardingCheckPromises = Object.entries(updatesByLocation).map( + async ([locationId, locationUpdates]) => { + // Check if any bills were marked as paid + const hasPaidUpdate = locationUpdates.some(update => update.paid === true); + + if (!hasPaidUpdate) { + return; // Skip if no bills were marked as paid + } + + // Fetch the full location data to check forwarding conditions + const location = await dbClient.collection("lokacije").findOne({ + _id: locationId, + userId, + yearMonth: { + year: yearMonth.year, + month: yearMonth.month, + }, + }); + + if (!location) { + return; // Location not found + } + + // Check each bill update to see if it triggers forwarding + for (const update of locationUpdates) { + if (shouldUpdateBillFwdStatusWhenPayed(location, update.billId, update.paid)) { + // Update billFwdStatus to "pending" + await dbClient.collection("lokacije").updateOne( + { _id: locationId }, + { $set: { billFwdStatus: "pending" } } + ); + break; // Only need to set once per location + } + } + } + ); + + await Promise.all(forwardingCheckPromises); + // Revalidate the home page and multi-edit page to show fresh data revalidatePath('/home'); revalidatePath(`/home/multi-bill-edit/${yearMonth.year}/${yearMonth.month}`); diff --git a/web-app/app/lib/billForwardingHelpers.ts b/web-app/app/lib/billForwardingHelpers.ts new file mode 100644 index 0000000..9226882 --- /dev/null +++ b/web-app/app/lib/billForwardingHelpers.ts @@ -0,0 +1,97 @@ +import { BillingLocation, BilledTo } from '@evidencija-rezija/shared-code'; + +/** + * Checks if billFwdStatus should be updated to "pending" based on attachment status + * @param location - The billing location containing the bill + * @param currentBillId - The ID of the bill being updated (to exclude from check) + * @param hasNewAttachment - Whether a new attachment is being added to the current bill + * @returns true if billFwdStatus should be set to "pending" + */ +export const shouldUpdateBillFwdStatusWhenAttached = ( + location: BillingLocation, + currentBillId: string | undefined, + hasNewAttachment: boolean +): boolean => { + // Only proceed if a new attachment is being added + if (!hasNewAttachment) { + return false; + } + + // Check billFwdEnabled is true + if (location.billFwdEnabled !== true) { + return false; + } + + // Check billFwdStrategy is "when-attached" + if (location.billFwdStrategy !== "when-attached") { + return false; + } + + // Check bills have already been sent or are pending -> don't sent them again + if (location.billFwdStatus === "pending" || location.billFwdStatus === "sent") { + return false; + } + + // Check if ALL other bills have attachments + const otherBills = location.bills.filter(bill => bill._id !== currentBillId); + // filter only bills billed to tenant + // because bills billed to landlord should not trigger forwarding + const billsPayedByTenant = otherBills.filter(bill => bill.billedTo === BilledTo.Tenant); + + if(billsPayedByTenant.length === 0) { + // No other bills billed to tenant exist, so do not trigger forwarding + return false; + } + + const allOtherBillsHaveAttachments = billsPayedByTenant.every(bill => bill.attachment !== null); + + return allOtherBillsHaveAttachments; +}; + +/** + * Checks if billFwdStatus should be updated to "pending" based on paid status + * @param location - The billing location containing the bill + * @param currentBillId - The ID of the bill being updated (to exclude from check) + * @param isPaid - Whether the current bill is being marked as paid + * @returns true if billFwdStatus should be set to "pending" + */ +export const shouldUpdateBillFwdStatusWhenPayed = ( + location: BillingLocation, + currentBillId: string | undefined, + isPaid: boolean +): boolean => { + // Only proceed if the bill is being marked as paid + if (!isPaid) { + return false; + } + + // Check billFwdEnabled is true + if (location.billFwdEnabled !== true) { + return false; + } + + // Check billFwdStrategy is "when-payed" + if (location.billFwdStrategy !== "when-payed") { + return false; + } + + // Check bills have already been sent or are pending -> don't sent them again + if (location.billFwdStatus === "pending" || location.billFwdStatus === "sent") { + return false; + } + + // Check if ALL other bills are paid + const otherBills = location.bills.filter(bill => bill._id !== currentBillId); + // filter only bills billed to tenant + // because bills billed to landlord should not trigger forwarding + const billsPayedByTenant = otherBills.filter(bill => bill.billedTo === BilledTo.Tenant); + + if(billsPayedByTenant.length === 0) { + // No other bills billed to tenant exist, so do not trigger forwarding + return false; + } + + const allOtherBillsPaid = billsPayedByTenant.every(bill => bill.paid === true); + + return allOtherBillsPaid; +};