création plots total et camembert suites à demande de matthieu

This commit is contained in:
pb 2025-06-30 21:49:29 +02:00
parent 6703b95df7
commit 3b4935bc6a
6 changed files with 3193 additions and 1698 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
.venv/
config

2372
compta.svg

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 25 KiB

4
config
View File

@ -1,4 +1,4 @@
[path]
wp-config=/var/www/bricolesocialclub.org/wp-config.php
wp-config=wp-config.php
budget=budget.csv
save_directory=/var/www/bsc.pbblanc.fr/wp-content/uploads/compta
save_directory=.

276
main.py
View File

@ -5,11 +5,14 @@ import configparser as cp
import os
from sankeyflow import Sankey
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import re
import datetime
import mariadb
import sys
import math
import numpy as np
from colorsys import hls_to_rgb
#node_central = 'total'
class BudgetLine():
@ -20,6 +23,8 @@ class BudgetLine():
self.revenue = revenue
class DBInfos():
name:str
user:str
@ -39,11 +44,30 @@ def main(path_b:str,
path_wp:str,
save_dir:str):
budget=import_csv(path_b)
create_budget_sankey(budget,save_dir)
budget = sort_des_budget(budget, 0)
#create_budget_sankey(budget,save_dir)
db_infos = get_db_infos(path_wp)
cursor = connect_mariadb(db_infos)
create_accounting_sankey(cursor, save_dir)
#cursor = connect_mariadb(db_infos)
#create_accounting_sankey(cursor, save_dir)
#finances, last_update = import_finances(cursor)
finances = import_csv(path_b)
finances = test_finance(finances)
last_update = rf'2025-01-01'
finances = sort_des_budget(finances, 0)
tot_rev = get_total_revenues(finances)
tot_ch = get_total_charges(finances)
totals = get_totals_lists_for_charts(
tot_ch_bud = get_total_charges(budget),
tot_ch_real = tot_ch,
tot_re_bud = get_total_revenues(budget),
tot_re_real = tot_rev
)
revenue_ratios = get_revenue_ratios(tot_rev, finances)
charge_ratios = get_charge_ratios(tot_ch, finances)
create_total_diagram(save_dir, totals, last_update)
create_pie_diagrams(save_dir, revenue_ratios, charge_ratios, last_update)
print('oucou')
#connection à la db
# Lister les comptes qui m'intéressent
@ -53,6 +77,242 @@ def main(path_b:str,
# - ajouter valeur dans flow et nodes
def test_finance(budget:list[BudgetLine]):
coef = -500
for line in budget:
if coef > 0 :
if line.revenue == 0 :
line.charge += coef
else :
line.revenue += coef
if coef < 0 :
if line.revenue == 0 and line.charge > abs(coef) :
line.charge += coef
elif line.charge == 0 and line.revenue > abs(coef) :
line.revenue += coef
return budget
def sort_des_budget(budget:list[BudgetLine], li:int):
if li < len(budget)-1 :
ch = budget[li].charge
rev = budget[li].revenue
if (ch > 0 and ch >= budget[li+1].charge) or (ch == 0 and budget[li+1].charge ==0 and rev >=budget[li+1].revenue ):
budget = sort_des_budget(budget, li+1)
else :
if li == 0 :
budget = [budget[li+1], budget[li]] + budget[li+2:]
budget = sort_des_budget(budget, li)
elif li < len(budget) - 2 :
budget = budget[:li] + [budget[li+1], budget[li]] + budget[li+2:]
budget = sort_des_budget(budget, li-1)
else :
budget = budget[:li] + [budget[li+1], budget[li]]
budget = sort_des_budget(budget, li-1)
return budget
def get_revenue_ratios(tot:int, budget:list[BudgetLine]):
values = {}
oth = 0
coef = 4
i = 0
for line in budget:
if line.revenue >0 :
if i < coef:
values.update(
{line.desc:line.revenue}
)
i+=1
else:
oth += line.revenue
if oth > 0 :
values.update(
{'Autres':oth}
)
return values
def get_charge_ratios(tot:int, budget:list[BudgetLine]):
values = {}
oth = 0
coef = 4
i = 0
for line in budget:
if line.charge >0 :
if i < coef:
values.update(
{line.desc:line.charge}
)
i+=1
else:
oth += line.charge
if oth > 0 :
values.update(
{'Autres':oth}
)
return values
def import_finances(cursor):
# extraire le compte et la caisse au 1 er janvier de l'année
year = datetime.datetime.now().year
first_day = rf'{year}-01-01'
accounts = get_income_and_expense_accounts(cursor)
finances = []
last_update = first_day
for a in accounts:
tot_deb, tot_cred, last_entrie = get_sum_of_operations(
cursor,
first_day,
a
)
if a.type == 6 :
#charge
finances.append(BudgetLine(a.label, tot_deb - tot_cred, 0))
elif a.type == 7:
finances.append(BudgetLine(a.label, 0, tot_cred - tot_deb))
if last_entrie >= last_update :
last_update = last_entrie
return finances, last_update
def get_total_charges(budget:list[BudgetLine]):
tot = 0
for line in budget:
tot += line.charge
return int(tot)
def get_total_revenues(budget:list[BudgetLine]):
tot = 0
for line in budget:
tot += line.revenue
return int(tot)
def get_totals_lists_for_charts(tot_ch_bud, tot_ch_real, tot_re_bud, tot_re_real):
rest_ch = abs(tot_ch_bud - tot_ch_real)
rest_re = abs(tot_re_bud - tot_re_real)
if tot_ch_bud >= tot_ch_real and tot_re_bud >= tot_re_real:
values = {
f'actuel' : [tot_re_real, tot_ch_real],
f'budget' : [rest_re, rest_ch]
}
else :
values = {
f'bot_budget' : [int(0.98 * tot_re_bud), int(0.98 * tot_ch_bud)],
f'budget' : [int(0.02 *tot_re_bud), int(0.02 *tot_ch_bud)],
f'actuel' : [rest_re, rest_ch]
}
return values
def hls_to_rgbs(s_hsl):
rgb = hls_to_rgb(s_hsl["Hue"], s_hsl["Luminosité"], s_hsl["Saturation"] )
return "#" + "".join("%02X" % round(i*255) for i in rgb )
def get_color_list(nb, s_hsl, sens = "Blanc") :
temp = s_hsl
luminosite = temp["Luminosité"]
if sens == "Blanc":
ecart = (1-luminosite ) /(nb +1)
else :
ecart = luminosite / (nb + 1)
l_couleur = []
for x in range(nb) :
l_couleur.append(hls_to_rgbs(temp ))
if sens == "Blanc" :
luminosite += ecart
else :
print(luminosite)
luminosite -= ecart
temp["Luminosité"] = luminosite
return l_couleur
def create_pie_diagrams(path:str,
revenue_ratios:dict[str, int],
charge_ratios:dict[str, int],
last_update:str):
bleu_hls = {"Hue":190 / 360,
"Saturation":100/100,
"Luminosité":30/100}
marron_hls = {"Hue":23 / 360,
"Saturation":72/100,
"Luminosité":30/100}
fig, axs = plt.subplots(ncols=2,figsize=(10, 4), layout='constrained')
labels, values = transform_dict_for_diag(revenue_ratios)
colors = get_color_list(len(values),bleu_hls)
p = axs[0].pie(x=values, labels=labels, colors=colors)
labels, values = transform_dict_for_diag(charge_ratios)
colors = get_color_list(len(values),marron_hls)
p = axs[1].pie(x=values, labels=labels, colors=colors)
axs[1].set_title('Répartition des dépenses réalisées')
axs[0].set_title('Répartition des recettes réalisées')
path = os.path.join(path, 'ratios.svg')
plt.savefig(path)
plt.close()
def transform_dict_for_diag(dicts:dict):
labels = []
values = []
for label, value in dicts.items():
labels.append(f'{label}\n{value}')
values.append(value)
return labels, values
def create_total_diagram(path:str,
totals: dict[str, list[int]],
last_upadate:str):
fig, ax = plt.subplots()
plt.grid(True, 'major', 'y', color="#555555")
width = 0.6
types = ('dépenses', 'revenus')
leg = [mpatches.Patch(color='#007e97', label=f'au {last_upadate}'),
mpatches.Patch(color='#999999', label='budgeté')
]
bottom = np.zeros(2)
if len(totals) ==2 :
col = ['#007e97', '#999999']
else:
col = ['#007e97', '#999999', '#007e97']
x = 0
for position, values in totals.items():
p = ax.bar(types, values, width, label=position, bottom=bottom, color=col[x] )
bottom += values
x+=1
#ax.invert_yaxis() # labels read top-to-bottom
ax.set_title('Total des dépenses et des revenus de 2025')
box = ax.get_position()
ax.set_position(
[box.x0, box.y0 + box.height * 0.1,
box.width, box.height * 0.9]# type: ignore
)
ax.legend(handles=leg, loc='upper center', bbox_to_anchor=(0.5, -0.07),
fancybox=True, shadow=True, ncol=2)
path = os.path.join(path, 'total.svg')
plt.savefig(path)
plt.close()
def create_accounting_sankey(cursor, save_dir):
NR = []
NC = []
@ -73,7 +333,7 @@ def create_accounting_sankey(cursor, save_dir):
tmp_res = reserves
tot = reserves
for a in accounts:
tot_deb, tot_cred = get_sum_of_operations(
tot_deb, tot_cred, last_entrie = get_sum_of_operations(
cursor,
first_day,
a
@ -110,6 +370,7 @@ def create_accounting_sankey(cursor, save_dir):
plt.savefig(path)
plt.close()
def get_income_and_expense_accounts(cursor):
VERBOSE = False
if VERBOSE : print("get_income_and_expense_accounts")
@ -191,12 +452,15 @@ def get_sum_of_operations(cursor, date:str, account:Account):
"SELECT piece_num, numero_compte, label_compte, doc_date, code_journal, debit, credit FROM llx_accounting_bookkeeping WHERE numero_compte = ? AND doc_date >= ?",
(account.number, date)
)
last_entrie = date
for piece_num, numero_compte, label_compte, doc_date, code_journal, debit, credit in cursor :
tot_cred += credit
tot_deb += debit
if doc_date > last_entrie :
last_entrie = doc_date
if VERBOSE : print(f'pour le compte {account.number} : credit = {tot_cred} / debit = {tot_deb} à partir du {date}')
return int(tot_deb), int(tot_cred)
return int(tot_deb), int(tot_cred), last_entrie
def get_db_infos(path_wp:str):

1212
ratios.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 36 KiB

1024
total.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 28 KiB