from io import BytesIO import os from typing import List, Tuple from openpyxl import Workbook from openpyxl.styles import Font from openpyxl.styles import Alignment from openpyxl.styles import numbers from openpyxl.styles.borders import Border, Side import streamlit as st import pandas as pd import numpy as np from data.cli_dropbox import dropbox_download_file, dropbox_upload_bytefile from .dataframes import complete_affaires, complete_arrets, complete_intervenants, complete_supplements, complete_vehicules, merge_clients, merge_affaires, merge_intervenants_affaires,cast_specifics_to_str def check_paths(paths: List[str]) -> bool: files = [] for path in paths: if not os.path.exists(path) or not os.path.isfile(path): files.append(path) return files def load_excels(datapath: str, excel_sources: List[dict]) -> pd.DataFrame: data = {} for key, value in excel_sources.items(): data[key] = pd.read_excel(os.path.join(datapath, excel_sources[key]['path']), sheet_name=excel_sources[key]['sheet_name'], usecols=excel_sources[key]['columns'], nrows=excel_sources[key]['rows'], skiprows=excel_sources[key]['skiprows'], ) return data @st.cache_data def load_transform_data(datapath: str, excel_sources: List[dict]) -> pd.DataFrame: not_files = check_paths([os.path.join(datapath, excel['path']) for excel in excel_sources.values()]) if len(not_files): st.error(f'Erreur: une partie de la base de données n\'est pas accessible. {not_files}') return data = load_excels(datapath, excel_sources) merge_clients(data) merge_affaires(data) merge_intervenants_affaires(data) complete_vehicules(data) complete_supplements(data) complete_intervenants(data) complete_affaires(data) complete_arrets(data) cast_specifics_to_str(data) return data def filter_multiple_conditions_data(df, filters): filtered_df = df[df[filters.keys()].isin(filters.values()).all(axis=1)] return filtered_df def draw_border(sheet, start_cell: Tuple[int, int], end_cell: Tuple[int, int]): # Define the border style border_style = Border(left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin')) # Define the range of cells to apply borders to start_cell = sheet.cell(row=start_cell[0], column=start_cell[1]) end_cell = sheet.cell(row=end_cell[0] , column=end_cell[1]) cell_range = '{}:{}'.format(start_cell.coordinate, end_cell.coordinate) # Apply borders to the range of cells for row in sheet[cell_range]: for cell in row: cell.border = border_style def get_fit_totals(dataframe): column_sums = {} for column in dataframe.columns: if dataframe[column].dtype in [int, float] and not np.isnan(dataframe[column]).all(): column_sums[column] = dataframe[column].sum() column_sums['rows'] = dataframe.shape[0] column_sums['worked_hours'] = column_sums['H.\njour'] + column_sums['H.\nnuit (1)'] return column_sums def load_fit(datapath: str, intervenant: str, year: str, month: str, week: str): filename = f'{intervenant}_{year}_{month}_{week}_FIT.xlsx' if dropbox_download_file(f'/SEC_IND_GTP2023_OUTPUT/FIT/{intervenant}/{year}/{month}/{week}/{filename}', os.path.join(datapath, filename)): #TODO get file from dropbox if os.path.exists(os.path.join(datapath, filename)) and os.path.isfile(os.path.join(datapath, filename)): data = pd.read_excel(os.path.join(datapath, filename), sheet_name='Sheet', skiprows=6, nrows=10) data.dropna(axis=0, how='all', inplace=True) totals = get_fit_totals(data) if 'fit' not in st.session_state.keys(): st.session_state['fit'] = {} if intervenant not in st.session_state['fit'].keys(): st.session_state['fit'][intervenant] = {} if year not in st.session_state['fit'][intervenant].keys(): st.session_state['fit'][intervenant][year] = {} if month not in st.session_state['fit'][intervenant][year].keys(): st.session_state['fit'][intervenant][year][month] = {} if week not in st.session_state['fit'][intervenant][year][month].keys(): st.session_state['fit'][intervenant][year][month][week] = {} st.session_state['fit'][intervenant][year][month][week] = { 'data': data, 'totals': totals } return data print('error loading fit') return None async def update_society_fit(dropbox_datapath: str, form: dict): society = form['prestataire'] year = form['year'] month = form['month'] week = form['week'] dropbox_path = f'{dropbox_datapath}/SOCIETE/{society}/{year}/{month}/{week}' filename = f'{society}_{year}_{month}_{week}_FIT.csv' fit_df = pd.DataFrame([form]) fit = dropbox_download_file(os.path.join(dropbox_path, filename), '', False) if fit: fit = pd.read_csv(BytesIO(fit), index_col=0) fit_df = pd.concat([fit, fit_df], ignore_index=True) csv_data = BytesIO() fit_df.to_csv(csv_data, index = False) dropbox_upload_bytefile(dropbox_data_path=dropbox_path, dropbox_file_name=filename, bytes=csv_data) return fit_df async def update_society_payroll(dropbox_datapath: str, form: dict): prestataire = form['Prestataire'] fournisseur = form['Fournisseur'] year = form['year'] month = form['month'] dropbox_path = f'{dropbox_datapath}/PRESTATIONS/{prestataire}/{year}/{month}' filename = f'{prestataire}_{fournisseur}_{year}_{month}_PRESTATIONS_CROISEES.xlsx' payroll_df = pd.DataFrame([form]) payroll = dropbox_download_file(os.path.join(dropbox_path, filename), '', False) if payroll: payroll = pd.read_excel(BytesIO(payroll)) payroll_df = pd.concat([payroll, payroll_df], ignore_index=True) excel_data = BytesIO() payroll_df.to_excel(excel_data, index = False) dropbox_upload_bytefile(dropbox_data_path=dropbox_path, dropbox_file_name=filename, bytes=excel_data) return payroll_df async def update_historical_week(dropbox_datapath: str, form: dict): intervenant = form['intervenant'] year = form['year'] month = form['month'] week = form['week'] dropbox_path = f'{dropbox_datapath}/FIT/{intervenant}/{year}/{month}/{week}' historic_df = pd.DataFrame([form]) historic = dropbox_download_file(dropbox_path + '/historique.xlsx', '', False) if historic: historic = pd.read_excel(historic) historic_df = pd.concat([historic, historic_df], ignore_index=True) excel_data = BytesIO() historic_df.to_excel(excel_data, index = False) dropbox_upload_bytefile(dropbox_data_path=dropbox_path, dropbox_file_name='historique.xlsx', bytes=excel_data) return historic_df async def update_monthly_payroll(dropbox_datapath: str, payroll_dict: dict, year: str, month: str, week: str): dropbox_path = f'{dropbox_datapath}/PAYES' # dropbox_path = dropbox_datapath nom = payroll_dict['Nom'] prenom = payroll_dict['Prénom'] payroll_df = pd.DataFrame([payroll_dict]) payroll = dropbox_download_file(dropbox_path + f'/tableau_prepaye_{year}_{month}.xlsx', '', False) if payroll: payroll = pd.read_excel(payroll) intervenant_rows = payroll[(payroll['Nom'] == nom) & (payroll['Prénom'] == prenom)] # print(len(intervenant_rows)) if len(intervenant_rows): current_week_row = payroll[(payroll['Nom'] == nom) & (payroll_df['Prénom'] == prenom) & (payroll['Semaine'] == f'{year}-s{week}')] # print(len(current_week_row)) if len(current_week_row): payroll.iloc[current_week_row.index] = payroll_df.loc[0] payroll_df = payroll else: payroll_df = pd.concat([payroll, payroll_df], ignore_index=True) else: payroll_df = pd.concat([payroll, payroll_df], ignore_index=True) rows_for_total = payroll_df[(payroll_df['Nom'] == nom) & (payroll_df['Prénom'] == prenom) & (payroll_df['Semaine'].str.contains(f'{year}-s'))] total = pd.DataFrame([rows_for_total.drop(columns=['Nom', 'Prénom', 'Semaine']).sum()]) total['Nom'] = nom total['Prénom'] = prenom total['Semaine'] = 'TOTAL' all_but_total = payroll_df[~((payroll_df['Nom'] == nom) & (payroll_df['Prénom'] == prenom) & (payroll_df['Semaine'].str.contains('TOTAL')))] # print(all_but_total) payroll_df = pd.concat([total, all_but_total], ignore_index=True, axis = 0) # print(payroll_df) payroll_df = payroll_df.sort_values(by=['Nom', 'Prénom', 'Semaine']) column_order = payroll_df.columns[-3:].tolist() + payroll_df.columns[:-3].tolist() payroll_df = payroll_df[column_order] excel_data = BytesIO() payroll_df.to_excel(excel_data, index = False) dropbox_upload_bytefile(dropbox_data_path=dropbox_path, dropbox_file_name=f'tableau_prepaye_{year}_{month}.xlsx', bytes=excel_data) return payroll_df def write_excel_fit(datapath: str, filename: str, data, starting_row = 7): workbook = Workbook() sheet = workbook.active sheet.column_dimensions['A'].width = 60 sheet.column_dimensions['B'].width = 40 sheet.column_dimensions['C'].width = 80 sheet.column_dimensions['D'].width = 40 sheet.column_dimensions['E'].width = 20 sheet.column_dimensions['K'].width = 60 sheet.column_dimensions['L'].width = 40 sheet.column_dimensions['M'].width = 40 sheet.column_dimensions['O'].width = 20 sheet.column_dimensions['P'].width = 40 sheet.column_dimensions['Q'].width = 40 sheet.column_dimensions['R'].width = 40 sheet.column_dimensions['S'].width = 20 sheet.row_dimensions[29].height = 30 sheet.row_dimensions[31].height = 40 sheet['A1'] = 'SECMI' sheet['D1'] = 'FICHE D\'INTERVENTION ET DE TEMPS (FIT)' sheet['A3'] = f'Intervenant: {data["intervenant"]}' draw_border(sheet, (3, 1), (3, 1)) sheet.merge_cells('M1:N1') sheet['M1'] = f'Année: {data["year"]}' draw_border(sheet, (1, 13), (1, 13)) sheet.merge_cells('M2:N2') sheet['M2'] = f'Semaine: {data["week"]}' draw_border(sheet, (2, 13), (2, 13)) sheet['A18'] = '(1) travail effectué entre 21h00 et 06h00' sheet.merge_cells('A19:S22') sheet['A19'] = 'Commentaires SECMI:' draw_border(sheet, (19, 1), (22, 19)) sheet.merge_cells('A23:S26') sheet['A23'] = 'Commentaires Client:' draw_border(sheet, (23, 1), (26, 19)) sheet.merge_cells('A30:D30') sheet['A30'] = 'Signature client:' draw_border(sheet, (30, 1), (30, 4)) sheet.merge_cells('A31:D32') draw_border(sheet, (31, 1), (32, 4)) sheet['E30'] = 'Note\n(de 0 à 10)' draw_border(sheet, (30, 5), (30, 5)) sheet.merge_cells('E31:E32') draw_border(sheet, (31, 5), (32, 5)) sheet['L30'] = 'Signature chargé d\'affaire:' draw_border(sheet, (30, 12), (30, 12)) sheet.merge_cells('L31:L32') draw_border(sheet, (31, 12), (32, 12)) sheet['M30'] = 'Signature intervenant:' draw_border(sheet, (30, 13), (30, 13)) sheet.merge_cells('M31:M32') draw_border(sheet, (31, 13), (32, 13)) sheet.merge_cells('A33:T33') sheet.merge_cells('A34:T34') draw_border(sheet, (33, 1), (34, 19)) sheet['A33'] = 'Service Administratif' sheet['A34'] = 'Tel: +33 6 02 14 55 16 - Email : compta.grh@secmi-addax.com' # Define the starting row for writing the dictionary draw_border(sheet, (starting_row, 1), (starting_row + 10, 19)) draw_border(sheet, (starting_row - 2, 4), (starting_row -2, 19)) sheet.cell(row=starting_row - 2, column=4, value='TOTAUX (en heure)') # Write the dictionary to the sheet starting from the specified row header = list(data['data'].keys()) for col_i, key in enumerate(header): sheet.cell(row=starting_row, column=col_i + 1, value=key) if key in data['totals'].keys(): sheet.cell(row=starting_row - 2, column=col_i + 1, value=data['totals'][key]) for cell in sheet[starting_row - 2]: cell.font = Font(bold=True) for cell in sheet[starting_row]: cell.font = Font(bold=True) starting_row += 1 for col_i, key in enumerate(data['data'].keys()): values = data['data'][key] for j, value in enumerate(values): sheet.cell(row=starting_row + j, column=col_i + 1, value=value) alignment = Alignment(horizontal='center', vertical='center') # Set the decimal format decimal_format = numbers.FORMAT_NUMBER_00 for row in sheet.iter_rows(): for cell in row: cell.alignment = alignment cell.number_format = decimal_format sheet['A1'].font = Font(bold=True, underline='single', size=11) sheet['D1'].font = Font(bold=True, underline='single', size=11) sheet['A19'].font = Font(bold=True, underline='single') sheet['A19'].alignment = Alignment(horizontal='left', vertical='top') sheet['A23'].font = Font(bold=True, underline='single') sheet['A23'].alignment = Alignment(horizontal='left', vertical='top') sheet['A33'].font = Font(bold=True) sheet['A33'].alignment = Alignment(horizontal='center') sheet['A34'].font = Font(bold=True) sheet['A34'].alignment = Alignment(horizontal='center') workbook.save(os.path.join(datapath, filename))