Team Ai
Apppublic

thanhpham0704/streamlit_python

sourceHugging Faceupdated 4y agoView on Hugging Face
0likes
Homepage.py710 linesDownload Raw Back to root
1import streamlit as st2import requests3import plotly.express as px4import pandas as pd5from datetime import datetime, timedelta6from pathlib import Path7import pickle8import streamlit_authenticator as stauth9import numpy as np10import calendar11 12# names = ["Phạm Tấn Thành", "Phạm Minh Tâm", "Vận hành"]13# usernames = ["thanhpham", "tampham", "vietopvanhanh"]14# passwords = ['thanhpham0704', 'tampham1234', 'vanhanh2023']15 16# hashed_passwords = stauth.Hasher(passwords).generate()17 18# file_path = Path(__file__).parent / "hashed_pw.pkl"19# with file_path.open("wb") as file:20#     pickle.dump(hashed_passwords, file)21 22page_title = "Lương và thực thu"23page_icon = ":chart_with_upwards_trend:"24layout = "wide"25st.set_page_config(page_title=page_title, page_icon=page_icon, layout=layout)26 27# ----------------------------------------28names = ["Phạm Tấn Thành", "Phạm Minh Tâm", "Vận hành"]29usernames = ["thanhpham", "tampham", "vietopvanhanh"]30 31# Load hashed password32file_path = Path(__file__).parent / 'hashed_pw.pkl'33with file_path.open("rb") as file:34    hashed_passwords = pickle.load(file)35 36authenticator = stauth.Authenticate(names, usernames, hashed_passwords,37                                    "sales_dashboard", "abcdef", cookie_expiry_days=1)38 39name, authentication_status, username = authenticator.login("Login", "main")40 41if authentication_status == False:42    st.error("Username/password is incorrect")43 44if authentication_status == None:45    st.warning("Please enter your username and password")46 47if authentication_status:48    authenticator.logout("logout", "main")49 50    # Add CSS styling to position the button on the top right corner of the page51    st.markdown(52        """53            <style>54            .stButton button {55                position: absolute;56                top: 0px;57                right: 0px;58            }59            </style>60            """,61        unsafe_allow_html=True62    )63    st.title(page_title + " " + page_icon)64    #----------------------#65    # Filter66    now = datetime.now()67    DEFAULT_START_DATE = datetime(now.year, now.month, 1)68    DEFAULT_END_DATE = datetime(now.year, now.month, 1) + timedelta(days=32)69    DEFAULT_END_DATE = DEFAULT_END_DATE.replace(day=1) - timedelta(days=1)70 71    # Create a form to get the date range filters72    with st.form(key='date_filter_form'):73        col1, col2 = st.columns(2)74        ketoan_start_time = col1.date_input(75            "Select start date", value=DEFAULT_START_DATE)76        ketoan_end_time = col2.date_input(77            "Select end date", value=DEFAULT_END_DATE)78        submit_button = st.form_submit_button(79            label='Filter')80 81    # the duration between 2 dates exclude Sunday82    duration = sum(1 for i in range((ketoan_end_time - ketoan_start_time).days)83                   if (ketoan_start_time + timedelta(i)).weekday() != 6)84    # the number of days in a month exclude Sunday85    days_in_month = calendar.monthrange(86        ketoan_start_time.year, ketoan_start_time.month)[1]87    sundays_in_month = sum(1 for day in range(1, days_in_month + 1) if datetime(88        ketoan_start_time.year, ketoan_start_time.month, day).weekday() == 6)89    days_excluding_sundays = days_in_month - sundays_in_month90    #----------------------#91 92    @st.cache(ttl = timedelta(days = 1))93    def collect_data(link):94        return(pd.DataFrame((requests.get(link).json())))95 96    @st.cache97    def rename_lop(dataframe, column_name):98        dataframe[column_name] = dataframe[column_name].replace(99            {1: "Hoa Cúc", 2: "Gò Dầu", 3: "Lê Quang Định", 5: "Lê Hồng Phong"})100        return dataframe101 102    @st.cache103    def grand_total(dataframe, column):104        # create a new row with the sum of each numerical column105        totals = dataframe.select_dtypes(include=[float, int]).sum()106        totals[column] = "Grand total"107        # append the new row to the dataframe108        dataframe = dataframe.append(totals, ignore_index=True)109        return dataframe110 111    # "---------------" Thông tin lương giáo viên112    users = collect_data('https://vietop.tech/api/get_data/users')113    # Thong tin luong114    import gspread115    sa = gspread.service_account(116        filename='taichinh-380507-b8f84e9ee681.json')117    sh = sa.open("Nhân sự")118    worksheet = sh.worksheet("Giáo viên")119    salary = pd.DataFrame(worksheet.get_all_records())120    salary = salary.replace("", np.nan).dropna(subset='Mã giáo viên')121    salary = salary.replace('\.', '', regex=True)122    salary = salary.astype({'Lương theo hợp đông': 'float', 'Thâm niên': 'float',123                           'Chức danh': "float", 'Tổng lương': 'float', 'date_affected': 'datetime64[ns]'})124    # salary.info()125    # salary = salary.sort_values("date_affected", ascending=False)\126    #     .drop_duplicates(subset='id_gg')127    salary = salary.sort_values("date_affected", ascending=False)\128        .query("date_affected <= @ketoan_end_time")\129        .drop_duplicates("id_gg")130    salary.fillna(0, inplace=True)131    # Thong tin luong132    salary['salary_ngay_cong'] = round(133        salary['Tổng lương'] * duration/days_excluding_sundays, 0)134    salary.fillna(0, inplace=True)135    salary.drop(['STT', 'Mã giáo viên', 'Tổng lương'], axis=1, inplace=True)136    salary.rename(columns={"Lương theo hợp đông": "hopdong", "Thâm niên": "thamnien",137                           'Chức danh': 'chucdanh', 'Ngày': 'ngay', 'Tối': 'toi', 'Cuối tuần': 'cuoituan',138                           'Trợ giảng': 'trogiang', 'BHXH': 'bhxh', 'Chế độ': 'working_status', 'Bậc giáo viên': 'level', 'Tổng ngày nghỉ phép': 'ngaynghi_total',139                           'Tổng ngày công thực tế': 'ngaycong_real_total'}, inplace=True)140 141    # "------------------"142    gv_diemdanh = collect_data('https://vietop.tech/api/get_data/diemdanh')143    gv_diemdanh['date_created'] = pd.to_datetime(gv_diemdanh['date_created'])144    gv_diemdanh = gv_diemdanh.query(145        "date_created >= @ketoan_start_time and date_created <= @ketoan_end_time")146    # Ca hoc table147    cahoc = {'cahoc': ['ca1', 'ca2', 'ca3', 'ca4', 'ca5', 'ca6'],148             'start_time': ['08:30:00', '10:30:00', '13:30:00', '15:30:00', '18:00:00', '19:45:00'],149             'end_time': ['10:30:00', '12:30:00', '15:30:00', '17:30:00', '19:45:00', '21:30:00']}150    cahoc = pd.DataFrame(cahoc)151    # --------------- GET DATA FROM API152 153    sh = sa.open("Nhân sự")154    worksheet = sh.worksheet("Overtime")155    offline_overtime = pd.DataFrame(worksheet.get_all_records())156    offline_overtime['date_affected'] = pd.to_datetime(157        offline_overtime['date_affected'])158    offline_overtime = offline_overtime.sort_values("date_affected", ascending=False)\159        .drop_duplicates(subset='Họ và tên')160    offline_overtime.drop("date_affected", axis=1, inplace=True)161 162    # Define the start and end times of the day163    start_time = pd.to_datetime('2000-01-01 06:00:00').time()164    end_time = pd.to_datetime('2000-01-01 18:00:00').time()165    ca1 = pd.to_datetime('2000-01-01 06:30:00').time()166    ca2 = pd.to_datetime('2000-01-01 10:30:00').time()167    ca3 = pd.to_datetime('2000-01-01 13:30:00').time()168    ca4 = pd.to_datetime('2000-01-01 15:30:00').time()169    ca5 = pd.to_datetime('2000-01-01 18:00:00').time()170    # tren office khong cos 19:45171    ca6 = pd.to_datetime('2000-01-01 19:30:00').time()172    # Create a function that takes a time and returns "Morning" or "Evening" depending on whether the time falls within the specified range173 174    @st.cache175    def time_of_day(time):176        if (time >= start_time) & (time < end_time):177            return "Sáng"178        else:179            return "Tối"180    # Create a function that takes a time and returns "Morning" or "Evening" depending on whether the time falls within the specified range181 182    @st.cache183    def day_of_week(day):184        if (day == 5) | (day == 6):185            return "weekend"186        else:187            return "weekdays"188    # Create a function that takes a time and returns "Morning" or "Evening" depending on whether the time falls within the specified range189 190    @st.cache191    def cahoc_converter(ca):192        if (ca >= ca1) & (ca < ca2):193            return 1194        elif (ca >= ca2) & (ca < ca3):195            return 2196        elif (ca >= ca3) & (ca < ca4):197            return 3198        elif (ca >= ca4) & (ca < ca5):199            return 4200        elif (ca >= ca5) & (ca < ca6):201            return 5202        elif (ca >= ca6):203            return 6204 205    # "---------------" Bảng lương giáo viên206 207    overtime_melt = offline_overtime.melt(208        id_vars=['id_gg', 'Họ và tên', 'WORKING_STATUS'], var_name='Column Name', value_name='overtime_status')209    overtime_melt['day_of_week'], overtime_melt['cahoc'] = overtime_melt['Column Name'].str.split(210        'Ca ', 1).str211    overtime_melt['day_of_week'].replace(212        {'T2': 0, 'T3': 1, 'T4': 2, 'T5': 3, 'T6': 4, 'T7': 5, 'T8': 6}, inplace=True)213    overtime_melt['overtime_status'].replace(214        {0: 'in', 'a': 'out'}, inplace=True)215    # Convert 5 and 6 into "Cuối tuần"216    overtime_melt['weekend_or_not'] = overtime_melt['day_of_week'].apply(217        day_of_week)218    # Convert ca into Sáng or Tối219    overtime_melt['time_of_day'] = ['Sáng' if i in [220        '1', '2', '3', '4'] else 'Tối' for i in overtime_melt['cahoc']]221    # Drop unnecessary columns222    overtime_melt.drop(223        ['Column Name'], axis=1, inplace=True)224    overtime_melt['cahoc'] = overtime_melt['cahoc'].astype(int)225    overtime_melt.rename(226        columns={'WORKING_STATUS': 'working_status'}, inplace=True)227 228    # "---------------" Lương overtime của giáo viên229    lophoc = collect_data('https://vietop.tech/api/get_data/lophoc')230    diemdanh = gv_diemdanh.merge(users[['fullname', 'id']], left_on='giaovien', right_on='id', how='inner')\231        .sort_values("created_at", ascending=False)232    # diemdanh['cahoc'].replace({0: 'không học', 1: 'ca1', 2: 'ca2', 3: 'ca3', 4:'ca4', 5:'ca5', 6:'ca6', 7:'ca 1.5 giờ', 8: 'ca 2.5 giờ', 9: 'ca 3.0 giờ', 10: 'ca 1 giờ', 11: 'ca 1.75 giờ', 12: 'ca 2 giờ'}, inplace = True)233    diemdanh = diemdanh[['lop_id', 'sogio', 'cahoc', 'phanloai',234                        'date_created', 'created_by', 'id',235                         'updated_by', 'created_at', 'fullname']]236    # Convert the date column to datetime237    diemdanh['created_at'] = pd.to_datetime(diemdanh['created_at'])238    # Extract the time component of each datetime value239    diemdanh['created_at_time'] = diemdanh['created_at'].dt.time240    # Create a new column that indicates the day of the week241    diemdanh['day_of_week'] = diemdanh['created_at'].dt.dayofweek242    # Create a boolean mask that indicates whether each time is within the specified time frame243    diemdanh["time_of_day"] = diemdanh['created_at_time'].apply(time_of_day)244    # Convert 5 and 6 into "Cuối tuần"245    diemdanh['weekend_or_not'] = diemdanh["day_of_week"].apply(day_of_week)246    diemdanh = diemdanh[['id', 'fullname', 'sogio', 'cahoc', 'phanloai',247                        'created_at', 'day_of_week', 'created_at_time', 'time_of_day', 'weekend_or_not', 'date_created',248                         'lop_id']]249    diemdanh['cahoc'] = diemdanh['created_at_time'].apply(cahoc_converter)250    # Sum giohoc according to fullname, time of day and weekend or not251    diemdanh_sum_giohoc = diemdanh.groupby(252        ["id", "fullname", "cahoc", 'phanloai', 'day_of_week', "time_of_day", "weekend_or_not", 'lop_id'], as_index=False)['sogio'].sum()253    # Get lopcn from lophoc254    diemdanh_lop_cn = diemdanh_sum_giohoc.merge(255        lophoc[['lop_id', 'lop_cn']], on='lop_id')256 257    # "---------------"258    sal_diem = diemdanh_lop_cn.merge(259        salary, left_on='id', right_on='id_gg')260    # Merge diemdanh and overtime261    sal_diem_over = sal_diem\262        .merge(overtime_melt, on=['id_gg', 'Họ và tên', 'cahoc', 'day_of_week', 'time_of_day', 'weekend_or_not'], how='inner', validate='many_to_many')263    # Drop duplicates264    sal_diem_over.drop_duplicates(inplace=True)265    # Fill na266    sal_diem_over.fillna(0, inplace=True)267    # Calculate luong ngay cong268    empty = []269    for index, value in sal_diem_over.iterrows():270        if value['weekend_or_not'] == 'weekend' and value['overtime_status'] == 'out':271            empty.append(value['cuoituan'] * value['sogio'])272        elif value['time_of_day'] == 'Tối' and value['overtime_status'] == 'out':273            empty.append(value['toi'] * value['sogio'])274        elif value['time_of_day'] == 'Sáng' and value['overtime_status'] == 'out':275            empty.append(value['ngay'] * value['sogio'])276        elif value['phanloai'] == 0:277            empty.append(value['trogiang'] * value['sogio'])278        else:279            empty.append(0)280    sal_diem_over['salary_gio_cong'] = empty281 282    # Slicing columns283    sal_diem_over = sal_diem_over.loc[:, ['lop_cn', 'id_gg', 'Họ và tên', 'working_status_x', 'cahoc', 'phanloai', 'overtime_status',284                                          'time_of_day', 'day_of_week', 'weekend_or_not', 'sogio',285                                          'ngay', 'toi', 'cuoituan', 'trogiang', 'salary_gio_cong', 'salary_ngay_cong']]286    sal_diem_over_group_lop = sal_diem_over.groupby(['id_gg', 'Họ và tên', 'lop_cn', 'working_status_x', 'overtime_status', 'salary_ngay_cong'], as_index=False)['sogio', 'salary_gio_cong'].sum()\287        .query("overtime_status == 'out'")288    # Sum luong_gio_cong according to fullname289    sal_diem_over_group = sal_diem_over.groupby(['id_gg', 'Họ và tên', 'working_status_x', 'overtime_status', 'salary_ngay_cong'], as_index=False)['sogio', 'salary_gio_cong'].sum()\290        .query("overtime_status == 'out'").sort_values("salary_gio_cong", ascending=False)291    sal_diem_over_details = sal_diem_over.drop('salary_ngay_cong', axis=1)\292        .query("overtime_status == 'out'")\293 294    # ----------------------# Phân phối lương cứng theo chi nhánh295    df = sal_diem_over.groupby(['lop_cn', 'id_gg', 'Họ và tên', 'working_status_x', 'overtime_status',296                                'salary_ngay_cong'], as_index=False)['sogio', 'salary_gio_cong'].sum()297    df = df.query('overtime_status == "in"')298    df_sum = df.groupby('Họ và tên', as_index=False)['sogio'].sum()299    df_proportion = df_sum.merge(df, on='Họ và tên')300    df_proportion['proportion_sogio'] = df_proportion['sogio_y'] / \301        df_proportion['sogio_x']302    df_proportion['salary_ngay_cong_divided'] = df_proportion['proportion_sogio'] * \303        df_proportion['salary_ngay_cong']304    # Giáo viên ngoại trừ phòng đào tạo305    df_proportion_nodaotao = df_proportion[~df_proportion['Họ và tên'].isin(306        ['Mai Minh Trung', 'Trần Thị Thanh Nga', 'Nguyễn Thị Thu Hà', 'Huỳnh Trương Hồng Châu Long', 'Nguyễn Huy Hoàng', 'Đỗ Nguyễn Đăng Khoa'])]307    # Subset308    df_proportion_nodaotao = df_proportion_nodaotao[[309        'id_gg', 'Họ và tên', 'lop_cn', 'salary_ngay_cong_divided']]310    # Riêng phòng đào tạo311    df_proportion_daotao = salary[salary['Họ và tên'].isin(312        ['Phạm Tấn Thành', 'Mai Minh Trung', 'Trần Thị Thanh Nga', 'Nguyễn Thị Thu Hà', 'Huỳnh Trương Hồng Châu Long', 'Nguyễn Huy Hoàng', 'Đỗ Nguyễn Đăng Khoa'])]313    df_proportion_daotao['1'] = 0.26 * df_proportion_daotao['salary_ngay_cong']314    df_proportion_daotao['2'] = 0.26 * df_proportion_daotao['salary_ngay_cong']315    df_proportion_daotao['3'] = 0.18 * df_proportion_daotao['salary_ngay_cong']316    df_proportion_daotao['5'] = 0.30 * df_proportion_daotao['salary_ngay_cong']317    # Subset318    df_proportion_daotao = df_proportion_daotao.loc[:, [319        'id_gg', 'Họ và tên', '1', '2', '3', '5']]320    # Lương đào tạo sau khi phân phối321    df_proportion_daotao = pd.melt(df_proportion_daotao, id_vars=[322        'id_gg', 'Họ và tên'], var_name='lop_cn', value_name='salary_ngay_cong_divided')323    df_proportion_daotao['lop_cn'] = df_proportion_daotao['lop_cn'].astype(324        'int64')325    # Concat luong đào tạo and lương giáo viên326    salary_gv_dt = pd.concat([df_proportion_daotao, df_proportion_nodaotao])327    salary_gv_dt['salary_ngay_cong_divided'] = round(328        salary_gv_dt['salary_ngay_cong_divided'], 2)329    salary_gv_dt = salary_gv_dt.sort_values(330        "salary_ngay_cong_divided", ascending=False)331    # ----------------------# Thực thu332 333    orders = collect_data(334        'https://vietop.tech/api/get_data/orders').query("deleted_at.isnull()")335    lophoc = collect_data('https://vietop.tech/api/get_data/lophoc')336    hocvien = collect_data(337        'https://vietop.tech/api/get_data/hocvien').query("hv_id != 737 and deleted_at.isnull()")338    # hv đang họccd Au339    hocvien_danghoc = hocvien.merge(orders, on='hv_id')\340        .query("ketoan_active == 1")\341        .groupby('ketoan_coso', as_index=False).size().rename(columns={"size": "total_students"})342    hocvien_danghoc = rename_lop(hocvien_danghoc, 'ketoan_coso')343 344    @st.cache345    def plotly_chart(df, yvalue, xvalue, text, title, y_title, x_title, color=None, discrete_sequence=None, map=None):346        fig = px.bar(df, y=yvalue,347                     x=xvalue, text=text, color=color, color_discrete_sequence=discrete_sequence, color_discrete_map=map)348        fig.update_layout(349            title=title,350            yaxis_title=y_title,351            xaxis_title=x_title,352        )353        fig.update_traces(textposition='auto')354        return fig355 356    fig5 = plotly_chart(hocvien_danghoc, 'ketoan_coso', 'total_students', 'total_students',357                        'Tổng học viên đang học theo chi nhánh', 'Chi nhánh', 'Học viên')358 359    # Lop dang hoc360    lop_danghoc = lophoc.query(361        "(lop_status == 2 or lop_status == 4) and deleted_at.isnull()")\362        .groupby('lop_cn', as_index=False).size().rename(columns={"size": "total_classes"})363    lop_danghoc.lop_cn = lop_danghoc.lop_cn.replace(364        {1: "Hoa Cúc", 2: "Gò Dầu", 3: "Lê Quang Định", 5: "Lê Hồng Phong"})365 366    fig6 = plotly_chart(lop_danghoc, 'lop_cn', 'total_classes', 'total_classes',367                        "Tổng lớp đang học theo chi nhánh", 'Chi nhánh', 'Lớp học')368    ""369    # "------------------"370 371    # Define a function372    @st.cache373    def csv_reader(file):374        df = pd.read_csv(file)375        df = df.query("phanloai == 1")  # Filter lop chính376        df['date_created'] = pd.to_datetime(df['date_created'])377        return df378 379    @st.cache380    def collect_filtered_data(table, date_column='', start_time='', end_time=''):381        link = f"https://vietop.tech/api/get_data/{table}?column={date_column}&date_start={start_time}&date_end={end_time}"382        df = pd.DataFrame((requests.get(link).json()))383        df[date_column] = pd.to_datetime(df[date_column])384        return df385 386    df = csv_reader("diemdanh_details.csv")387    df1 = collect_filtered_data(table='diemdanh_details', date_column='date_created',388                                start_time='2023-01-01', end_time='2025-01-01')389    diemdanh_details = pd.concat([df, df1])390 391    thucthu = diemdanh_details.query(392        'date_created >= @ketoan_start_time and date_created <= @ketoan_end_time')\393        .groupby(['ketoan_id', 'lop_id', 'gv_id', 'date_created'], as_index=False)['giohoc'].sum()\394        .merge(orders, on='ketoan_id')\395        .merge(lophoc, on='lop_id')\396        .merge(users[['fullname', 'id']], left_on='gv_id', right_on='id')397    thucthu_all = diemdanh_details.query("date_created > '2023-01-01'")\398        .groupby(['ketoan_id', 'lop_id', 'gv_id', 'date_created'], as_index=False)['giohoc'].sum()\399        .merge(orders, on='ketoan_id')\400        .merge(lophoc, on='lop_id')\401        .merge(users[['fullname', 'id']], left_on='gv_id', right_on='id')402 403    thucthu['thucthu'] = thucthu['giohoc'] * thucthu['ketoan_tientrengio']404    thucthu['date_created_month'] = thucthu['date_created'].dt.month_name()405    thucthu_all['thucthu'] = thucthu_all['giohoc'] * \406        thucthu_all['ketoan_tientrengio']407    thucthu_all['date_created_month'] = thucthu_all['date_created'].dt.month_name()408 409    new_order = ['January', 'February', 'March', 'April', 'May', 'June',410                 'July', 'August', 'September', 'October', 'November', 'December']411    # Reorder months412    thucthu_all['date_created_month'] = pd.Categorical(413        thucthu_all['date_created_month'], categories=new_order, ordered=True)414    # Groupby giaovien415    thucthu_gv = thucthu.groupby(['id', 'fullname'], as_index=False)[416        'thucthu'].sum()417    # Groupby cn418    thucthu_cn = thucthu.groupby(['lop_cn'], as_index=False)['thucthu'].sum()419    thucthu_cn_rename = thucthu.groupby(420        ['lop_cn'], as_index=False)['thucthu'].sum()421    thucthu_cn_rename = rename_lop(thucthu_cn_rename, 'lop_cn')422 423    # Thực thu theo giáo viên và chi nhánh424    thucthu_details = thucthu.groupby(425        ['id', 'fullname', 'lop_cn'], as_index=False)['thucthu'].sum()426    # "_______________"427 428    @st.cache429    def thucthu_time(dataframe, column):430        df = dataframe.groupby(['lop_cn', column], as_index=False)[431            'thucthu'].sum()432        df.lop_cn = df.lop_cn.replace(433            {1: "Hoa Cúc", 2: "Gò Dầu", 3: "Lê Quang Định", 5: "Lê Hồng Phong"})434        return df435    thucthu_diemdanh_ngay = thucthu_time(thucthu, 'date_created')436    thucthu_diemdanh_ngay = thucthu_diemdanh_ngay.pivot(437        index='date_created', columns='lop_cn', values='thucthu')438    thucthu_diemdanh_month = thucthu_time(thucthu_all, 'date_created_month')439    # Thực thu điểm danh theo ngày và tháng440    fig9 = px.bar(thucthu_diemdanh_ngay, x=thucthu_diemdanh_ngay.index, y=thucthu_diemdanh_ngay.columns, barmode='stack',441                  color_discrete_sequence=['#07a203', '#ffc107', '#e700aa', '#2196f3'])442 443    fig10 = px.bar(thucthu_diemdanh_month, x="date_created_month",444                   y="thucthu", color="lop_cn", barmode="group", color_discrete_sequence=['#ffc107', '#07a203', '#2196f3', '#e700aa'], text="thucthu")445    # update the chart layout446    fig9.update_layout(title='Thực thu điểm danh theo ngày',447                       xaxis_title='Ngày', yaxis_title='Thực thu điểm danh')448    fig10.update_layout(title='Thực thu điểm danh theo tháng trong năm 2023',449                        xaxis_title='Tháng', yaxis_title='Thực thu', showlegend=True)450    fig10.update_traces(451        hovertemplate="Thực thu điểm danh: %{y:,.0f}<extra></extra>")452    # "_______________"453    fig1 = plotly_chart(thucthu_cn_rename, 'lop_cn', 'thucthu', thucthu_cn_rename['thucthu'].apply(lambda x: format(x, ',')),454                        "Thực thu theo chi nhánh", 'Chi nhánh', 'Thực thu')455 456    # "_______________" Tính tổng lương457 458    fixed_salary_cn = salary_gv_dt.groupby("lop_cn", as_index=False)[459        'salary_ngay_cong_divided'].sum()460    overtime_salary_cn = sal_diem_over_group_lop.groupby("lop_cn", as_index=False)[461        'salary_gio_cong'].sum()462    overtime_fixed_salary_cn = fixed_salary_cn.merge(463        overtime_salary_cn, on='lop_cn')464 465    overtime_fixed_salary_cn['fixed_overtime'] = overtime_fixed_salary_cn['salary_ngay_cong_divided'] + \466        overtime_fixed_salary_cn['salary_gio_cong']467 468    salary_thucthu = overtime_fixed_salary_cn.merge(thucthu_cn, on='lop_cn')469 470    # Create grand total471    salary_thucthu_grand_total = grand_total(salary_thucthu, 'lop_cn')472    # Create percent473    salary_thucthu_grand_total['percent'] = salary_thucthu_grand_total.fixed_overtime / \474        salary_thucthu_grand_total.thucthu * 100475    salary_thucthu_grand_total['percent'] = round(476        salary_thucthu_grand_total['percent'], 2)477    salary_thucthu_grand_total = rename_lop(478        salary_thucthu_grand_total, 'lop_cn')479 480    salary_thucthu_grand_total.columns = ['Chi nhánh', 'Tổng lương ngày công',481                                          'Tổng lương giờ công', 'Tổng lương giáo viên', 'Thực thu điểm danh', 'Tổng lương / thực thu']482    # "_______________"483    # Create a barplot for Tỷ lệ tổng lương / thực thu theo chi nhánh484    fig2 = plotly_chart(salary_thucthu_grand_total, 'Tổng lương / thực thu', 'Chi nhánh', salary_thucthu_grand_total["Tổng lương / thực thu"].apply(485        lambda x: '{:.2%}'.format(x/100)),486        "Tỷ lệ tổng lương / thực thu theo chi nhánh", 'Chi nhánh', 'Tổng lương / thực thu', color='Chi nhánh', map={487        'Hoa Cúc': '#ffc107',488        'Gò Dầu': '#07a203',489        'Lê Quang Định': '#2196f3',490        'Lê Hồng Phong': '#e700aa',491        'Grand total': 'white'492    })493    fig2.update_layout(font=dict(size=17), xaxis={494                       'categoryorder': 'total descending'})495 496    # "_______________"497    thucthu_hocvien_lop = thucthu_cn_rename.merge(498        hocvien_danghoc, left_on='lop_cn', right_on='ketoan_coso')\499        .merge(lop_danghoc, on='lop_cn')500    thucthu_hocvien_lop['thucthu_div_hocvien'] = round(501        thucthu_hocvien_lop['thucthu'] / thucthu_hocvien_lop['total_students'], 0)502    thucthu_hocvien_lop['thucthu_div_lophoc'] = round(503        thucthu_hocvien_lop['thucthu'] / thucthu_hocvien_lop['total_classes'], 0)504 505    # fig7 = plotly_chart(thucthu_hocvien_lop, 'lop_cn', 'thucthu_div_hocvien', thucthu_hocvien_lop['thucthu_div_hocvien'].apply(lambda x: format(x, ',')),506    #                     "Trung bình thực thu 1 học viên", 'Chi nhánh', 'Thực thu / học viên')507 508    # fig8 = plotly_chart(thucthu_hocvien_lop, 'lop_cn', 'thucthu_div_lophoc', thucthu_hocvien_lop['thucthu_div_lophoc'].apply(lambda x: format(x, ',')),509    #                     "Trung bình thực thu 1 lớp học", 'Chi nhánh', 'Thực thu / lớp học')510 511    # "_______________"512    overtime_salary_cn_gv = sal_diem_over_group_lop.groupby(513        ['id_gg', 'Họ và tên', "lop_cn", "working_status_x"], as_index=False)['salary_gio_cong'].sum()514    df = overtime_salary_cn_gv.merge(515        salary_gv_dt, on=['lop_cn', 'Họ và tên', 'id_gg'], how='outer')516    df.fillna(0, inplace=True)517    df['fixed_overtime'] = df['salary_gio_cong'] + \518        df['salary_ngay_cong_divided']519    gv_thucthu_cs = df.merge(thucthu_cn, on='lop_cn')520    gv_thucthu_cs['percent'] = round(gv_thucthu_cs['fixed_overtime'] /521                                     gv_thucthu_cs['thucthu'] * 100, 2)522    # "_______________"523    # salary_merge = st.session_state['salary_merge']524    gv_thucthu_gv = gv_thucthu_cs.groupby(['id_gg', 'Họ và tên'], as_index=False)['fixed_overtime'].sum()\525        .merge(thucthu_gv, left_on='id_gg', right_on='id', how='left')526    gv_thucthu_gv['percent'] = round(gv_thucthu_gv['fixed_overtime'] /527                                     gv_thucthu_gv['thucthu'] * 100, 2)528 529    gv_thucthu_gv = gv_thucthu_gv.merge(salary, left_on='id', right_on='id_gg')530 531    # Fulltime532    df = gv_thucthu_gv533    df1 = df[df["working_status"] == "Fulltime"].sort_values(534        by="percent", ascending=True)535    df1['fullname'] = df1['fullname'] + " (" + df['level'] + ")"536 537    # Parttime538    df2 = df[df["working_status"] == "Partime"].sort_values(539        by="percent", ascending=True)540    df2['fullname'] = df2['fullname'] + " (" + df['level'] + ")"541    # Plotly graphs542 543    fig3 = plotly_chart(df1.sort_values(544        "percent", ascending=True), 'fullname', 'percent', df1["percent"].apply(545        lambda x: '{:.2%}'.format(x/100)),546        "Fulltime - Tỷ lệ tổng lương / thực thu", '', 'Tỷ lệ')547    fig3.update_layout(548        height=1000,  # set the height of the plot to 600 pixels549        width=800)550 551 552# Plotly graphs553    fig3_1 = plotly_chart(df2.sort_values(554        "percent", ascending=True), 'fullname', 'percent', df2["percent"].apply(555        lambda x: '{:.2%}'.format(x/100)),556        "Parttime - Tỷ lệ tổng lương / thực thu", '', 'Tỷ lệ')557    fig3_1.update_layout(558        height=1000,  # set the height of the plot to 600 pixels559        width=800)560 561    # "_______________" thực thu chuyển phí562    hv_status = collect_data('https://vietop.tech/api/get_data/hv_status')563    # Filter orders564    orders_chuyenphi = orders.query("ketoan_active == 5")[["ketoan_id", "hv_id", "ketoan_details", "ketoan_coso", "ketoan_sogio", "ketoan_price",565                                                           "ketoan_tientrengio", "remaining_time", "kh_id"]]566    # Filter hv_status567    hv_status_chuyenphi = hv_status[['ketoan_id', 'status', 'lop_id', 'note', 'is_price', 'created_at']]\568        .query("status ==7")569    # Filter hocvien570    hocvien_chuyenphi = hocvien[['hv_id', 'hv_fullname']]571    # Merge hv_status and orders572    chuyenphi = hv_status_chuyenphi.merge(573        orders_chuyenphi, on='ketoan_id', how='left')574    # Merge hocvien_chuyephi575    chuyenphi = chuyenphi.merge(hocvien_chuyenphi, on='hv_id', how='left')576    chuyenphi = chuyenphi[['created_at', 'hv_fullname',577                           'ketoan_coso', 'note', 'is_price']]578    # Add column Phi Chuyen579    chuyenphi['phí chuyển'] = chuyenphi.is_price * 0.1580    # Add column Tien con lai sau phi581    chuyenphi['thực thu chuyển phí'] = chuyenphi.is_price - \582        chuyenphi['phí chuyển']583    # Change data type584    chuyenphi = chuyenphi.astype(585        {'created_at': 'datetime64[ns]'})586    # Sort587    chuyenphi = chuyenphi.sort_values(by='created_at', ascending=False)588    chuyenphi = chuyenphi.query(589        "created_at >= @ketoan_start_time and created_at <= @ketoan_end_time")590    # Rename columns591    # chuyenphi.columns = [["created_at", "Họ tên", "ketoan_coso", "Ghi chú", "Học phí chuyển", "Phí chuyển", "Còn lại sau phí"]]592    chuyenphi = chuyenphi.groupby('ketoan_coso', as_index=False)[593        'thực thu chuyển phí'].sum()594 595    chuyenphi = rename_lop(chuyenphi, 'ketoan_coso')596 597    # "_______________" Thực thu kết thúc598    # Filter ketthuc599    orders_ketthuc = orders.query("ketoan_active == 5 and deleted_at.isnull()")600    # Merge orders_ketthuc and diemdanh_details601    df = diemdanh_details[['ketoan_id', 'giohoc']]\602        .merge(orders_ketthuc, on='ketoan_id', how='right').groupby(603        ['ketoan_id', 'ketoan_coso', 'remaining_time', 'ketoan_tientrengio', 'date_end'], as_index=False).giohoc.sum()604    # Add 2 more columns605    df['gio_con_lai'] = df.remaining_time - df.giohoc606    df['thực thu kết thúc'] = df.gio_con_lai * df.ketoan_tientrengio607    # Convert to datetime608    df['date_end'] = pd.to_datetime(df['date_end'])609    # Filter gioconlai > 0 and time610    thucthu_ketthuc = df.query("gio_con_lai > 0")\611        .query("date_end >= @ketoan_start_time and date_end <= @ketoan_end_time")612    thucthu_ketthuc = thucthu_ketthuc.merge(613        orders[['hv_id', 'ketoan_id']], on='ketoan_id')614    thucthu_ketthuc = thucthu_ketthuc.groupby("ketoan_coso", as_index=False)[615        'thực thu kết thúc'].sum()616    thucthu_ketthuc = rename_lop(thucthu_ketthuc, 'ketoan_coso')617 618    # "_______________"619 620    overtime_salary = sal_diem_over_group.query('working_status_x != "Ngoài giờ"')\621        .merge(salary[['Họ và tên', 'working_status']], left_on='Họ và tên', right_on='Họ và tên')622    overtime_salary['out_div_total'] = overtime_salary['salary_gio_cong'] / \623        (overtime_salary['salary_ngay_cong'] +624         overtime_salary['salary_gio_cong'])625    overtime_salary = overtime_salary[[626        'Họ và tên', 'salary_ngay_cong', 'salary_gio_cong', 'out_div_total']]627    overtime_salary['out_div_total'] = round(628        overtime_salary['out_div_total'] * 100, 2)629    overtime_salary_fulltime = overtime_salary.query("salary_ngay_cong != 0")630 631    # "_______________" thucthu điểm danh and chuyen phi632    thucthu_hocvien_lop = thucthu_hocvien_lop.merge(633        chuyenphi, left_on='ketoan_coso', right_on='ketoan_coso', how='left')\634        .merge(thucthu_ketthuc, left_on='ketoan_coso', right_on='ketoan_coso')635    # Renam thucthu => thuc thu diem danh636    thucthu_hocvien_lop = thucthu_hocvien_lop.rename(637        columns={'thucthu': "thực thu điểm danh"})638    # Fillna with 0639    thucthu_hocvien_lop.fillna(0, inplace=True)640    # Add all thucthu641    thucthu_hocvien_lop['tổng thực thu'] = thucthu_hocvien_lop['thực thu chuyển phí'] + \642        thucthu_hocvien_lop['thực thu kết thúc'] + \643        thucthu_hocvien_lop['thực thu điểm danh']644    # Add ty lệ thực thu645    thucthu_hocvien_lop['tỷ trọng tổng thực thu'] = thucthu_hocvien_lop['tổng thực thu'].apply(646        lambda x: round(x/thucthu_hocvien_lop['tổng thực thu'].sum()*100, 2))647    # create a new row with the sum of each numerical column648    totals = thucthu_hocvien_lop.select_dtypes(include=[float, int]).sum()649    totals["lop_cn"] = "Grand total"650    # append the new row to the dataframe651    thucthu_hocvien_lop = thucthu_hocvien_lop.append(totals, ignore_index=True)652    # Add % in tỷ trọng tổng thực thu653    thucthu_hocvien_lop["tỷ trọng tổng thực thu"] = thucthu_hocvien_lop["tỷ trọng tổng thực thu"].apply(654        lambda x: '{:.2%}'.format(x/100))655    salary_thucthu_grand_total['Tổng lương / thực thu'] = salary_thucthu_grand_total['Tổng lương / thực thu'].apply(656        lambda x: '{:.2%}'.format(x/100))657 658    # define a function659    @ st.cache660    def thousands_divider(df, col):661        df[col] = df[col].apply(662            lambda x: '{:,.0f}'.format(x))663        return df664    thucthu_hocvien_lop = thousands_divider(665        thucthu_hocvien_lop, 'tổng thực thu')666    thucthu_hocvien_lop = thousands_divider(667        thucthu_hocvien_lop, 'thực thu điểm danh')668    thucthu_hocvien_lop = thousands_divider(669        thucthu_hocvien_lop, 'thực thu chuyển phí')670    thucthu_hocvien_lop = thousands_divider(671        thucthu_hocvien_lop, 'thực thu kết thúc')672    thucthu_hocvien_lop = thucthu_hocvien_lop.set_index("lop_cn")673 674    thucthu_hocvien_lop.index.names = ['Chi nhánh']675    # Show tables676    st.plotly_chart(fig2, use_container_width=True)677    st.subheader("Thưc thu theo chi nhánh")678    st.dataframe(thucthu_hocvien_lop.drop(["ketoan_coso", "total_students", "total_classes", "thucthu_div_hocvien", "thucthu_div_lophoc"],679                                          axis=1).style.background_gradient().set_precision(0), use_container_width=True)680    # Show Chi nhanh by 2 columns681    st.plotly_chart(fig10, use_container_width=True)682    st.plotly_chart(fig9, use_container_width=True)683 684    # left_column, right_column = st.columns([1, 2])685    # left_column.plotly_chart(fig10, use_container_width=True)686    # right_column.plotly_chart(fig9, use_container_width=True)687    # left_column, right_column = st.columns(2)688    # left_column.plotly_chart(fig7, use_container_width=True)689    # right_column.plotly_chart(fig8, use_container_width=True)690 691    # left_column, right_column = st.columns(2)692    # left_column.plotly_chart(fig5, use_container_width=True)693    # right_column.plotly_chart(fig6, use_container_width=True)694 695    # left_column, right_column = st.columns(2)696    # left_column.plotly_chart(fig1, use_container_width=True)697    # right_column.plotly_chart(fig2, use_container_width=True)698 699    left_column, right_column = st.columns(2)700    left_column.plotly_chart(fig3, use_container_width=True)701    right_column.plotly_chart(fig3_1, use_container_width=True)702 703    ""704 705    fig4 = plotly_chart(overtime_salary_fulltime[['Họ và tên', 'out_div_total']].sort_values(706        "out_div_total", ascending=True), "Họ và tên", 'out_div_total', 'out_div_total',707        "Tỷ lệ lương ngoài giờ / trong giờ của giáo viên fulltime", '', 'Tỷ lệ')708    fig4.update_layout(height=800, width=800)709    st.plotly_chart(fig4)710