From e1405a5c4f23ed6c011e510b9c537926439f6669 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 14 Jan 2025 16:59:15 +0530 Subject: [PATCH] refactor: allow users to configure interval for Semi-Auto payment reconciliation (#45211) * refactor: configurable interval for reconciliation trigger * refactor: set default value for interval * refactor: configurable queue size * refactor: use patch to setup default cron job * refactor: use 'after_migrate' to setup cron for reconciliation User specified interval will be used * chore: type casting * refactor: use scheduler_event to persist cron * chore: rename field * chore: use configured queue size * chore: remove unwanted field (cherry picked from commit ce9c606f718835a76916ee4bc8634ce0168de34c) --- .../accounts_settings/accounts_settings.json | 30 ++++++++++++++-- .../accounts_settings/accounts_settings.py | 19 ++++++++++ .../process_payment_reconciliation.py | 2 +- erpnext/accounts/utils.py | 35 +++++++++++++++++++ erpnext/hooks.py | 1 - erpnext/patches.txt | 1 + .../v15_0/sync_auto_reconcile_config.py | 26 ++++++++++++++ 7 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 erpnext/patches/v15_0/sync_auto_reconcile_config.py diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index e9b383776f3..98007e963ea 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -40,9 +40,13 @@ "show_payment_schedule_in_print", "currency_exchange_section", "allow_stale", + "column_break_yuug", + "stale_days", "section_break_jpd0", "auto_reconcile_payments", - "stale_days", + "auto_reconciliation_job_trigger", + "reconciliation_queue_size", + "column_break_resa", "invoicing_settings_tab", "accounts_transactions_settings_section", "over_billing_allowance", @@ -489,6 +493,28 @@ "fieldname": "create_pr_in_draft_status", "fieldtype": "Check", "label": "Create in Draft Status" + }, + { + "fieldname": "column_break_yuug", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_resa", + "fieldtype": "Column Break" + }, + { + "default": "15", + "description": "Interval should be between 1 to 59 MInutes", + "fieldname": "auto_reconciliation_job_trigger", + "fieldtype": "Int", + "label": "Auto Reconciliation Job Trigger" + }, + { + "default": "5", + "description": "Documents Processed on each trigger. Queue Size should be between 5 and 100", + "fieldname": "reconciliation_queue_size", + "fieldtype": "Int", + "label": "Reconciliation Queue Size" } ], "icon": "icon-cog", @@ -496,7 +522,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2024-07-26 06:48:52.714630", + "modified": "2025-01-13 17:38:39.661320", "modified_by": "Administrator", "module": "Accounts", "name": "Accounts Settings", diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py index 608b3a96f2f..c2dafafc251 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py @@ -10,6 +10,7 @@ from frappe.custom.doctype.property_setter.property_setter import make_property_ from frappe.model.document import Document from frappe.utils import cint +from erpnext.accounts.utils import sync_auto_reconcile_config from erpnext.stock.utils import check_pending_reposting @@ -27,6 +28,7 @@ class AccountsSettings(Document): allow_multi_currency_invoices_against_single_party_account: DF.Check allow_stale: DF.Check auto_reconcile_payments: DF.Check + auto_reconciliation_job_trigger: DF.Int automatically_fetch_payment_terms: DF.Check automatically_process_deferred_accounting_entry: DF.Check book_asset_depreciation_entry_automatically: DF.Check @@ -51,6 +53,7 @@ class AccountsSettings(Document): over_billing_allowance: DF.Currency post_change_gl_entries: DF.Check receivable_payable_remarks_length: DF.Int + reconciliation_queue_size: DF.Int role_allowed_to_over_bill: DF.Link | None round_row_wise_tax: DF.Check show_balance_in_coa: DF.Check @@ -90,6 +93,8 @@ class AccountsSettings(Document): if clear_cache: frappe.clear_cache() + self.validate_and_sync_auto_reconcile_config() + def validate_stale_days(self): if not self.allow_stale and cint(self.stale_days) <= 0: frappe.msgprint( @@ -114,3 +119,17 @@ class AccountsSettings(Document): def validate_pending_reposts(self): if self.acc_frozen_upto: check_pending_reposting(self.acc_frozen_upto) + + def validate_and_sync_auto_reconcile_config(self): + if self.has_value_changed("auto_reconciliation_job_trigger"): + if ( + cint(self.auto_reconciliation_job_trigger) > 0 + and cint(self.auto_reconciliation_job_trigger) < 60 + ): + sync_auto_reconcile_config(self.auto_reconciliation_job_trigger) + else: + frappe.throw(_("Cron Interval should be between 1 and 59 Min")) + + if self.has_value_changed("reconciliation_queue_size"): + if cint(self.reconciliation_queue_size) < 5 or cint(self.reconciliation_queue_size) > 100: + frappe.throw(_("Queue Size should be between 5 and 100")) diff --git a/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.py b/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.py index 35f1e31af34..c4c75913d65 100644 --- a/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.py +++ b/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.py @@ -210,7 +210,7 @@ def trigger_reconciliation_for_queued_docs(): docs_to_trigger = [] unique_filters = set() - queue_size = 5 + queue_size = frappe.db.get_single_value("Accounts Settings", "reconciliation_queue_size") or 5 fields = ["company", "party_type", "party", "receivable_payable_account", "default_advance_account"] diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index ae90819b409..a7f8581e0f8 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -2250,3 +2250,38 @@ def run_ledger_health_checks(): doc.general_and_payment_ledger_mismatch = True doc.checked_on = run_date doc.save() + + +def sync_auto_reconcile_config(auto_reconciliation_job_trigger: int = 15): + auto_reconciliation_job_trigger = auto_reconciliation_job_trigger or frappe.db.get_single_value( + "Accounts Settings", "auto_reconciliation_job_trigger" + ) + method = "erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.trigger_reconciliation_for_queued_docs" + + sch_event = frappe.get_doc( + "Scheduler Event", {"scheduled_against": "Process Payment Reconciliation", "method": method} + ) + if frappe.db.get_value("Scheduled Job Type", {"method": method}): + frappe.get_doc( + "Scheduled Job Type", + { + "method": method, + }, + ).update( + { + "cron_format": f"0/{auto_reconciliation_job_trigger} * * * *", + "scheduler_event": sch_event.name, + } + ).save() + else: + frappe.get_doc( + { + "doctype": "Scheduled Job Type", + "method": method, + "scheduler_event": sch_event.name, + "cron_format": f"0/{auto_reconciliation_job_trigger} * * * *", + "create_log": True, + "stopped": False, + "frequency": "Cron", + } + ).save() diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 882adec4d51..d5c43f5060d 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -412,7 +412,6 @@ scheduler_events = { "cron": { "0/15 * * * *": [ "erpnext.manufacturing.doctype.bom_update_log.bom_update_log.resume_bom_cost_update_jobs", - "erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.trigger_reconciliation_for_queued_docs", ], "0/30 * * * *": [ "erpnext.utilities.doctype.video.video.update_youtube_data", diff --git a/erpnext/patches.txt b/erpnext/patches.txt index a16f87de0dc..ad8400da318 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -388,3 +388,4 @@ erpnext.patches.v15_0.enable_allow_existing_serial_no erpnext.patches.v15_0.update_cc_in_process_statement_of_accounts erpnext.patches.v15_0.update_asset_status_to_work_in_progress erpnext.patches.v15_0.migrate_checkbox_to_select_for_reconciliation_effect +erpnext.patches.v15_0.sync_auto_reconcile_config diff --git a/erpnext/patches/v15_0/sync_auto_reconcile_config.py b/erpnext/patches/v15_0/sync_auto_reconcile_config.py new file mode 100644 index 00000000000..721364dcaa6 --- /dev/null +++ b/erpnext/patches/v15_0/sync_auto_reconcile_config.py @@ -0,0 +1,26 @@ +import frappe + +from erpnext.accounts.utils import sync_auto_reconcile_config + + +def execute(): + """ + Set default Cron Interval and Queue size + """ + frappe.db.set_single_value("Accounts Settings", "auto_reconciliation_job_trigger", 15) + frappe.db.set_single_value("Accounts Settings", "reconciliation_queue_size", 5) + + # Create Scheduler Event record if it doesn't exist + method = "erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation.trigger_reconciliation_for_queued_docs" + if not frappe.db.get_all( + "Scheduler Event", {"scheduled_against": "Process Payment Reconciliation", "method": method} + ): + frappe.get_doc( + { + "doctype": "Scheduler Event", + "scheduled_against": "Process Payment Reconciliation", + "method": method, + } + ).save() + + sync_auto_reconcile_config(15)