From 2f564b0983abbbcea781e54423dd2161be712ac0 Mon Sep 17 00:00:00 2001 From: got Date: Wed, 9 Jul 2025 17:25:28 +0200 Subject: [PATCH 1/4] init # Conflicts: # erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.js --- .../soldes_intermediaires_de_gestion.js | 2 +- .../soldes_intermediaires_de_gestion.py | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.js b/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.js index 133d5c75c8..7070f20f83 100644 --- a/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.js +++ b/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.js @@ -13,7 +13,7 @@ frappe.query_reports["Soldes Intermediaires de Gestion"]["filters"].splice(1, 1) Object.assign(frappe.query_reports["Soldes Intermediaires de Gestion"], { "formatter": function(value, row, column, data, default_formatter, filter) { - if (row[1].content && column.fieldtype == "Currency") { + if (row[1].content && ["Currency", "Percent"].includes(column.fieldtype)) { value = default_formatter(value, row, column, data); } return value || ""; diff --git a/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py b/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py index 4a09c5f6e5..349f22f5a7 100644 --- a/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py +++ b/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py @@ -97,11 +97,21 @@ class SIGCalculator: "width": 150, } ) + # Ajoute la colonne pourcentage pour chaque période + columns.append( + { + "fieldname": f"{period.key}_pct", + "label": f"{period.label} (%)", + "fieldtype": "Percent", + "width": 50, # largeur réduite + } + ) return columns def get_data(self): self.data = defaultdict(dict) + self.ca_by_period = {} for period in self.period_list: self.period_key = period.key @@ -115,6 +125,13 @@ class SIGCalculator: self.calcul_resultat_exceptionnel() self.calcul_resultat_net() + # Calcul du CA pour la période courante + ca = ( + self.data[_("Ventes de marchandise")].get(self.period_key, 0.0) + + self.data[_("Production vendue")].get(self.period_key, 0.0) + ) + self.ca_by_period[self.period_key] = ca if ca else 1e-9 # éviter division par zéro + result = [] empty_row = False for label in self.labels: @@ -129,6 +146,16 @@ class SIGCalculator: row["bold"] = True empty_row = True + # Ajoute le pourcentage pour chaque période (toujours en valeur absolue, arrondi sans virgule) + for period in self.period_list: + val = row.get(period.key, 0.0) + ca = self.ca_by_period.get(period.key, 1e-9) + if not self.ca_by_period.get(period.key): # CA == 0 + percent = 0.0 + else: + percent = (abs(val) / abs(ca) * 100) + row[f"{period.key}_pct"] = round(percent) + result.append(row) return result -- GitLab From dac6d2099d0e0cde5e485befc286eda58525eee3 Mon Sep 17 00:00:00 2001 From: Charles-Henri Decultot Date: Thu, 10 Jul 2025 09:18:02 +0200 Subject: [PATCH 2/4] fix: Make report compatible with v5 --- .../soldes_intermediaires_de_gestion.py | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py b/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py index 349f22f5a7..70bd9efffe 100644 --- a/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py +++ b/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py @@ -103,7 +103,7 @@ class SIGCalculator: "fieldname": f"{period.key}_pct", "label": f"{period.label} (%)", "fieldtype": "Percent", - "width": 50, # largeur réduite + "width": 100, # largeur réduite } ) @@ -111,7 +111,7 @@ class SIGCalculator: def get_data(self): self.data = defaultdict(dict) - self.ca_by_period = {} + self.turnover_by_period = {} for period in self.period_list: self.period_key = period.key @@ -126,11 +126,10 @@ class SIGCalculator: self.calcul_resultat_net() # Calcul du CA pour la période courante - ca = ( - self.data[_("Ventes de marchandise")].get(self.period_key, 0.0) - + self.data[_("Production vendue")].get(self.period_key, 0.0) - ) - self.ca_by_period[self.period_key] = ca if ca else 1e-9 # éviter division par zéro + ca = self.data[_("Ventes de marchandise")].get(self.period_key, 0.0) + self.data[ + _("Production vendue") + ].get(self.period_key, 0.0) + self.turnover_by_period[self.period_key] = ca if ca else 1e-9 # éviter division par zéro result = [] empty_row = False @@ -149,11 +148,11 @@ class SIGCalculator: # Ajoute le pourcentage pour chaque période (toujours en valeur absolue, arrondi sans virgule) for period in self.period_list: val = row.get(period.key, 0.0) - ca = self.ca_by_period.get(period.key, 1e-9) - if not self.ca_by_period.get(period.key): # CA == 0 + ca = self.turnover_by_period.get(period.key, 1e-9) + if not self.turnover_by_period.get(period.key): # CA == 0 percent = 0.0 else: - percent = (abs(val) / abs(ca) * 100) + percent = abs(val) / abs(ca) * 100 row[f"{period.key}_pct"] = round(percent) result.append(row) @@ -161,7 +160,7 @@ class SIGCalculator: return result def get_accounts( - self, account_type: str, selected_numbers: tuple | str, excluded_numbers: list = None + self, account_type: str, selected_numbers: tuple | str, excluded_numbers: list | None = None ): accounts_list = self.revenue_accounts if account_type == "revenue" else self.expense_accounts @@ -175,21 +174,28 @@ class SIGCalculator: else: return [a.name for a in accounts_list if a.account_number.startswith(selected_numbers)] - def get_accounting_entries(self, accounts): + def get_accounting_entries(self, lft, rgt): return get_accounting_entries( - "GL Entry", - self.period.from_date, - self.period.to_date, - accounts, - self.filters, - True, + doctype="GL Entry", + from_date=self.period.from_date, + to_date=self.period.to_date, + root_lft=lft, + root_rgt=rgt, + filters=self.filters, + ignore_closing_entries=True, + ignore_opening_entries=True, ) def get_accounts_balance(self, accounts): if not accounts: return 0.0 - entries = self.get_accounting_entries(accounts) + entries = [] + for account in accounts: # TODO: Optimize query + if account_details := frappe.get_all( + "Account", filters={"name": account}, fields=["min(lft) as lft", "max(rgt) as rgt"] + ): + entries.extend(self.get_accounting_entries(account_details[0].lft, account_details[0].rgt)) # type: ignore return sum(entry.credit - entry.debit for entry in entries) @@ -246,9 +252,7 @@ class SIGCalculator: # 3.2 Variation des stocks de matières premières stock_variation_accounts = self.get_accounts("expense", "603", "6037") total_stock_variations = self.get_accounts_balance(stock_variation_accounts) - self.data[_("Variation des stocks de matières premières")][ - self.period_key - ] = total_stock_variations + self.data[_("Variation des stocks de matières premières")][self.period_key] = total_stock_variations # 3.3 Autres achats et charges externes external_expenses_accounts = self.get_accounts("expense", ("61", "62")) -- GitLab From 4ac8b2b2209b51cdeb0742d84b28d604e37cb41c Mon Sep 17 00:00:00 2001 From: Charles-Henri Decultot Date: Thu, 10 Jul 2025 09:23:12 +0200 Subject: [PATCH 3/4] fix: naming and handle division by zero risk --- .../soldes_intermediaires_de_gestion.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py b/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py index 70bd9efffe..85f1a2be93 100644 --- a/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py +++ b/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py @@ -126,10 +126,9 @@ class SIGCalculator: self.calcul_resultat_net() # Calcul du CA pour la période courante - ca = self.data[_("Ventes de marchandise")].get(self.period_key, 0.0) + self.data[ - _("Production vendue") - ].get(self.period_key, 0.0) - self.turnover_by_period[self.period_key] = ca if ca else 1e-9 # éviter division par zéro + self.turnover_by_period[self.period_key] = self.data[_("Ventes de marchandise")].get( + self.period_key, 0.0 + ) + self.data[_("Production vendue")].get(self.period_key, 0.0) result = [] empty_row = False @@ -148,11 +147,11 @@ class SIGCalculator: # Ajoute le pourcentage pour chaque période (toujours en valeur absolue, arrondi sans virgule) for period in self.period_list: val = row.get(period.key, 0.0) - ca = self.turnover_by_period.get(period.key, 1e-9) - if not self.turnover_by_period.get(period.key): # CA == 0 + period_turnover = self.turnover_by_period.get(period.key) + if not period_turnover: percent = 0.0 else: - percent = abs(val) / abs(ca) * 100 + percent = abs(val) / abs(period_turnover) * 100 row[f"{period.key}_pct"] = round(percent) result.append(row) -- GitLab From f15b993d8e1a23c06c13b4b0ef1861bf05ab8793 Mon Sep 17 00:00:00 2001 From: Charles-Henri Decultot Date: Thu, 10 Jul 2025 11:26:08 +0200 Subject: [PATCH 4/4] fix: adjust API to v4 --- .../soldes_intermediaires_de_gestion.py | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py b/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py index 85f1a2be93..3f54acb3b0 100644 --- a/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py +++ b/erpnext/regional/report/soldes_intermediaires_de_gestion/soldes_intermediaires_de_gestion.py @@ -173,28 +173,22 @@ class SIGCalculator: else: return [a.name for a in accounts_list if a.account_number.startswith(selected_numbers)] - def get_accounting_entries(self, lft, rgt): + def get_accounting_entries(self, accounts): return get_accounting_entries( - doctype="GL Entry", - from_date=self.period.from_date, - to_date=self.period.to_date, - root_lft=lft, - root_rgt=rgt, - filters=self.filters, - ignore_closing_entries=True, - ignore_opening_entries=True, + "GL Entry", + self.period.from_date, + self.period.to_date, + accounts, + self.filters, + True, ) + def get_accounts_balance(self, accounts): if not accounts: return 0.0 - entries = [] - for account in accounts: # TODO: Optimize query - if account_details := frappe.get_all( - "Account", filters={"name": account}, fields=["min(lft) as lft", "max(rgt) as rgt"] - ): - entries.extend(self.get_accounting_entries(account_details[0].lft, account_details[0].rgt)) # type: ignore + entries = self.get_accounting_entries(accounts) return sum(entry.credit - entry.debit for entry in entries) -- GitLab