import streamlit as st
import requests
import plotly.express as px
import pandas as pd
from datetime import datetime, timedelta
from pathlib import Path
import pickle
import streamlit_authenticator as stauth
import numpy as np
import calendar
# names = ["Phạm Tấn Thành", "Phạm Minh Tâm", "Vận hành"]
# usernames = ["thanhpham", "tampham", "vietopvanhanh"]
# passwords = ['thanhpham0704', 'tampham1234', 'vanhanh2023']
# hashed_passwords = stauth.Hasher(passwords).generate()
# file_path = Path(__file__).parent / "hashed_pw.pkl"
# with file_path.open("wb") as file:
# pickle.dump(hashed_passwords, file)
page_title = "Lương và thực thu"
page_icon = ":chart_with_upwards_trend:"
layout = "wide"
st.set_page_config(page_title=page_title, page_icon=page_icon, layout=layout)
# ----------------------------------------
names = ["Phạm Tấn Thành", "Phạm Minh Tâm", "Vận hành"]
usernames = ["thanhpham", "tampham", "vietopvanhanh"]
# Load hashed password
file_path = Path(__file__).parent / 'hashed_pw.pkl'
with file_path.open("rb") as file:
hashed_passwords = pickle.load(file)
authenticator = stauth.Authenticate(names, usernames, hashed_passwords,
"sales_dashboard", "abcdef", cookie_expiry_days=1)
name, authentication_status, username = authenticator.login("Login", "main")
if authentication_status == False:
st.error("Username/password is incorrect")
if authentication_status == None:
st.warning("Please enter your username and password")
if authentication_status:
authenticator.logout("logout", "main")
# Add CSS styling to position the button on the top right corner of the page
st.markdown(
"""
""",
unsafe_allow_html=True
)
st.title(page_title + " " + page_icon)
#----------------------#
# Filter
now = datetime.now()
DEFAULT_START_DATE = datetime(now.year, now.month, 1)
DEFAULT_END_DATE = datetime(now.year, now.month, 1) + timedelta(days=32)
DEFAULT_END_DATE = DEFAULT_END_DATE.replace(day=1) - timedelta(days=1)
# Create a form to get the date range filters
with st.form(key='date_filter_form'):
col1, col2 = st.columns(2)
ketoan_start_time = col1.date_input(
"Select start date", value=DEFAULT_START_DATE)
ketoan_end_time = col2.date_input(
"Select end date", value=DEFAULT_END_DATE)
submit_button = st.form_submit_button(
label='Filter')
# the duration between 2 dates exclude Sunday
duration = sum(1 for i in range((ketoan_end_time - ketoan_start_time).days)
if (ketoan_start_time + timedelta(i)).weekday() != 6)
# the number of days in a month exclude Sunday
days_in_month = calendar.monthrange(
ketoan_start_time.year, ketoan_start_time.month)[1]
sundays_in_month = sum(1 for day in range(1, days_in_month + 1) if datetime(
ketoan_start_time.year, ketoan_start_time.month, day).weekday() == 6)
days_excluding_sundays = days_in_month - sundays_in_month
#----------------------#
@st.cache(ttl = timedelta(days = 1))
def collect_data(link):
return(pd.DataFrame((requests.get(link).json())))
@st.cache
def rename_lop(dataframe, column_name):
dataframe[column_name] = dataframe[column_name].replace(
{1: "Hoa Cúc", 2: "Gò Dầu", 3: "Lê Quang Định", 5: "Lê Hồng Phong"})
return dataframe
@st.cache
def grand_total(dataframe, column):
# create a new row with the sum of each numerical column
totals = dataframe.select_dtypes(include=[float, int]).sum()
totals[column] = "Grand total"
# append the new row to the dataframe
dataframe = dataframe.append(totals, ignore_index=True)
return dataframe
# "---------------" Thông tin lương giáo viên
users = collect_data('https://vietop.tech/api/get_data/users')
# Thong tin luong
import gspread
sa = gspread.service_account(
filename='taichinh-380507-b8f84e9ee681.json')
sh = sa.open("Nhân sự")
worksheet = sh.worksheet("Giáo viên")
salary = pd.DataFrame(worksheet.get_all_records())
salary = salary.replace("", np.nan).dropna(subset='Mã giáo viên')
salary = salary.replace('\.', '', regex=True)
salary = salary.astype({'Lương theo hợp đông': 'float', 'Thâm niên': 'float',
'Chức danh': "float", 'Tổng lương': 'float', 'date_affected': 'datetime64[ns]'})
# salary.info()
# salary = salary.sort_values("date_affected", ascending=False)\
# .drop_duplicates(subset='id_gg')
salary = salary.sort_values("date_affected", ascending=False)\
.query("date_affected <= @ketoan_end_time")\
.drop_duplicates("id_gg")
salary.fillna(0, inplace=True)
# Thong tin luong
salary['salary_ngay_cong'] = round(
salary['Tổng lương'] * duration/days_excluding_sundays, 0)
salary.fillna(0, inplace=True)
salary.drop(['STT', 'Mã giáo viên', 'Tổng lương'], axis=1, inplace=True)
salary.rename(columns={"Lương theo hợp đông": "hopdong", "Thâm niên": "thamnien",
'Chức danh': 'chucdanh', 'Ngày': 'ngay', 'Tối': 'toi', 'Cuối tuần': 'cuoituan',
'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',
'Tổng ngày công thực tế': 'ngaycong_real_total'}, inplace=True)
# "------------------"
gv_diemdanh = collect_data('https://vietop.tech/api/get_data/diemdanh')
gv_diemdanh['date_created'] = pd.to_datetime(gv_diemdanh['date_created'])
gv_diemdanh = gv_diemdanh.query(
"date_created >= @ketoan_start_time and date_created <= @ketoan_end_time")
# Ca hoc table
cahoc = {'cahoc': ['ca1', 'ca2', 'ca3', 'ca4', 'ca5', 'ca6'],
'start_time': ['08:30:00', '10:30:00', '13:30:00', '15:30:00', '18:00:00', '19:45:00'],
'end_time': ['10:30:00', '12:30:00', '15:30:00', '17:30:00', '19:45:00', '21:30:00']}
cahoc = pd.DataFrame(cahoc)
# --------------- GET DATA FROM API
sh = sa.open("Nhân sự")
worksheet = sh.worksheet("Overtime")
offline_overtime = pd.DataFrame(worksheet.get_all_records())
offline_overtime['date_affected'] = pd.to_datetime(
offline_overtime['date_affected'])
offline_overtime = offline_overtime.sort_values("date_affected", ascending=False)\
.drop_duplicates(subset='Họ và tên')
offline_overtime.drop("date_affected", axis=1, inplace=True)
# Define the start and end times of the day
start_time = pd.to_datetime('2000-01-01 06:00:00').time()
end_time = pd.to_datetime('2000-01-01 18:00:00').time()
ca1 = pd.to_datetime('2000-01-01 06:30:00').time()
ca2 = pd.to_datetime('2000-01-01 10:30:00').time()
ca3 = pd.to_datetime('2000-01-01 13:30:00').time()
ca4 = pd.to_datetime('2000-01-01 15:30:00').time()
ca5 = pd.to_datetime('2000-01-01 18:00:00').time()
# tren office khong cos 19:45
ca6 = pd.to_datetime('2000-01-01 19:30:00').time()
# Create a function that takes a time and returns "Morning" or "Evening" depending on whether the time falls within the specified range
@st.cache
def time_of_day(time):
if (time >= start_time) & (time < end_time):
return "Sáng"
else:
return "Tối"
# Create a function that takes a time and returns "Morning" or "Evening" depending on whether the time falls within the specified range
@st.cache
def day_of_week(day):
if (day == 5) | (day == 6):
return "weekend"
else:
return "weekdays"
# Create a function that takes a time and returns "Morning" or "Evening" depending on whether the time falls within the specified range
@st.cache
def cahoc_converter(ca):
if (ca >= ca1) & (ca < ca2):
return 1
elif (ca >= ca2) & (ca < ca3):
return 2
elif (ca >= ca3) & (ca < ca4):
return 3
elif (ca >= ca4) & (ca < ca5):
return 4
elif (ca >= ca5) & (ca < ca6):
return 5
elif (ca >= ca6):
return 6
# "---------------" Bảng lương giáo viên
overtime_melt = offline_overtime.melt(
id_vars=['id_gg', 'Họ và tên', 'WORKING_STATUS'], var_name='Column Name', value_name='overtime_status')
overtime_melt['day_of_week'], overtime_melt['cahoc'] = overtime_melt['Column Name'].str.split(
'Ca ', 1).str
overtime_melt['day_of_week'].replace(
{'T2': 0, 'T3': 1, 'T4': 2, 'T5': 3, 'T6': 4, 'T7': 5, 'T8': 6}, inplace=True)
overtime_melt['overtime_status'].replace(
{0: 'in', 'a': 'out'}, inplace=True)
# Convert 5 and 6 into "Cuối tuần"
overtime_melt['weekend_or_not'] = overtime_melt['day_of_week'].apply(
day_of_week)
# Convert ca into Sáng or Tối
overtime_melt['time_of_day'] = ['Sáng' if i in [
'1', '2', '3', '4'] else 'Tối' for i in overtime_melt['cahoc']]
# Drop unnecessary columns
overtime_melt.drop(
['Column Name'], axis=1, inplace=True)
overtime_melt['cahoc'] = overtime_melt['cahoc'].astype(int)
overtime_melt.rename(
columns={'WORKING_STATUS': 'working_status'}, inplace=True)
# "---------------" Lương overtime của giáo viên
lophoc = collect_data('https://vietop.tech/api/get_data/lophoc')
diemdanh = gv_diemdanh.merge(users[['fullname', 'id']], left_on='giaovien', right_on='id', how='inner')\
.sort_values("created_at", ascending=False)
# 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)
diemdanh = diemdanh[['lop_id', 'sogio', 'cahoc', 'phanloai',
'date_created', 'created_by', 'id',
'updated_by', 'created_at', 'fullname']]
# Convert the date column to datetime
diemdanh['created_at'] = pd.to_datetime(diemdanh['created_at'])
# Extract the time component of each datetime value
diemdanh['created_at_time'] = diemdanh['created_at'].dt.time
# Create a new column that indicates the day of the week
diemdanh['day_of_week'] = diemdanh['created_at'].dt.dayofweek
# Create a boolean mask that indicates whether each time is within the specified time frame
diemdanh["time_of_day"] = diemdanh['created_at_time'].apply(time_of_day)
# Convert 5 and 6 into "Cuối tuần"
diemdanh['weekend_or_not'] = diemdanh["day_of_week"].apply(day_of_week)
diemdanh = diemdanh[['id', 'fullname', 'sogio', 'cahoc', 'phanloai',
'created_at', 'day_of_week', 'created_at_time', 'time_of_day', 'weekend_or_not', 'date_created',
'lop_id']]
diemdanh['cahoc'] = diemdanh['created_at_time'].apply(cahoc_converter)
# Sum giohoc according to fullname, time of day and weekend or not
diemdanh_sum_giohoc = diemdanh.groupby(
["id", "fullname", "cahoc", 'phanloai', 'day_of_week', "time_of_day", "weekend_or_not", 'lop_id'], as_index=False)['sogio'].sum()
# Get lopcn from lophoc
diemdanh_lop_cn = diemdanh_sum_giohoc.merge(
lophoc[['lop_id', 'lop_cn']], on='lop_id')
# "---------------"
sal_diem = diemdanh_lop_cn.merge(
salary, left_on='id', right_on='id_gg')
# Merge diemdanh and overtime
sal_diem_over = sal_diem\
.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')
# Drop duplicates
sal_diem_over.drop_duplicates(inplace=True)
# Fill na
sal_diem_over.fillna(0, inplace=True)
# Calculate luong ngay cong
empty = []
for index, value in sal_diem_over.iterrows():
if value['weekend_or_not'] == 'weekend' and value['overtime_status'] == 'out':
empty.append(value['cuoituan'] * value['sogio'])
elif value['time_of_day'] == 'Tối' and value['overtime_status'] == 'out':
empty.append(value['toi'] * value['sogio'])
elif value['time_of_day'] == 'Sáng' and value['overtime_status'] == 'out':
empty.append(value['ngay'] * value['sogio'])
elif value['phanloai'] == 0:
empty.append(value['trogiang'] * value['sogio'])
else:
empty.append(0)
sal_diem_over['salary_gio_cong'] = empty
# Slicing columns
sal_diem_over = sal_diem_over.loc[:, ['lop_cn', 'id_gg', 'Họ và tên', 'working_status_x', 'cahoc', 'phanloai', 'overtime_status',
'time_of_day', 'day_of_week', 'weekend_or_not', 'sogio',
'ngay', 'toi', 'cuoituan', 'trogiang', 'salary_gio_cong', 'salary_ngay_cong']]
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()\
.query("overtime_status == 'out'")
# Sum luong_gio_cong according to fullname
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()\
.query("overtime_status == 'out'").sort_values("salary_gio_cong", ascending=False)
sal_diem_over_details = sal_diem_over.drop('salary_ngay_cong', axis=1)\
.query("overtime_status == 'out'")\
# ----------------------# Phân phối lương cứng theo chi nhánh
df = sal_diem_over.groupby(['lop_cn', 'id_gg', 'Họ và tên', 'working_status_x', 'overtime_status',
'salary_ngay_cong'], as_index=False)['sogio', 'salary_gio_cong'].sum()
df = df.query('overtime_status == "in"')
df_sum = df.groupby('Họ và tên', as_index=False)['sogio'].sum()
df_proportion = df_sum.merge(df, on='Họ và tên')
df_proportion['proportion_sogio'] = df_proportion['sogio_y'] / \
df_proportion['sogio_x']
df_proportion['salary_ngay_cong_divided'] = df_proportion['proportion_sogio'] * \
df_proportion['salary_ngay_cong']
# Giáo viên ngoại trừ phòng đào tạo
df_proportion_nodaotao = df_proportion[~df_proportion['Họ và tên'].isin(
['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'])]
# Subset
df_proportion_nodaotao = df_proportion_nodaotao[[
'id_gg', 'Họ và tên', 'lop_cn', 'salary_ngay_cong_divided']]
# Riêng phòng đào tạo
df_proportion_daotao = salary[salary['Họ và tên'].isin(
['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'])]
df_proportion_daotao['1'] = 0.26 * df_proportion_daotao['salary_ngay_cong']
df_proportion_daotao['2'] = 0.26 * df_proportion_daotao['salary_ngay_cong']
df_proportion_daotao['3'] = 0.18 * df_proportion_daotao['salary_ngay_cong']
df_proportion_daotao['5'] = 0.30 * df_proportion_daotao['salary_ngay_cong']
# Subset
df_proportion_daotao = df_proportion_daotao.loc[:, [
'id_gg', 'Họ và tên', '1', '2', '3', '5']]
# Lương đào tạo sau khi phân phối
df_proportion_daotao = pd.melt(df_proportion_daotao, id_vars=[
'id_gg', 'Họ và tên'], var_name='lop_cn', value_name='salary_ngay_cong_divided')
df_proportion_daotao['lop_cn'] = df_proportion_daotao['lop_cn'].astype(
'int64')
# Concat luong đào tạo and lương giáo viên
salary_gv_dt = pd.concat([df_proportion_daotao, df_proportion_nodaotao])
salary_gv_dt['salary_ngay_cong_divided'] = round(
salary_gv_dt['salary_ngay_cong_divided'], 2)
salary_gv_dt = salary_gv_dt.sort_values(
"salary_ngay_cong_divided", ascending=False)
# ----------------------# Thực thu
orders = collect_data(
'https://vietop.tech/api/get_data/orders').query("deleted_at.isnull()")
lophoc = collect_data('https://vietop.tech/api/get_data/lophoc')
hocvien = collect_data(
'https://vietop.tech/api/get_data/hocvien').query("hv_id != 737 and deleted_at.isnull()")
# hv đang họccd Au
hocvien_danghoc = hocvien.merge(orders, on='hv_id')\
.query("ketoan_active == 1")\
.groupby('ketoan_coso', as_index=False).size().rename(columns={"size": "total_students"})
hocvien_danghoc = rename_lop(hocvien_danghoc, 'ketoan_coso')
@st.cache
def plotly_chart(df, yvalue, xvalue, text, title, y_title, x_title, color=None, discrete_sequence=None, map=None):
fig = px.bar(df, y=yvalue,
x=xvalue, text=text, color=color, color_discrete_sequence=discrete_sequence, color_discrete_map=map)
fig.update_layout(
title=title,
yaxis_title=y_title,
xaxis_title=x_title,
)
fig.update_traces(textposition='auto')
return fig
fig5 = plotly_chart(hocvien_danghoc, 'ketoan_coso', 'total_students', 'total_students',
'Tổng học viên đang học theo chi nhánh', 'Chi nhánh', 'Học viên')
# Lop dang hoc
lop_danghoc = lophoc.query(
"(lop_status == 2 or lop_status == 4) and deleted_at.isnull()")\
.groupby('lop_cn', as_index=False).size().rename(columns={"size": "total_classes"})
lop_danghoc.lop_cn = lop_danghoc.lop_cn.replace(
{1: "Hoa Cúc", 2: "Gò Dầu", 3: "Lê Quang Định", 5: "Lê Hồng Phong"})
fig6 = plotly_chart(lop_danghoc, 'lop_cn', 'total_classes', 'total_classes',
"Tổng lớp đang học theo chi nhánh", 'Chi nhánh', 'Lớp học')
""
# "------------------"
# Define a function
@st.cache
def csv_reader(file):
df = pd.read_csv(file)
df = df.query("phanloai == 1") # Filter lop chính
df['date_created'] = pd.to_datetime(df['date_created'])
return df
@st.cache
def collect_filtered_data(table, date_column='', start_time='', end_time=''):
link = f"https://vietop.tech/api/get_data/{table}?column={date_column}&date_start={start_time}&date_end={end_time}"
df = pd.DataFrame((requests.get(link).json()))
df[date_column] = pd.to_datetime(df[date_column])
return df
df = csv_reader("diemdanh_details.csv")
df1 = collect_filtered_data(table='diemdanh_details', date_column='date_created',
start_time='2023-01-01', end_time='2025-01-01')
diemdanh_details = pd.concat([df, df1])
thucthu = diemdanh_details.query(
'date_created >= @ketoan_start_time and date_created <= @ketoan_end_time')\
.groupby(['ketoan_id', 'lop_id', 'gv_id', 'date_created'], as_index=False)['giohoc'].sum()\
.merge(orders, on='ketoan_id')\
.merge(lophoc, on='lop_id')\
.merge(users[['fullname', 'id']], left_on='gv_id', right_on='id')
thucthu_all = diemdanh_details.query("date_created > '2023-01-01'")\
.groupby(['ketoan_id', 'lop_id', 'gv_id', 'date_created'], as_index=False)['giohoc'].sum()\
.merge(orders, on='ketoan_id')\
.merge(lophoc, on='lop_id')\
.merge(users[['fullname', 'id']], left_on='gv_id', right_on='id')
thucthu['thucthu'] = thucthu['giohoc'] * thucthu['ketoan_tientrengio']
thucthu['date_created_month'] = thucthu['date_created'].dt.month_name()
thucthu_all['thucthu'] = thucthu_all['giohoc'] * \
thucthu_all['ketoan_tientrengio']
thucthu_all['date_created_month'] = thucthu_all['date_created'].dt.month_name()
new_order = ['January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December']
# Reorder months
thucthu_all['date_created_month'] = pd.Categorical(
thucthu_all['date_created_month'], categories=new_order, ordered=True)
# Groupby giaovien
thucthu_gv = thucthu.groupby(['id', 'fullname'], as_index=False)[
'thucthu'].sum()
# Groupby cn
thucthu_cn = thucthu.groupby(['lop_cn'], as_index=False)['thucthu'].sum()
thucthu_cn_rename = thucthu.groupby(
['lop_cn'], as_index=False)['thucthu'].sum()
thucthu_cn_rename = rename_lop(thucthu_cn_rename, 'lop_cn')
# Thực thu theo giáo viên và chi nhánh
thucthu_details = thucthu.groupby(
['id', 'fullname', 'lop_cn'], as_index=False)['thucthu'].sum()
# "_______________"
@st.cache
def thucthu_time(dataframe, column):
df = dataframe.groupby(['lop_cn', column], as_index=False)[
'thucthu'].sum()
df.lop_cn = df.lop_cn.replace(
{1: "Hoa Cúc", 2: "Gò Dầu", 3: "Lê Quang Định", 5: "Lê Hồng Phong"})
return df
thucthu_diemdanh_ngay = thucthu_time(thucthu, 'date_created')
thucthu_diemdanh_ngay = thucthu_diemdanh_ngay.pivot(
index='date_created', columns='lop_cn', values='thucthu')
thucthu_diemdanh_month = thucthu_time(thucthu_all, 'date_created_month')
# Thực thu điểm danh theo ngày và tháng
fig9 = px.bar(thucthu_diemdanh_ngay, x=thucthu_diemdanh_ngay.index, y=thucthu_diemdanh_ngay.columns, barmode='stack',
color_discrete_sequence=['#07a203', '#ffc107', '#e700aa', '#2196f3'])
fig10 = px.bar(thucthu_diemdanh_month, x="date_created_month",
y="thucthu", color="lop_cn", barmode="group", color_discrete_sequence=['#ffc107', '#07a203', '#2196f3', '#e700aa'], text="thucthu")
# update the chart layout
fig9.update_layout(title='Thực thu điểm danh theo ngày',
xaxis_title='Ngày', yaxis_title='Thực thu điểm danh')
fig10.update_layout(title='Thực thu điểm danh theo tháng trong năm 2023',
xaxis_title='Tháng', yaxis_title='Thực thu', showlegend=True)
fig10.update_traces(
hovertemplate="Thực thu điểm danh: %{y:,.0f}")
# "_______________"
fig1 = plotly_chart(thucthu_cn_rename, 'lop_cn', 'thucthu', thucthu_cn_rename['thucthu'].apply(lambda x: format(x, ',')),
"Thực thu theo chi nhánh", 'Chi nhánh', 'Thực thu')
# "_______________" Tính tổng lương
fixed_salary_cn = salary_gv_dt.groupby("lop_cn", as_index=False)[
'salary_ngay_cong_divided'].sum()
overtime_salary_cn = sal_diem_over_group_lop.groupby("lop_cn", as_index=False)[
'salary_gio_cong'].sum()
overtime_fixed_salary_cn = fixed_salary_cn.merge(
overtime_salary_cn, on='lop_cn')
overtime_fixed_salary_cn['fixed_overtime'] = overtime_fixed_salary_cn['salary_ngay_cong_divided'] + \
overtime_fixed_salary_cn['salary_gio_cong']
salary_thucthu = overtime_fixed_salary_cn.merge(thucthu_cn, on='lop_cn')
# Create grand total
salary_thucthu_grand_total = grand_total(salary_thucthu, 'lop_cn')
# Create percent
salary_thucthu_grand_total['percent'] = salary_thucthu_grand_total.fixed_overtime / \
salary_thucthu_grand_total.thucthu * 100
salary_thucthu_grand_total['percent'] = round(
salary_thucthu_grand_total['percent'], 2)
salary_thucthu_grand_total = rename_lop(
salary_thucthu_grand_total, 'lop_cn')
salary_thucthu_grand_total.columns = ['Chi nhánh', 'Tổng lương ngày công',
'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']
# "_______________"
# Create a barplot for Tỷ lệ tổng lương / thực thu theo chi nhánh
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(
lambda x: '{:.2%}'.format(x/100)),
"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={
'Hoa Cúc': '#ffc107',
'Gò Dầu': '#07a203',
'Lê Quang Định': '#2196f3',
'Lê Hồng Phong': '#e700aa',
'Grand total': 'white'
})
fig2.update_layout(font=dict(size=17), xaxis={
'categoryorder': 'total descending'})
# "_______________"
thucthu_hocvien_lop = thucthu_cn_rename.merge(
hocvien_danghoc, left_on='lop_cn', right_on='ketoan_coso')\
.merge(lop_danghoc, on='lop_cn')
thucthu_hocvien_lop['thucthu_div_hocvien'] = round(
thucthu_hocvien_lop['thucthu'] / thucthu_hocvien_lop['total_students'], 0)
thucthu_hocvien_lop['thucthu_div_lophoc'] = round(
thucthu_hocvien_lop['thucthu'] / thucthu_hocvien_lop['total_classes'], 0)
# fig7 = plotly_chart(thucthu_hocvien_lop, 'lop_cn', 'thucthu_div_hocvien', thucthu_hocvien_lop['thucthu_div_hocvien'].apply(lambda x: format(x, ',')),
# "Trung bình thực thu 1 học viên", 'Chi nhánh', 'Thực thu / học viên')
# fig8 = plotly_chart(thucthu_hocvien_lop, 'lop_cn', 'thucthu_div_lophoc', thucthu_hocvien_lop['thucthu_div_lophoc'].apply(lambda x: format(x, ',')),
# "Trung bình thực thu 1 lớp học", 'Chi nhánh', 'Thực thu / lớp học')
# "_______________"
overtime_salary_cn_gv = sal_diem_over_group_lop.groupby(
['id_gg', 'Họ và tên', "lop_cn", "working_status_x"], as_index=False)['salary_gio_cong'].sum()
df = overtime_salary_cn_gv.merge(
salary_gv_dt, on=['lop_cn', 'Họ và tên', 'id_gg'], how='outer')
df.fillna(0, inplace=True)
df['fixed_overtime'] = df['salary_gio_cong'] + \
df['salary_ngay_cong_divided']
gv_thucthu_cs = df.merge(thucthu_cn, on='lop_cn')
gv_thucthu_cs['percent'] = round(gv_thucthu_cs['fixed_overtime'] /
gv_thucthu_cs['thucthu'] * 100, 2)
# "_______________"
# salary_merge = st.session_state['salary_merge']
gv_thucthu_gv = gv_thucthu_cs.groupby(['id_gg', 'Họ và tên'], as_index=False)['fixed_overtime'].sum()\
.merge(thucthu_gv, left_on='id_gg', right_on='id', how='left')
gv_thucthu_gv['percent'] = round(gv_thucthu_gv['fixed_overtime'] /
gv_thucthu_gv['thucthu'] * 100, 2)
gv_thucthu_gv = gv_thucthu_gv.merge(salary, left_on='id', right_on='id_gg')
# Fulltime
df = gv_thucthu_gv
df1 = df[df["working_status"] == "Fulltime"].sort_values(
by="percent", ascending=True)
df1['fullname'] = df1['fullname'] + " (" + df['level'] + ")"
# Parttime
df2 = df[df["working_status"] == "Partime"].sort_values(
by="percent", ascending=True)
df2['fullname'] = df2['fullname'] + " (" + df['level'] + ")"
# Plotly graphs
fig3 = plotly_chart(df1.sort_values(
"percent", ascending=True), 'fullname', 'percent', df1["percent"].apply(
lambda x: '{:.2%}'.format(x/100)),
"Fulltime - Tỷ lệ tổng lương / thực thu", '', 'Tỷ lệ')
fig3.update_layout(
height=1000, # set the height of the plot to 600 pixels
width=800)
# Plotly graphs
fig3_1 = plotly_chart(df2.sort_values(
"percent", ascending=True), 'fullname', 'percent', df2["percent"].apply(
lambda x: '{:.2%}'.format(x/100)),
"Parttime - Tỷ lệ tổng lương / thực thu", '', 'Tỷ lệ')
fig3_1.update_layout(
height=1000, # set the height of the plot to 600 pixels
width=800)
# "_______________" thực thu chuyển phí
hv_status = collect_data('https://vietop.tech/api/get_data/hv_status')
# Filter orders
orders_chuyenphi = orders.query("ketoan_active == 5")[["ketoan_id", "hv_id", "ketoan_details", "ketoan_coso", "ketoan_sogio", "ketoan_price",
"ketoan_tientrengio", "remaining_time", "kh_id"]]
# Filter hv_status
hv_status_chuyenphi = hv_status[['ketoan_id', 'status', 'lop_id', 'note', 'is_price', 'created_at']]\
.query("status ==7")
# Filter hocvien
hocvien_chuyenphi = hocvien[['hv_id', 'hv_fullname']]
# Merge hv_status and orders
chuyenphi = hv_status_chuyenphi.merge(
orders_chuyenphi, on='ketoan_id', how='left')
# Merge hocvien_chuyephi
chuyenphi = chuyenphi.merge(hocvien_chuyenphi, on='hv_id', how='left')
chuyenphi = chuyenphi[['created_at', 'hv_fullname',
'ketoan_coso', 'note', 'is_price']]
# Add column Phi Chuyen
chuyenphi['phí chuyển'] = chuyenphi.is_price * 0.1
# Add column Tien con lai sau phi
chuyenphi['thực thu chuyển phí'] = chuyenphi.is_price - \
chuyenphi['phí chuyển']
# Change data type
chuyenphi = chuyenphi.astype(
{'created_at': 'datetime64[ns]'})
# Sort
chuyenphi = chuyenphi.sort_values(by='created_at', ascending=False)
chuyenphi = chuyenphi.query(
"created_at >= @ketoan_start_time and created_at <= @ketoan_end_time")
# Rename columns
# 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í"]]
chuyenphi = chuyenphi.groupby('ketoan_coso', as_index=False)[
'thực thu chuyển phí'].sum()
chuyenphi = rename_lop(chuyenphi, 'ketoan_coso')
# "_______________" Thực thu kết thúc
# Filter ketthuc
orders_ketthuc = orders.query("ketoan_active == 5 and deleted_at.isnull()")
# Merge orders_ketthuc and diemdanh_details
df = diemdanh_details[['ketoan_id', 'giohoc']]\
.merge(orders_ketthuc, on='ketoan_id', how='right').groupby(
['ketoan_id', 'ketoan_coso', 'remaining_time', 'ketoan_tientrengio', 'date_end'], as_index=False).giohoc.sum()
# Add 2 more columns
df['gio_con_lai'] = df.remaining_time - df.giohoc
df['thực thu kết thúc'] = df.gio_con_lai * df.ketoan_tientrengio
# Convert to datetime
df['date_end'] = pd.to_datetime(df['date_end'])
# Filter gioconlai > 0 and time
thucthu_ketthuc = df.query("gio_con_lai > 0")\
.query("date_end >= @ketoan_start_time and date_end <= @ketoan_end_time")
thucthu_ketthuc = thucthu_ketthuc.merge(
orders[['hv_id', 'ketoan_id']], on='ketoan_id')
thucthu_ketthuc = thucthu_ketthuc.groupby("ketoan_coso", as_index=False)[
'thực thu kết thúc'].sum()
thucthu_ketthuc = rename_lop(thucthu_ketthuc, 'ketoan_coso')
# "_______________"
overtime_salary = sal_diem_over_group.query('working_status_x != "Ngoài giờ"')\
.merge(salary[['Họ và tên', 'working_status']], left_on='Họ và tên', right_on='Họ và tên')
overtime_salary['out_div_total'] = overtime_salary['salary_gio_cong'] / \
(overtime_salary['salary_ngay_cong'] +
overtime_salary['salary_gio_cong'])
overtime_salary = overtime_salary[[
'Họ và tên', 'salary_ngay_cong', 'salary_gio_cong', 'out_div_total']]
overtime_salary['out_div_total'] = round(
overtime_salary['out_div_total'] * 100, 2)
overtime_salary_fulltime = overtime_salary.query("salary_ngay_cong != 0")
# "_______________" thucthu điểm danh and chuyen phi
thucthu_hocvien_lop = thucthu_hocvien_lop.merge(
chuyenphi, left_on='ketoan_coso', right_on='ketoan_coso', how='left')\
.merge(thucthu_ketthuc, left_on='ketoan_coso', right_on='ketoan_coso')
# Renam thucthu => thuc thu diem danh
thucthu_hocvien_lop = thucthu_hocvien_lop.rename(
columns={'thucthu': "thực thu điểm danh"})
# Fillna with 0
thucthu_hocvien_lop.fillna(0, inplace=True)
# Add all thucthu
thucthu_hocvien_lop['tổng thực thu'] = thucthu_hocvien_lop['thực thu chuyển phí'] + \
thucthu_hocvien_lop['thực thu kết thúc'] + \
thucthu_hocvien_lop['thực thu điểm danh']
# Add ty lệ thực thu
thucthu_hocvien_lop['tỷ trọng tổng thực thu'] = thucthu_hocvien_lop['tổng thực thu'].apply(
lambda x: round(x/thucthu_hocvien_lop['tổng thực thu'].sum()*100, 2))
# create a new row with the sum of each numerical column
totals = thucthu_hocvien_lop.select_dtypes(include=[float, int]).sum()
totals["lop_cn"] = "Grand total"
# append the new row to the dataframe
thucthu_hocvien_lop = thucthu_hocvien_lop.append(totals, ignore_index=True)
# Add % in tỷ trọng tổng thực thu
thucthu_hocvien_lop["tỷ trọng tổng thực thu"] = thucthu_hocvien_lop["tỷ trọng tổng thực thu"].apply(
lambda x: '{:.2%}'.format(x/100))
salary_thucthu_grand_total['Tổng lương / thực thu'] = salary_thucthu_grand_total['Tổng lương / thực thu'].apply(
lambda x: '{:.2%}'.format(x/100))
# define a function
@ st.cache
def thousands_divider(df, col):
df[col] = df[col].apply(
lambda x: '{:,.0f}'.format(x))
return df
thucthu_hocvien_lop = thousands_divider(
thucthu_hocvien_lop, 'tổng thực thu')
thucthu_hocvien_lop = thousands_divider(
thucthu_hocvien_lop, 'thực thu điểm danh')
thucthu_hocvien_lop = thousands_divider(
thucthu_hocvien_lop, 'thực thu chuyển phí')
thucthu_hocvien_lop = thousands_divider(
thucthu_hocvien_lop, 'thực thu kết thúc')
thucthu_hocvien_lop = thucthu_hocvien_lop.set_index("lop_cn")
thucthu_hocvien_lop.index.names = ['Chi nhánh']
# Show tables
st.plotly_chart(fig2, use_container_width=True)
st.subheader("Thưc thu theo chi nhánh")
st.dataframe(thucthu_hocvien_lop.drop(["ketoan_coso", "total_students", "total_classes", "thucthu_div_hocvien", "thucthu_div_lophoc"],
axis=1).style.background_gradient().set_precision(0), use_container_width=True)
# Show Chi nhanh by 2 columns
st.plotly_chart(fig10, use_container_width=True)
st.plotly_chart(fig9, use_container_width=True)
# left_column, right_column = st.columns([1, 2])
# left_column.plotly_chart(fig10, use_container_width=True)
# right_column.plotly_chart(fig9, use_container_width=True)
# left_column, right_column = st.columns(2)
# left_column.plotly_chart(fig7, use_container_width=True)
# right_column.plotly_chart(fig8, use_container_width=True)
# left_column, right_column = st.columns(2)
# left_column.plotly_chart(fig5, use_container_width=True)
# right_column.plotly_chart(fig6, use_container_width=True)
# left_column, right_column = st.columns(2)
# left_column.plotly_chart(fig1, use_container_width=True)
# right_column.plotly_chart(fig2, use_container_width=True)
left_column, right_column = st.columns(2)
left_column.plotly_chart(fig3, use_container_width=True)
right_column.plotly_chart(fig3_1, use_container_width=True)
""
fig4 = plotly_chart(overtime_salary_fulltime[['Họ và tên', 'out_div_total']].sort_values(
"out_div_total", ascending=True), "Họ và tên", 'out_div_total', 'out_div_total',
"Tỷ lệ lương ngoài giờ / trong giờ của giáo viên fulltime", '', 'Tỷ lệ')
fig4.update_layout(height=800, width=800)
st.plotly_chart(fig4)