From 3d44b4d98c58af6fe21311f78f6e52991b413157 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 19 Jun 2026 15:02:34 +0530 Subject: [PATCH] refactor(sales_invoice): simplify TimesheetBillingService._update_time_sheet_detail The link-decision was a single four-way boolean OR (cyclomatic complexity C/16) where every branch repeated 'args.timesheet_detail == data.name'. Factor that match out as a loop guard and extract the remaining decision into _should_set_sales_invoice as ordered guard clauses. Behaviour is unchanged (project, link-on-submit, unlink-on-cancel and return paths preserved); characterization tests and the full timesheet suite are green. --- .../services/timesheet_billing.py | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/services/timesheet_billing.py b/erpnext/accounts/doctype/sales_invoice/services/timesheet_billing.py index f688363dfc7..50087588116 100644 --- a/erpnext/accounts/doctype/sales_invoice/services/timesheet_billing.py +++ b/erpnext/accounts/doctype/sales_invoice/services/timesheet_billing.py @@ -99,23 +99,24 @@ class TimesheetBillingService: doc.total_billing_hours = sum(flt(ts.billing_hours) for ts in doc.timesheets) def _update_time_sheet_detail(self, timesheet, args, sales_invoice: str | None) -> None: - doc = self.doc for data in timesheet.time_logs: - if ( - (doc.project and args.timesheet_detail == data.name) - or (not doc.project and not data.sales_invoice and args.timesheet_detail == data.name) - or ( - not sales_invoice - and data.sales_invoice == doc.name - and args.timesheet_detail == data.name - ) - or ( - doc.is_return - and doc.return_against - and data.sales_invoice - and data.sales_invoice == doc.return_against - and not sales_invoice - and args.timesheet_detail == data.name - ) - ): + if args.timesheet_detail == data.name and self._should_set_sales_invoice(data, sales_invoice): data.sales_invoice = sales_invoice + + def _should_set_sales_invoice(self, time_log, sales_invoice: str | None) -> bool: + """Whether this time log's sales-invoice link should be (re)set to sales_invoice.""" + doc = self.doc + if doc.project: + return True + if not time_log.sales_invoice: + return True + if not sales_invoice and time_log.sales_invoice == doc.name: + # clearing the link on cancellation of this invoice + return True + # clearing the link on a return raised against the original invoice + return bool( + doc.is_return + and doc.return_against + and not sales_invoice + and time_log.sales_invoice == doc.return_against + )