From 31e2d4ac5a21346a2ea2eb0db5f136e06c740e1b Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 1 Jul 2026 16:15:59 +0530 Subject: [PATCH 1/2] fix: prevent max recursion on supplier scorecard save on_update() called self.save(), which re-enters on_update() via run_post_save_methods(), recursing indefinitely when make_all_scorecards() keeps returning newly created periods. Guard the re-save with an in_rescore flag so the nested on_update() short-circuits, while still running the full validate() once to refresh score and standings. Co-Authored-By: Claude Opus 4.8 --- .../doctype/supplier_scorecard/supplier_scorecard.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py index 8c835a29912..a6bab72b1d8 100644 --- a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py +++ b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py @@ -55,8 +55,12 @@ class SupplierScorecard(Document): self.update_standing() def on_update(self): - score = make_all_scorecards(self.name) - if score > 0: + # Guard against recursion: the save() below re-enters on_update(). + if self.flags.in_rescore: + return + if make_all_scorecards(self.name) > 0: + # New periods were created; re-save to refresh score and standings. + self.flags.in_rescore = True self.save() def validate_standings(self): From 603404775bac969273b5e5528c6a554d815a8189 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 1 Jul 2026 16:19:52 +0530 Subject: [PATCH 2/2] fix: reset in_rescore flag after re-save Ensure the recursion guard only applies to the nested save() and is cleared afterwards, so a later save() on the same doc instance still creates periods. Co-Authored-By: Claude Opus 4.8 --- .../buying/doctype/supplier_scorecard/supplier_scorecard.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py index a6bab72b1d8..26e41c8ac76 100644 --- a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py +++ b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py @@ -61,7 +61,10 @@ class SupplierScorecard(Document): if make_all_scorecards(self.name) > 0: # New periods were created; re-save to refresh score and standings. self.flags.in_rescore = True - self.save() + try: + self.save() + finally: + self.flags.in_rescore = False def validate_standings(self): # Standings must form a continuous chain of bands covering 0 to 100 with no gaps or overlaps