diff --git a/propms/lease_invoice_schedule.py b/propms/lease_invoice_schedule.py index 78fcb35..717301f 100644 --- a/propms/lease_invoice_schedule.py +++ b/propms/lease_invoice_schedule.py @@ -1,62 +1,84 @@ from __future__ import unicode_literals import frappe -from frappe.utils import add_days, today, getdate, add_months +from frappe.utils import add_days, today, getdate, add_months, get_first_day, get_last_day from propms.auto_custom import app_error_log, makeInvoiceSchedule, getDateMonthDiff from frappe.query_builder import DocType +def get_aligned_invoice_date(date): + """Returns the first day of the month for the given date""" + return get_first_day(date) + @frappe.whitelist() def make_lease_invoice_schedule(): + # First check if make_invoice_schedule_up_to_tomorrow_only is enabled settings = frappe.get_single("Property Management Settings") - if not settings.get("make_invoice_schedule_up_to_tomorrow_only", 0): + make_schedule_up_to_tomorrow = settings.get("make_invoice_schedule_up_to_tomorrow_only", 0) + if not make_schedule_up_to_tomorrow: return - invoice_start_date = getdate(settings.get("invoice_start_date", None)) - + + # Proceed with other computations only if the setting is enabled use_valid_from_date = settings.use_valid_from_date today_date = getdate(today()) - next_month_end = add_days(add_months(today_date, 1), -1) + next_month_end = get_last_day(add_months(today_date, 1)) # End of next month + invoice_start_date = getdate(settings.get("invoice_start_date", None)) + + if not invoice_start_date: + frappe.throw("Please set Invoice Start Date in Property Management Settings") Lease = DocType("Lease") query = ( frappe.qb.from_(Lease) .select(Lease.name) - .where(Lease.start_date <= today_date) + .where( + (Lease.start_date <= today_date) + # Only check start_date, ignore end_date for inclusion + ) ) lease_names = [row[0] for row in frappe.db.sql(query.get_sql())] - freq_map = { - "Monthly": 1.0, - "Bi-Monthly": 2.0, - "Quarterly": 3.0, - "6 months": 6.0, - "Annually": 12.0, - } - for lease_name in lease_names: try: lease = frappe.get_doc("Lease", lease_name) + lease_start = getdate(lease.start_date) schedule_end = getdate(lease.end_date) if lease.end_date else next_month_end - schedule_start = invoice_start_date if invoice_start_date > lease.start_date else lease.start_date + + # Use the later date between lease_start and invoice_start_date + schedule_start = max(lease_start, invoice_start_date) if lease_start else invoice_start_date if not schedule_start: - continue + continue # skip if no start_date + # Clean up schedule entries for removed lease items lease_item_names = [li.lease_item for li in lease.lease_item] schedule_items = frappe.get_all("Lease Invoice Schedule", filters={"parent": lease.name}, fields=["name", "lease_item"]) for s in schedule_items: if s.lease_item not in lease_item_names: frappe.delete_doc("Lease Invoice Schedule", s.name) + # Frequency map + freq_map = { + "Monthly": 1.0, + "Bi-Monthly": 2.0, + "Quarterly": 3.0, + "6 months": 6.0, + "Annually": 12.0, + } + idx = 1 for item in lease.lease_item: if not item.frequency: continue + freq = freq_map.get(item.frequency) if not freq: frappe.log_error(f"Invalid frequency '{item.frequency}' for item {item.lease_item} in lease {lease.name}", "Invalid Frequency") continue invoice_qty = float(freq) + + # Default to base amount item_amount = item.amount + # Get the latest active lease item that has valid_from date lease_items = frappe.get_all( "Lease Item", filters={ @@ -68,13 +90,20 @@ def make_lease_invoice_schedule(): order_by="valid_from desc", limit=1 ) + + # Use amount from the most recent active lease item if found if use_valid_from_date and lease_items: item_amount = lease_items[0].amount - invoice_date = schedule_start + # Get the first day of the month in which schedule_start falls + invoice_date = get_first_day(schedule_start) + + # Generate invoice schedules up to next month while schedule_end >= invoice_date and invoice_date <= next_month_end: - invoice_period_end = add_days(add_months(invoice_date, freq), -1) + # Calculate period end as last day of the month after freq months + invoice_period_end = get_last_day(add_months(invoice_date, freq - 1)) + # Only create schedule if date_to_invoice is between invoice start date and today + next month if schedule_start <= invoice_date <= next_month_end: exists = frappe.db.exists( "Lease Invoice Schedule", @@ -84,6 +113,7 @@ def make_lease_invoice_schedule(): "date_to_invoice": invoice_date, } ) + if not exists: makeInvoiceSchedule( invoice_date, @@ -103,6 +133,7 @@ def make_lease_invoice_schedule(): frappe.db.commit() idx += 1 + # Move to first day of next period invoice_date = add_days(invoice_period_end, 1) frappe.msgprint(f"Completed invoice schedule for Lease: {lease.name}")