From 6dade11d8fe0f645aa04870fad829f1d049ee770 Mon Sep 17 00:00:00 2001 From: l0gesh29 Date: Fri, 9 Jan 2026 19:08:23 +0530 Subject: [PATCH] fix: add validation for return against (cherry picked from commit ff9b936634fbd3d17677dbe124cab3521c0458f7) --- .../doctype/sales_invoice/sales_invoice.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 45791a66083..53eb92a9b3f 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -823,6 +823,7 @@ class SalesInvoice(SellingController): self.is_return and self.return_against and data.sales_invoice + and data.sales_invoice == self.return_against and not sales_invoice and args.timesheet_detail == data.name ) @@ -865,12 +866,10 @@ class SalesInvoice(SellingController): payment.account = get_bank_cash_account(payment.mode_of_payment, self.company).get("account") def validate_time_sheets_are_submitted(self): + # Note: This validation is skipped for return invoices + # to allow returns to reference already-billed timesheet details for data in self.timesheets: - if data.time_sheet: - status = frappe.db.get_value("Timesheet", data.time_sheet, "status") - if status not in ["Submitted", "Payslip", "Partially Billed"]: - frappe.throw(_("Timesheet {0} is already completed or cancelled").format(data.time_sheet)) - + # Handle invoice duplication if data.time_sheet and data.timesheet_detail: if sales_invoice := frappe.db.get_value( "Timesheet Detail", data.timesheet_detail, "sales_invoice" @@ -881,6 +880,11 @@ class SalesInvoice(SellingController): ) ) + if data.time_sheet: + status = frappe.db.get_value("Timesheet", data.time_sheet, "status") + if status not in ["Submitted", "Payslip", "Partially Billed"]: + frappe.throw(_("Timesheet {0} is already completed or cancelled").format(data.time_sheet)) + def set_pos_fields(self, for_validate=False): """Set retail related fields from POS Profiles""" if cint(self.is_pos) != 1: