reports.account_statement

  1from datetime import datetime
  2from dictionary.sql import user_current_accounts_query, expenses_statement_query, revenues_statement_query
  3from functions.login import Login
  4from dictionary.vars import to_remove_list, today, absolute_app_path
  5from dictionary.style import system_font
  6from fpdf import FPDF
  7from functions.get_actual_time import GetActualTime
  8from functions.query_executor import QueryExecutor
  9from functions.login import Login
 10from time import sleep
 11import pandas as pd
 12import streamlit as st
 13
 14
 15class AccountStatement:
 16    """
 17    Classe que representa os extratos bancários das contas do usuário.
 18    """
 19
 20    def consult_statement(self, statement_query_option: str, accounts: list, initial_data: str, final_data: str):
 21        """
 22        Realiza a consulta do extrato bancário de acordo com as consultas passadas como parâmetro.
 23
 24        Parameters
 25        ----------
 26        statement_query_option : str
 27            A opção de extrato selecionada pelo usuário.
 28        accounts : list
 29            Lista com as contas a serem consultadas.
 30        initial_data: str
 31            A data inicial da consulta.
 32        final_data: str
 33            A data final da consulta.
 34
 35        Returns
 36        -------
 37        value_list : list
 38            A lista com os valores do extrato.
 39        data_df_list : list
 40            A lista com os gráficos estruturados.
 41        """
 42        user_name, user_document = Login().get_user_data(return_option="user_doc_name")
 43
 44        value_list = []
 45        data_df_list = []
 46
 47        placeholders = ", ".join(["%s"] * len(accounts))
 48
 49        # Modificando a consulta para usar os placeholders corretamente
 50        revenues_query = revenues_statement_query.replace("IN %s", f"IN ({placeholders})")
 51        expenses_query = expenses_statement_query.replace("IN %s", f"IN ({placeholders})")
 52
 53        if statement_query_option == "Receitas e Despesas":
 54            empty_list = QueryExecutor().complex_compund_query(revenues_query, 6, params=(initial_data, final_data, *accounts, user_name, user_document))
 55            description, value, date, time, category, account = (empty_list)
 56
 57            if len(description) == 0 and len(value) == 0 and len(date) == 0 and len(time) == 0 and len(category) == 0 and len(account) == 0:
 58                with st.expander(label="Relatório de Receitas", expanded=True):
 59                    st.info(body="Nao há registros neste período.")
 60
 61            elif len(description) > 0 and len(value) > 0 and len(date) > 0 and len(time) > 0 and len(category) > 0 and len(account) > 0:
 62                aux_str = ""
 63
 64                for i in range(0, len(time)):
 65                    aux_str = str(time[i])
 66                    time[i] = aux_str
 67
 68                with st.expander(label="Relatório de Receitas", expanded=True):
 69
 70                    data_df = pd.DataFrame(
 71                        {
 72                            "Descrição": description,
 73                            "Valor": value,
 74                            "Data": date,
 75                            "Horário": time,
 76                            "Categoria": category,
 77                            "Conta": account,
 78                        }
 79                    )
 80
 81                    data_df["Valor"] = data_df["Valor"].apply(lambda x: f"R$ {x:.2f}".replace(".", ","))
 82                    data_df["Data"] = pd.to_datetime(data_df["Data"]).dt.strftime("%d/%m/%Y")
 83                    st.dataframe(data_df, hide_index=True, use_container_width=True)
 84
 85                value_list.append(value)
 86                data_df_list.append(data_df)
 87            
 88            empty_list = QueryExecutor().complex_compund_query(expenses_query, 6, params=(initial_data, final_data, *accounts, user_name, user_document))
 89            description, value, date, time, category, account = (empty_list)
 90
 91            if len(description) == 0 and len(value) == 0 and len(date) == 0 and len(time) == 0 and len(category) == 0 and len(account) == 0:
 92                with st.expander(label="Relatório de Despesas", expanded=True):
 93                    st.info(body="Nao há registros neste período.")
 94
 95            elif len(description) > 0 and len(value) > 0 and len(date) > 0 and len(time) > 0 and len(category) > 0 and len(account) > 0:
 96
 97                aux_str = ""
 98
 99                for i in range(0, len(time)):
100                    aux_str = str(time[i])
101                    time[i] = aux_str
102
103                with st.expander(label="Relatório de Despesas", expanded=True):
104
105                    data_df = pd.DataFrame(
106                        {
107                            "Descrição": description,
108                            "Valor": value,
109                            "Data": date,
110                            "Horário": time,
111                            "Categoria": category,
112                            "Conta": account,
113                        }
114                    )
115
116                    data_df["Valor"] = data_df["Valor"].apply(lambda x: f"R$ {x:.2f}".replace(".", ","))
117                    data_df["Data"] = pd.to_datetime(data_df["Data"]).dt.strftime("%d/%m/%Y")
118                    st.dataframe(data_df, hide_index=True, use_container_width=True)
119
120                value_list.append(value)
121                data_df_list.append(data_df)
122
123        if statement_query_option == "Receitas":
124            empty_list = QueryExecutor().complex_compund_query(revenues_query, 6, params=(initial_data, final_data, *accounts, user_name, user_document))
125            description, value, date, time, category, account = (empty_list)
126
127            if len(description) == 0 and len(value) == 0 and len(date) == 0 and len(time) == 0 and len(category) == 0 and len(account) == 0:
128                with st.expander(label="Relatório de Receitas", expanded=True):
129                    st.info(body="Nao há registros neste período.")
130
131            elif len(description) > 0 and len(value) > 0 and len(date) > 0 and len(time) > 0 and len(category) > 0 and len(account) > 0:
132                aux_str = ""
133
134                for i in range(0, len(time)):
135                    aux_str = str(time[i])
136                    time[i] = aux_str
137
138                with st.expander(label="Relatório de Receitas", expanded=True):
139
140                    data_df = pd.DataFrame(
141                        {
142                            "Descrição": description,
143                            "Valor": value,
144                            "Data": date,
145                            "Horário": time,
146                            "Categoria": category,
147                            "Conta": account,
148                        }
149                    )
150
151                    data_df["Valor"] = data_df["Valor"].apply(lambda x: f"R$ {x:.2f}".replace(".", ","))
152                    data_df["Data"] = pd.to_datetime(data_df["Data"]).dt.strftime("%d/%m/%Y")
153                    st.dataframe(data_df, hide_index=True, use_container_width=True)
154
155                value_list.append(value)
156                data_df_list.append(data_df)
157        
158        if statement_query_option == "Despesas":
159            empty_list = QueryExecutor().complex_compund_query(expenses_query, 6, params=(initial_data, final_data, *accounts, user_name, user_document))
160            description, value, date, time, category, account = (empty_list)
161
162            if len(description) == 0 and len(value) == 0 and len(date) == 0 and len(time) == 0 and len(category) == 0 and len(account) == 0:
163                with st.expander(label="Relatório de Despesas", expanded=True):
164                    st.info(body="Nao há registros neste período.")
165
166            elif len(description) > 0 and len(value) > 0 and len(date) > 0 and len(time) > 0 and len(category) > 0 and len(account) > 0:
167                aux_str = ""
168
169                for i in range(0, len(time)):
170                    aux_str = str(time[i])
171                    time[i] = aux_str
172
173                with st.expander(label="Relatório de Despesas", expanded=True):
174
175                    data_df = pd.DataFrame(
176                        {
177                            "Descrição": description,
178                            "Valor": value,
179                            "Data": date,
180                            "Horário": time,
181                            "Categoria": category,
182                            "Conta": account,
183                        }
184                    )
185
186                    data_df["Valor"] = data_df["Valor"].apply(lambda x: f"R$ {x:.2f}".replace(".", ","))
187                    data_df["Data"] = pd.to_datetime(data_df["Data"]).dt.strftime("%d/%m/%Y")
188                    st.dataframe(data_df, hide_index=True, use_container_width=True)
189
190                value_list.append(value)
191                data_df_list.append(data_df)
192        
193        return value_list, data_df_list
194
195    def generate_pdf(self, df: list, statement_type: str, initial_data: str, final_data: str, accounts: list):
196        """
197        Gera o PDF do extrato bancário.
198
199        Parameters
200        ----------
201        df : list
202            A lista com os gráficos.
203        statement_type : str
204            O tipo de extrato bancário.
205        initial_data : str
206            A data inicial do extrato.
207        final_data : str
208            A data final do extrato.
209        accounts : list
210            Lista com as contas consultadas.
211
212        Returns
213        -------
214        pdf: O PDF gerado pela função.
215        """
216
217        user_name, user_document = Login().get_user_data(return_option="user_doc_name")
218
219        unformatted_today = datetime.strptime(today, '%Y-%m-%d')
220        formatted_today = unformatted_today.strftime('%d/%m/%Y')
221
222        time = GetActualTime().get_actual_time()
223
224        accounts_str = ""
225        for item in range(0, len(accounts)):
226            if item < (len(accounts) - 1):
227                accounts_str = accounts_str + accounts[item] + ", "
228            if item == len(accounts) - 1:
229                accounts_str = accounts_str + accounts[item] + "."
230
231        pdf = FPDF(orientation='L', unit="mm", format="A4")
232        pdf.add_page()
233        pdf.add_font("SystemFont", "", "{}{}".format(absolute_app_path, system_font), uni=True)
234
235        pdf.set_font("SystemFont", size=16)
236        pdf.cell(0, 10, "Relatório de {}".format(statement_type), ln=True, align="C")
237        pdf.ln(10)
238
239        pdf.set_font("SystemFont", size=12)
240        pdf.cell(0, 5, "Período de consulta: {} à {}".format(initial_data, final_data), ln=True)
241        pdf.set_font("SystemFont", size=12)
242        pdf.cell(0, 10, "Contas consultadas: {}".format(accounts_str), ln=True)
243        pdf.ln(5)
244
245        statement_types = ["Receitas", "Despesas"]
246
247        for i in range(0, len(df)):
248
249            pdf.set_font("SystemFont", size=14)
250            pdf.cell(0, 10, "{}".format(statement_types[i]), ln=True)
251            pdf.ln(5)
252
253            col_width = (pdf.w / len(df[i].columns)) * 0.85
254
255            pdf.set_font("SystemFont", size=10)
256
257            for col in df[i].columns:
258                pdf.cell(col_width, 5, col, border=1, align="C")
259            pdf.ln()
260            pdf.set_font("SystemFont", size=10)
261            for _, row in df[i].iterrows():
262                for cell in row:
263                    pdf.cell(col_width, 10, str(cell), border=1, align="C")
264                pdf.ln()
265            pdf.ln(10)
266
267        # pdf.cell(0, 10, "{}".format(generated_description), align="L", ln=True)
268
269        pdf.cell(0, 10, "Horário da consulta: {}, às {}.".format(formatted_today, time), align="R", ln=True)
270        pdf.cell(0, 10, "Nome do usuário: {}.".format(user_name), align="R", ln=True)
271        pdf.ln(5)
272
273        return pdf
274
275    def main_menu(self):
276        """
277        Menu principal.
278        """
279        user_name, user_document = Login().get_user_data(return_option="user_doc_name")
280        logged_user, logged_user_password = Login().get_user_data(return_option="user_login_password")
281
282        user_current_accounts = QueryExecutor().complex_consult_query(query=user_current_accounts_query, params=(user_name, user_document))
283        user_current_accounts = QueryExecutor().treat_numerous_simple_result(user_current_accounts, to_remove_list)
284
285        col4, col5, col6 = st.columns(3)
286
287        if len(user_current_accounts) > 0:
288
289            with col4:
290                st.subheader(body=":computer: Entrada de Dados")
291                with st.expander(label="Dados", expanded=True):
292                    statement_option = st.selectbox(label="Tipos de extrato", options=["Selecione uma opção", "Receitas", "Despesas", "Receitas e Despesas"])
293                    selected_accounts = st.multiselect(label="Contas", options=user_current_accounts, placeholder="Escolha a(s) conta(s)")
294                    initial_data = st.date_input(label="Data de início")
295                    final_data = st.date_input(label="Data de fim")
296                    confirm_choice = st.checkbox(label="Confirmar dados")
297
298                consult_tables = st.button(label=":chart: Gerar Relatórios")
299
300            if confirm_choice and consult_tables:
301                with col5:
302                    with st.spinner(text="Aguarde..."):
303                        sleep(2.5)
304
305                    st.subheader(body=":bar_chart: Resultados")
306
307                    if statement_option != "Selecione uma opção" and len(selected_accounts) > 0 and (initial_data <= final_data):
308                        value_list, dataframes = self.consult_statement(statement_option, selected_accounts, initial_data, final_data)
309
310                        with col6:
311                            with st.spinner(text="Aguarde..."):
312                                sleep(2.5)
313                            st.subheader(body=":information_source: Informações")
314
315                            total_value = 0
316                            counter = 0
317
318                            for i in range(0, len(value_list)):
319                                for j in range(0, len(value_list[i])):
320                                    total_value += value_list[i][j]
321                                    counter += 1
322                                medium_value = round((total_value / len(value_list[i])), 2)
323
324                            medium_value = str(medium_value)
325                            medium_value = medium_value.replace(".", ",")
326                            total_value = str(total_value)
327                            total_value = total_value.replace(".", ",")
328
329                            with st.expander(label="Dados", expanded=True):
330                                st.info(body="Quantidade de {}: {}.".format(statement_option.lower(), counter))
331                                st.info(body="Valor total das {}: R$ {}.".format(statement_option.lower(), total_value))
332                                st.info(body="Valor médio das {}: R$ {}.".format(statement_option.lower(), medium_value))
333
334                            formatted_initial_data = initial_data.strftime("%d/%m/%Y")
335                            formatted_final_data = final_data.strftime("%d/%m/%Y")
336
337                            log_query = '''INSERT INTO financas.logs_atividades (usuario_log, tipo_log, conteudo_log) VALUES ( %s, %s, %s);'''
338                            log_values = (logged_user, "Consulta", "Consultou o relatório de {} entre o período de {} a {}.".format(statement_option, formatted_initial_data, formatted_final_data))
339                            QueryExecutor().insert_query(log_query, log_values, "Log gravado.", "Erro ao gravar log:")
340
341                            time = GetActualTime().get_actual_time()
342
343                            pdf = self.generate_pdf(dataframes, statement_option, formatted_initial_data, formatted_final_data, selected_accounts)
344                            pdf_bytes = pdf.output(dest='S').encode('latin1')
345
346                            st.download_button(
347                                label=":floppy_disk: Baixar PDF",
348                                data=pdf_bytes,
349                                file_name="extrato_bancario_{}_{}_a_{}_{}.pdf".format(statement_option.replace(" ", "_").lower(), initial_data, final_data, time),
350                                mime="application/pdf",
351                            )
352
353                    elif (len(selected_accounts) == 0) or (initial_data > final_data) or (statement_option == "Selecione uma opção"):
354                        with st.expander(label="Avisos", expanded=True):
355                            if statement_option == "Selecione uma opção":
356                                st.error(body="Selecione um tipo de extrato.")
357                            if len(selected_accounts) == 0:
358                                st.error(body="Nenhuma conta selecionada.")
359                            if initial_data > final_data:
360                                st.error(body="A data inicial não pode ser maior que a final.")
361
362        elif len(user_current_accounts) == 0:
363            with col5:
364                st.warning(body="Você ainda não possui contas cadastradas.")
class AccountStatement:
 16class AccountStatement:
 17    """
 18    Classe que representa os extratos bancários das contas do usuário.
 19    """
 20
 21    def consult_statement(self, statement_query_option: str, accounts: list, initial_data: str, final_data: str):
 22        """
 23        Realiza a consulta do extrato bancário de acordo com as consultas passadas como parâmetro.
 24
 25        Parameters
 26        ----------
 27        statement_query_option : str
 28            A opção de extrato selecionada pelo usuário.
 29        accounts : list
 30            Lista com as contas a serem consultadas.
 31        initial_data: str
 32            A data inicial da consulta.
 33        final_data: str
 34            A data final da consulta.
 35
 36        Returns
 37        -------
 38        value_list : list
 39            A lista com os valores do extrato.
 40        data_df_list : list
 41            A lista com os gráficos estruturados.
 42        """
 43        user_name, user_document = Login().get_user_data(return_option="user_doc_name")
 44
 45        value_list = []
 46        data_df_list = []
 47
 48        placeholders = ", ".join(["%s"] * len(accounts))
 49
 50        # Modificando a consulta para usar os placeholders corretamente
 51        revenues_query = revenues_statement_query.replace("IN %s", f"IN ({placeholders})")
 52        expenses_query = expenses_statement_query.replace("IN %s", f"IN ({placeholders})")
 53
 54        if statement_query_option == "Receitas e Despesas":
 55            empty_list = QueryExecutor().complex_compund_query(revenues_query, 6, params=(initial_data, final_data, *accounts, user_name, user_document))
 56            description, value, date, time, category, account = (empty_list)
 57
 58            if len(description) == 0 and len(value) == 0 and len(date) == 0 and len(time) == 0 and len(category) == 0 and len(account) == 0:
 59                with st.expander(label="Relatório de Receitas", expanded=True):
 60                    st.info(body="Nao há registros neste período.")
 61
 62            elif len(description) > 0 and len(value) > 0 and len(date) > 0 and len(time) > 0 and len(category) > 0 and len(account) > 0:
 63                aux_str = ""
 64
 65                for i in range(0, len(time)):
 66                    aux_str = str(time[i])
 67                    time[i] = aux_str
 68
 69                with st.expander(label="Relatório de Receitas", expanded=True):
 70
 71                    data_df = pd.DataFrame(
 72                        {
 73                            "Descrição": description,
 74                            "Valor": value,
 75                            "Data": date,
 76                            "Horário": time,
 77                            "Categoria": category,
 78                            "Conta": account,
 79                        }
 80                    )
 81
 82                    data_df["Valor"] = data_df["Valor"].apply(lambda x: f"R$ {x:.2f}".replace(".", ","))
 83                    data_df["Data"] = pd.to_datetime(data_df["Data"]).dt.strftime("%d/%m/%Y")
 84                    st.dataframe(data_df, hide_index=True, use_container_width=True)
 85
 86                value_list.append(value)
 87                data_df_list.append(data_df)
 88            
 89            empty_list = QueryExecutor().complex_compund_query(expenses_query, 6, params=(initial_data, final_data, *accounts, user_name, user_document))
 90            description, value, date, time, category, account = (empty_list)
 91
 92            if len(description) == 0 and len(value) == 0 and len(date) == 0 and len(time) == 0 and len(category) == 0 and len(account) == 0:
 93                with st.expander(label="Relatório de Despesas", expanded=True):
 94                    st.info(body="Nao há registros neste período.")
 95
 96            elif len(description) > 0 and len(value) > 0 and len(date) > 0 and len(time) > 0 and len(category) > 0 and len(account) > 0:
 97
 98                aux_str = ""
 99
100                for i in range(0, len(time)):
101                    aux_str = str(time[i])
102                    time[i] = aux_str
103
104                with st.expander(label="Relatório de Despesas", expanded=True):
105
106                    data_df = pd.DataFrame(
107                        {
108                            "Descrição": description,
109                            "Valor": value,
110                            "Data": date,
111                            "Horário": time,
112                            "Categoria": category,
113                            "Conta": account,
114                        }
115                    )
116
117                    data_df["Valor"] = data_df["Valor"].apply(lambda x: f"R$ {x:.2f}".replace(".", ","))
118                    data_df["Data"] = pd.to_datetime(data_df["Data"]).dt.strftime("%d/%m/%Y")
119                    st.dataframe(data_df, hide_index=True, use_container_width=True)
120
121                value_list.append(value)
122                data_df_list.append(data_df)
123
124        if statement_query_option == "Receitas":
125            empty_list = QueryExecutor().complex_compund_query(revenues_query, 6, params=(initial_data, final_data, *accounts, user_name, user_document))
126            description, value, date, time, category, account = (empty_list)
127
128            if len(description) == 0 and len(value) == 0 and len(date) == 0 and len(time) == 0 and len(category) == 0 and len(account) == 0:
129                with st.expander(label="Relatório de Receitas", expanded=True):
130                    st.info(body="Nao há registros neste período.")
131
132            elif len(description) > 0 and len(value) > 0 and len(date) > 0 and len(time) > 0 and len(category) > 0 and len(account) > 0:
133                aux_str = ""
134
135                for i in range(0, len(time)):
136                    aux_str = str(time[i])
137                    time[i] = aux_str
138
139                with st.expander(label="Relatório de Receitas", expanded=True):
140
141                    data_df = pd.DataFrame(
142                        {
143                            "Descrição": description,
144                            "Valor": value,
145                            "Data": date,
146                            "Horário": time,
147                            "Categoria": category,
148                            "Conta": account,
149                        }
150                    )
151
152                    data_df["Valor"] = data_df["Valor"].apply(lambda x: f"R$ {x:.2f}".replace(".", ","))
153                    data_df["Data"] = pd.to_datetime(data_df["Data"]).dt.strftime("%d/%m/%Y")
154                    st.dataframe(data_df, hide_index=True, use_container_width=True)
155
156                value_list.append(value)
157                data_df_list.append(data_df)
158        
159        if statement_query_option == "Despesas":
160            empty_list = QueryExecutor().complex_compund_query(expenses_query, 6, params=(initial_data, final_data, *accounts, user_name, user_document))
161            description, value, date, time, category, account = (empty_list)
162
163            if len(description) == 0 and len(value) == 0 and len(date) == 0 and len(time) == 0 and len(category) == 0 and len(account) == 0:
164                with st.expander(label="Relatório de Despesas", expanded=True):
165                    st.info(body="Nao há registros neste período.")
166
167            elif len(description) > 0 and len(value) > 0 and len(date) > 0 and len(time) > 0 and len(category) > 0 and len(account) > 0:
168                aux_str = ""
169
170                for i in range(0, len(time)):
171                    aux_str = str(time[i])
172                    time[i] = aux_str
173
174                with st.expander(label="Relatório de Despesas", expanded=True):
175
176                    data_df = pd.DataFrame(
177                        {
178                            "Descrição": description,
179                            "Valor": value,
180                            "Data": date,
181                            "Horário": time,
182                            "Categoria": category,
183                            "Conta": account,
184                        }
185                    )
186
187                    data_df["Valor"] = data_df["Valor"].apply(lambda x: f"R$ {x:.2f}".replace(".", ","))
188                    data_df["Data"] = pd.to_datetime(data_df["Data"]).dt.strftime("%d/%m/%Y")
189                    st.dataframe(data_df, hide_index=True, use_container_width=True)
190
191                value_list.append(value)
192                data_df_list.append(data_df)
193        
194        return value_list, data_df_list
195
196    def generate_pdf(self, df: list, statement_type: str, initial_data: str, final_data: str, accounts: list):
197        """
198        Gera o PDF do extrato bancário.
199
200        Parameters
201        ----------
202        df : list
203            A lista com os gráficos.
204        statement_type : str
205            O tipo de extrato bancário.
206        initial_data : str
207            A data inicial do extrato.
208        final_data : str
209            A data final do extrato.
210        accounts : list
211            Lista com as contas consultadas.
212
213        Returns
214        -------
215        pdf: O PDF gerado pela função.
216        """
217
218        user_name, user_document = Login().get_user_data(return_option="user_doc_name")
219
220        unformatted_today = datetime.strptime(today, '%Y-%m-%d')
221        formatted_today = unformatted_today.strftime('%d/%m/%Y')
222
223        time = GetActualTime().get_actual_time()
224
225        accounts_str = ""
226        for item in range(0, len(accounts)):
227            if item < (len(accounts) - 1):
228                accounts_str = accounts_str + accounts[item] + ", "
229            if item == len(accounts) - 1:
230                accounts_str = accounts_str + accounts[item] + "."
231
232        pdf = FPDF(orientation='L', unit="mm", format="A4")
233        pdf.add_page()
234        pdf.add_font("SystemFont", "", "{}{}".format(absolute_app_path, system_font), uni=True)
235
236        pdf.set_font("SystemFont", size=16)
237        pdf.cell(0, 10, "Relatório de {}".format(statement_type), ln=True, align="C")
238        pdf.ln(10)
239
240        pdf.set_font("SystemFont", size=12)
241        pdf.cell(0, 5, "Período de consulta: {} à {}".format(initial_data, final_data), ln=True)
242        pdf.set_font("SystemFont", size=12)
243        pdf.cell(0, 10, "Contas consultadas: {}".format(accounts_str), ln=True)
244        pdf.ln(5)
245
246        statement_types = ["Receitas", "Despesas"]
247
248        for i in range(0, len(df)):
249
250            pdf.set_font("SystemFont", size=14)
251            pdf.cell(0, 10, "{}".format(statement_types[i]), ln=True)
252            pdf.ln(5)
253
254            col_width = (pdf.w / len(df[i].columns)) * 0.85
255
256            pdf.set_font("SystemFont", size=10)
257
258            for col in df[i].columns:
259                pdf.cell(col_width, 5, col, border=1, align="C")
260            pdf.ln()
261            pdf.set_font("SystemFont", size=10)
262            for _, row in df[i].iterrows():
263                for cell in row:
264                    pdf.cell(col_width, 10, str(cell), border=1, align="C")
265                pdf.ln()
266            pdf.ln(10)
267
268        # pdf.cell(0, 10, "{}".format(generated_description), align="L", ln=True)
269
270        pdf.cell(0, 10, "Horário da consulta: {}, às {}.".format(formatted_today, time), align="R", ln=True)
271        pdf.cell(0, 10, "Nome do usuário: {}.".format(user_name), align="R", ln=True)
272        pdf.ln(5)
273
274        return pdf
275
276    def main_menu(self):
277        """
278        Menu principal.
279        """
280        user_name, user_document = Login().get_user_data(return_option="user_doc_name")
281        logged_user, logged_user_password = Login().get_user_data(return_option="user_login_password")
282
283        user_current_accounts = QueryExecutor().complex_consult_query(query=user_current_accounts_query, params=(user_name, user_document))
284        user_current_accounts = QueryExecutor().treat_numerous_simple_result(user_current_accounts, to_remove_list)
285
286        col4, col5, col6 = st.columns(3)
287
288        if len(user_current_accounts) > 0:
289
290            with col4:
291                st.subheader(body=":computer: Entrada de Dados")
292                with st.expander(label="Dados", expanded=True):
293                    statement_option = st.selectbox(label="Tipos de extrato", options=["Selecione uma opção", "Receitas", "Despesas", "Receitas e Despesas"])
294                    selected_accounts = st.multiselect(label="Contas", options=user_current_accounts, placeholder="Escolha a(s) conta(s)")
295                    initial_data = st.date_input(label="Data de início")
296                    final_data = st.date_input(label="Data de fim")
297                    confirm_choice = st.checkbox(label="Confirmar dados")
298
299                consult_tables = st.button(label=":chart: Gerar Relatórios")
300
301            if confirm_choice and consult_tables:
302                with col5:
303                    with st.spinner(text="Aguarde..."):
304                        sleep(2.5)
305
306                    st.subheader(body=":bar_chart: Resultados")
307
308                    if statement_option != "Selecione uma opção" and len(selected_accounts) > 0 and (initial_data <= final_data):
309                        value_list, dataframes = self.consult_statement(statement_option, selected_accounts, initial_data, final_data)
310
311                        with col6:
312                            with st.spinner(text="Aguarde..."):
313                                sleep(2.5)
314                            st.subheader(body=":information_source: Informações")
315
316                            total_value = 0
317                            counter = 0
318
319                            for i in range(0, len(value_list)):
320                                for j in range(0, len(value_list[i])):
321                                    total_value += value_list[i][j]
322                                    counter += 1
323                                medium_value = round((total_value / len(value_list[i])), 2)
324
325                            medium_value = str(medium_value)
326                            medium_value = medium_value.replace(".", ",")
327                            total_value = str(total_value)
328                            total_value = total_value.replace(".", ",")
329
330                            with st.expander(label="Dados", expanded=True):
331                                st.info(body="Quantidade de {}: {}.".format(statement_option.lower(), counter))
332                                st.info(body="Valor total das {}: R$ {}.".format(statement_option.lower(), total_value))
333                                st.info(body="Valor médio das {}: R$ {}.".format(statement_option.lower(), medium_value))
334
335                            formatted_initial_data = initial_data.strftime("%d/%m/%Y")
336                            formatted_final_data = final_data.strftime("%d/%m/%Y")
337
338                            log_query = '''INSERT INTO financas.logs_atividades (usuario_log, tipo_log, conteudo_log) VALUES ( %s, %s, %s);'''
339                            log_values = (logged_user, "Consulta", "Consultou o relatório de {} entre o período de {} a {}.".format(statement_option, formatted_initial_data, formatted_final_data))
340                            QueryExecutor().insert_query(log_query, log_values, "Log gravado.", "Erro ao gravar log:")
341
342                            time = GetActualTime().get_actual_time()
343
344                            pdf = self.generate_pdf(dataframes, statement_option, formatted_initial_data, formatted_final_data, selected_accounts)
345                            pdf_bytes = pdf.output(dest='S').encode('latin1')
346
347                            st.download_button(
348                                label=":floppy_disk: Baixar PDF",
349                                data=pdf_bytes,
350                                file_name="extrato_bancario_{}_{}_a_{}_{}.pdf".format(statement_option.replace(" ", "_").lower(), initial_data, final_data, time),
351                                mime="application/pdf",
352                            )
353
354                    elif (len(selected_accounts) == 0) or (initial_data > final_data) or (statement_option == "Selecione uma opção"):
355                        with st.expander(label="Avisos", expanded=True):
356                            if statement_option == "Selecione uma opção":
357                                st.error(body="Selecione um tipo de extrato.")
358                            if len(selected_accounts) == 0:
359                                st.error(body="Nenhuma conta selecionada.")
360                            if initial_data > final_data:
361                                st.error(body="A data inicial não pode ser maior que a final.")
362
363        elif len(user_current_accounts) == 0:
364            with col5:
365                st.warning(body="Você ainda não possui contas cadastradas.")

Classe que representa os extratos bancários das contas do usuário.

def consult_statement( self, statement_query_option: str, accounts: list, initial_data: str, final_data: str):
 21    def consult_statement(self, statement_query_option: str, accounts: list, initial_data: str, final_data: str):
 22        """
 23        Realiza a consulta do extrato bancário de acordo com as consultas passadas como parâmetro.
 24
 25        Parameters
 26        ----------
 27        statement_query_option : str
 28            A opção de extrato selecionada pelo usuário.
 29        accounts : list
 30            Lista com as contas a serem consultadas.
 31        initial_data: str
 32            A data inicial da consulta.
 33        final_data: str
 34            A data final da consulta.
 35
 36        Returns
 37        -------
 38        value_list : list
 39            A lista com os valores do extrato.
 40        data_df_list : list
 41            A lista com os gráficos estruturados.
 42        """
 43        user_name, user_document = Login().get_user_data(return_option="user_doc_name")
 44
 45        value_list = []
 46        data_df_list = []
 47
 48        placeholders = ", ".join(["%s"] * len(accounts))
 49
 50        # Modificando a consulta para usar os placeholders corretamente
 51        revenues_query = revenues_statement_query.replace("IN %s", f"IN ({placeholders})")
 52        expenses_query = expenses_statement_query.replace("IN %s", f"IN ({placeholders})")
 53
 54        if statement_query_option == "Receitas e Despesas":
 55            empty_list = QueryExecutor().complex_compund_query(revenues_query, 6, params=(initial_data, final_data, *accounts, user_name, user_document))
 56            description, value, date, time, category, account = (empty_list)
 57
 58            if len(description) == 0 and len(value) == 0 and len(date) == 0 and len(time) == 0 and len(category) == 0 and len(account) == 0:
 59                with st.expander(label="Relatório de Receitas", expanded=True):
 60                    st.info(body="Nao há registros neste período.")
 61
 62            elif len(description) > 0 and len(value) > 0 and len(date) > 0 and len(time) > 0 and len(category) > 0 and len(account) > 0:
 63                aux_str = ""
 64
 65                for i in range(0, len(time)):
 66                    aux_str = str(time[i])
 67                    time[i] = aux_str
 68
 69                with st.expander(label="Relatório de Receitas", expanded=True):
 70
 71                    data_df = pd.DataFrame(
 72                        {
 73                            "Descrição": description,
 74                            "Valor": value,
 75                            "Data": date,
 76                            "Horário": time,
 77                            "Categoria": category,
 78                            "Conta": account,
 79                        }
 80                    )
 81
 82                    data_df["Valor"] = data_df["Valor"].apply(lambda x: f"R$ {x:.2f}".replace(".", ","))
 83                    data_df["Data"] = pd.to_datetime(data_df["Data"]).dt.strftime("%d/%m/%Y")
 84                    st.dataframe(data_df, hide_index=True, use_container_width=True)
 85
 86                value_list.append(value)
 87                data_df_list.append(data_df)
 88            
 89            empty_list = QueryExecutor().complex_compund_query(expenses_query, 6, params=(initial_data, final_data, *accounts, user_name, user_document))
 90            description, value, date, time, category, account = (empty_list)
 91
 92            if len(description) == 0 and len(value) == 0 and len(date) == 0 and len(time) == 0 and len(category) == 0 and len(account) == 0:
 93                with st.expander(label="Relatório de Despesas", expanded=True):
 94                    st.info(body="Nao há registros neste período.")
 95
 96            elif len(description) > 0 and len(value) > 0 and len(date) > 0 and len(time) > 0 and len(category) > 0 and len(account) > 0:
 97
 98                aux_str = ""
 99
