Skip to content
Merged
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
67 changes: 49 additions & 18 deletions propms/lease_invoice_schedule.py
Original file line number Diff line number Diff line change
@@ -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))

Check notice on line 18 in propms/lease_invoice_schedule.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

propms/lease_invoice_schedule.py#L18

Trailing whitespace
# 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={
Expand All @@ -68,13 +90,20 @@
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",
Expand All @@ -84,6 +113,7 @@
"date_to_invoice": invoice_date,
}
)

if not exists:
makeInvoiceSchedule(
invoice_date,
Expand All @@ -103,6 +133,7 @@
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}")
Expand Down