100                for i in range(0, len(time)):
101                    aux_str = str(time[i])
102                    time[i] = aux_str
103
104                with st.expander(label="Relatório de Despesas", expanded=True):
105
106                    data_df = pd.DataFrame(
107                        {
108                            "Descrição": description,
109                            "Valor": value,
110                            "Data": date,
111                            "Horário": time,
112                            "Categoria": category,
113                            "Conta": account,
114                        }
115                    )
116
117                    data_df["Valor"] = data_df["Valor"].apply(lambda x: f"R$ {x:.2f}".replace(".", ","))
118                    data_df["Data"] = pd.to_datetime(data_df["Data"]).dt.strftime("%d/%m/%Y")
119                    st.dataframe(data_df, hide_index=True, use_container_width=True)
120
121                value_list.append(value)
122                data_df_list.append(data_df)
123
124        if statement_query_option == "Receitas":
125            empty_list = QueryExecutor().complex_compund_query(revenues_query, 6, params=(initial_data, final_data, *accounts, user_name, user_document))
126            description, value, date, time, category, account = (empty_list)
127
128            if len(description) == 0 and len(value) == 0 and len(date) == 0 and len(time) == 0 and len(category) == 0 and len(account) == 0:
129                with st.expander(label="Relatório de Receitas", expanded=True):
130                    st.info(body="Nao há registros neste período.")
131
132            elif len(description) > 0 and len(value) > 0 and len(date) > 0 and len(time) > 0 and len(category) > 0 and len(account) > 0:
133                aux_str = ""
134
135                for i in range(0, len(time)):
136                    aux_str = str(time[i])
137                    time[i] = aux_str
138
139                with st.expander(label="Relatório de Receitas", expanded=True):
140
141                    data_df = pd.DataFrame(
142                        {
143                            "Descrição": description,
144                            "Valor": value,
145                            "Data": date,
146                            "Horário": time,
147                            "Categoria": category,
148                            "Conta": account,
149                        }
150                    )
151
152                    data_df["Valor"] = data_df["Valor"].apply(lambda x: f"R$ {x:.2f}".replace(".", ","))
153                    data_df["Data"] = pd.to_datetime(data_df["Data"]).dt.strftime("%d/%m/%Y")
154                    st.dataframe(data_df, hide_index=True, use_container_width=True)
155
156                value_list.append(value)
157                data_df_list.append(data_df)
158        
159        if statement_query_option == "Despesas":
160            empty_list = QueryExecutor().complex_compund_query(expenses_query, 6, params=(initial_data, final_data, *accounts, user_name, user_document))
161            description, value, date, time, category, account = (empty_list)
162
163            if len(description) == 0 and len(value) == 0 and len(date) == 0 and len(time) == 0 and len(category) == 0 and len(account) == 0:
164                with st.expander(label="Relatório de Despesas", expanded=True):
165                    st.info(body="Nao há registros neste período.")
166
167            elif len(description) > 0 and len(value) > 0 and len(date) > 0 and len(time) > 0 and len(category) > 0 and len(account) > 0:
168                aux_str = ""
169
170                for i in range(0, len(time)):
171                    aux_str = str(time[i])
172                    time[i] = aux_str
173
174                with st.expander(label="Relatório de Despesas", expanded=True):
175
176                    data_df = pd.DataFrame(
177                        {
178                            "Descrição": description,
179                            "Valor": value,
180                            "Data": date,
181                            "Horário": time,
182                            "Categoria": category,
183                            "Conta": account,
184                        }
185                    )
186
187                    data_df["Valor"] = data_df["Valor"].apply(lambda x: f"R$ {x:.2f}".replace(".", ","))
188                    data_df["Data"] = pd.to_datetime(data_df["Data"]).dt.strftime("%d/%m/%Y")
189                    st.dataframe(data_df, hide_index=True, use_container_width=True)
190
191                value_list.append(value)
192                data_df_list.append(data_df)
193        
194        return value_list, data_df_list

Realiza a consulta do extrato bancário de acordo com as consultas passadas como parâmetro.

Parameters
  • statement_query_option (str): A opção de extrato selecionada pelo usuário.
  • accounts (list): Lista com as contas a serem consultadas.
  • initial_data (str): A data inicial da consulta.
  • final_data (str): A data final da consulta.
Returns
  • value_list (list): A lista com os valores do extrato.
  • data_df_list (list): A lista com os gráficos estruturados.
def generate_pdf( self, df: list, statement_type: str, initial_data: str, final_data: str, accounts: list):
196    def generate_pdf(self, df: list, statement_type: str, initial_data: str, final_data: str, accounts: list):
197        """
198        Gera o PDF do extrato bancário.
199
200        Parameters
201        ----------
202        df : list
203            A lista com os gráficos.
204        statement_type : str
205            O tipo de extrato bancário.
206        initial_data : str
207            A data inicial do extrato.
208        final_data : str
209            A data final do extrato.
210        accounts : list
211            Lista com as contas consultadas.
212
213        Returns
214        -------
215        pdf: O PDF gerado pela função.
216        """
217
218        user_name, user_document = Login().get_user_data(return_option="user_doc_name")
219
220        unformatted_today = datetime.strptime(today, '%Y-%m-%d')
221        formatted_today = unformatted_today.strftime('%d/%m/%Y')
222
223        time = GetActualTime().get_actual_time()
224
225        accounts_str = ""
226        for item in range(0, len(accounts)):
227            if item < (len(accounts) - 1):
228                accounts_str = accounts_str + accounts[item] + ", "
229            if item == len(accounts) - 1:
230                accounts_str = accounts_str + accounts[item] + "."
231
232        pdf = FPDF(orientation='L', unit="mm", format="A4")
233        pdf.add_page()
234        pdf.add_font("SystemFont", "", "{}{}".format(absolute_app_path, system_font), uni=True)
235
236        pdf.set_font("SystemFont", size=16)
237        pdf.cell(0, 10, "Relatório de {}".format(statement_type), ln=True, align="C")
238        pdf.ln(10)
239
240        pdf.set_font("SystemFont", size=12)
241        pdf.cell(0, 5, "Período de consulta: {} à {}".format(initial_data, final_data), ln=True)
242        pdf.set_font("SystemFont", size=12)
243        pdf.cell(0, 10, "Contas consultadas: {}".format(accounts_str), ln=True)
244        pdf.ln(5)
245
246        statement_types = ["Receitas", "Despesas"]
247
248        for i in range(0, len(df)):
249
250            pdf.set_font("SystemFont", size=14)
251            pdf.cell(0, 10, "{}".format(statement_types[i]), ln=True)
252            pdf.ln(5)
253
254            col_width = (pdf.w / len(df[i].columns)) * 0.85
255
256            pdf.set_font("SystemFont", size=10)
257
258            for col in df[i].columns:
259                pdf.cell(col_width, 5, col, border=1, align="C")
260            pdf.ln()
261            pdf.set_font("SystemFont", size=10)
262            for _, row in df[i].iterrows():
263                for cell in row:
264                    pdf.cell(col_width, 10, str(cell), border=1, align="C")
265                pdf.ln()
266            pdf.ln(10)
267
268        # pdf.cell(0, 10, "{}".format(generated_description), align="L", ln=True)
269
270        pdf.cell(0, 10, "Horário da consulta: {}, às {}.".format(formatted_today, time), align="R", ln=True)
271        pdf.cell(0, 10, "Nome do usuário: {}.".format(user_name), align="R", ln=True)
272        pdf.ln(5)
273
274        return pdf

Gera o PDF do extrato bancário.

Parameters
  • df (list): A lista com os gráficos.
  • statement_type (str): O tipo de extrato bancário.
  • initial_data (str): A data inicial do extrato.
  • final_data (str): A data final do extrato.
  • accounts (list): Lista com as contas consultadas.
Returns
  • pdf (O PDF gerado pela função.):
def main_menu(self):
276    def main_menu(self):
277        """
278        Menu principal.
279        """
280        user_name, user_document = Login().get_user_data(return_option="user_doc_name")
281        logged_user, logged_user_password = Login().get_user_data(return_option="user_login_password")
282
283        user_current_accounts = QueryExecutor().complex_consult_query(query=user_current_accounts_query, params=(user_name, user_document))
284        user_current_accounts = QueryExecutor().treat_numerous_simple_result(user_current_accounts, to_remove_list)
285
286        col4, col5, col6 = st.columns(3)
287
288        if len(user_current_accounts) > 0:
289
290            with col4:
291                st.subheader(body=":computer: Entrada de Dados")
292                with st.expander(label="Dados", expanded=True):
293                    statement_option = st.selectbox(label="Tipos de extrato", options=["Selecione uma opção", "Receitas", "Despesas", "Receitas e Despesas"])
294                    selected_accounts = st.multiselect(label="Contas", options=user_current_accounts, placeholder="Escolha a(s) conta(s)")
295                    initial_data = st.date_input(label="Data de início")
296                    final_data = st.date_input(label="Data de fim")
297                    confirm_choice = st.checkbox(label="Confirmar dados")
298
299                consult_tables = st.button(label=":chart: Gerar Relatórios")
300
301            if confirm_choice and consult_tables:
302                with col5:
303                    with st.spinner(text="Aguarde..."):
304                        sleep(2.5)
305
306                    st.subheader(body=":bar_chart: Resultados")
307
308                    if statement_option != "Selecione uma opção" and len(selected_accounts) > 0 and (initial_data <= final_data):
309                        value_list, dataframes = self.consult_statement(statement_option, selected_accounts, initial_data, final_data)
310
311                        with col6:
312                            with st.spinner(text="Aguarde..."):
313                                sleep(2.5)
314                            st.subheader(body=":information_source: Informações")
315
316                            total_value = 0
317                            counter = 0
318
319                            for i in range(0, len(value_list)):
320                                for j in range(0, len(value_list[i])):
321                                    total_value += value_list[i][j]
322                                    counter += 1
323                                medium_value = round((total_value / len(value_list[i])), 2)
324
325                            medium_value = str(medium_value)
326                            medium_value = medium_value.replace(".", ",")
327                            total_value = str(total_value)
328                            total_value = total_value.replace(".", ",")
329
330                            with st.expander(label="Dados", expanded=True):
331                                st.info(body="Quantidade de {}: {}.".format(statement_option.lower(), counter))
332                                st.info(body="Valor total das {}: R$ {}.".format(statement_option.lower(), total_value))
333                                st.info(body="Valor médio das {}: R$ {}.".format(statement_option.lower(), medium_value))
334
335                            formatted_initial_data = initial_data.strftime("%d/%m/%Y")
336                            formatted_final_data = final_data.strftime("%d/%m/%Y")
337
338                            log_query = '''INSERT INTO financas.logs_atividades (usuario_log, tipo_log, conteudo_log) VALUES ( %s, %s, %s);'''
339                            log_values = (logged_user, "Consulta", "Consultou o relatório de {} entre o período de {} a {}.".format(statement_option, formatted_initial_data, formatted_final_data))
340                            QueryExecutor().insert_query(log_query, log_values, "Log gravado.", "Erro ao gravar log:")
341
342                            time = GetActualTime().get_actual_time()
343
344                            pdf = self.generate_pdf(dataframes, statement_option, formatted_initial_data, formatted_final_data, selected_accounts)
345                            pdf_bytes = pdf.output(dest='S').encode('latin1')
346
347                            st.download_button(
348                                label=":floppy_disk: Baixar PDF",
349                                data=pdf_bytes,
350                                file_name="extrato_bancario_{}_{}_a_{}_{}.pdf".format(statement_option.replace(" ", "_").lower(), initial_data, final_data, time),
351                                mime="application/pdf",
352                            )
353
354                    elif (len(selected_accounts) == 0) or (initial_data > final_data) or (statement_option == "Selecione uma opção"):
355                        with st.expander(label="Avisos", expanded=True):
356                            if statement_option == "Selecione uma opção":
357                                st.error(body="Selecione um tipo de extrato.")
358                            if len(selected_accounts) == 0:
359                                st.error(body="Nenhuma conta selecionada.")
360                            if initial_data > final_data:
361                                st.error(body="A data inicial não pode ser maior que a final.")
362
363        elif len(user_current_accounts) == 0:
364            with col5:
365                st.warning(body="Você ainda não possui contas cadastradas.")

Menu principal.