|
""" |
|
وحدة إدارة الإدارات المساندة - إدارة تكاليف الإدارات المساندة |
|
""" |
|
|
|
import streamlit as st |
|
import pandas as pd |
|
import numpy as np |
|
import plotly.express as px |
|
import plotly.graph_objects as go |
|
import os |
|
import json |
|
from datetime import datetime |
|
import io |
|
|
|
class IndirectSupportManagement: |
|
"""فئة إدارة الإدارات المساندة""" |
|
|
|
def __init__(self): |
|
"""تهيئة وحدة إدارة الإدارات المساندة""" |
|
|
|
|
|
if 'indirect_support' not in st.session_state: |
|
self._initialize_indirect_support() |
|
|
|
def _initialize_indirect_support(self): |
|
"""تهيئة بيانات إدارة الإدارات المساندة""" |
|
|
|
|
|
departments = [ |
|
{ |
|
"id": "ADM-001", |
|
"name": "الإدارة العليا", |
|
"category": "إدارية", |
|
"annual_cost": 2400000, |
|
"staff_count": 5, |
|
"allocation_method": "نسبة من قيمة المشروع", |
|
"allocation_percentage": 0.02, |
|
"description": "تشمل الرئيس التنفيذي والمدراء التنفيذيين" |
|
}, |
|
{ |
|
"id": "ADM-002", |
|
"name": "إدارة الموارد البشرية", |
|
"category": "إدارية", |
|
"annual_cost": 1200000, |
|
"staff_count": 8, |
|
"allocation_method": "نسبة من قيمة المشروع", |
|
"allocation_percentage": 0.01, |
|
"description": "مسؤولة عن التوظيف والتدريب وشؤون الموظفين" |
|
}, |
|
{ |
|
"id": "ADM-003", |
|
"name": "الإدارة المالية", |
|
"category": "إدارية", |
|
"annual_cost": 1500000, |
|
"staff_count": 10, |
|
"allocation_method": "نسبة من قيمة المشروع", |
|
"allocation_percentage": 0.015, |
|
"description": "مسؤولة عن المحاسبة والميزانية والتقارير المالية" |
|
}, |
|
{ |
|
"id": "ADM-004", |
|
"name": "إدارة تقنية المعلومات", |
|
"category": "إدارية", |
|
"annual_cost": 1800000, |
|
"staff_count": 12, |
|
"allocation_method": "تكلفة ثابتة", |
|
"allocation_percentage": 0, |
|
"fixed_cost": 50000, |
|
"description": "مسؤولة عن البنية التحتية التقنية والدعم الفني" |
|
}, |
|
{ |
|
"id": "TEC-001", |
|
"name": "إدارة الجودة", |
|
"category": "فنية", |
|
"annual_cost": 1600000, |
|
"staff_count": 15, |
|
"allocation_method": "نسبة من قيمة المشروع", |
|
"allocation_percentage": 0.02, |
|
"description": "مسؤولة عن ضمان الجودة ومراقبة الجودة" |
|
}, |
|
{ |
|
"id": "TEC-002", |
|
"name": "إدارة السلامة", |
|
"category": "فنية", |
|
"annual_cost": 1400000, |
|
"staff_count": 12, |
|
"allocation_method": "نسبة من قيمة المشروع", |
|
"allocation_percentage": 0.015, |
|
"description": "مسؤولة عن السلامة المهنية وسلامة الموقع" |
|
}, |
|
{ |
|
"id": "TEC-003", |
|
"name": "إدارة المشتريات", |
|
"category": "فنية", |
|
"annual_cost": 2000000, |
|
"staff_count": 18, |
|
"allocation_method": "نسبة من قيمة المشروع", |
|
"allocation_percentage": 0.025, |
|
"description": "مسؤولة عن المشتريات والتعاقدات" |
|
}, |
|
{ |
|
"id": "TEC-004", |
|
"name": "إدارة المستودعات", |
|
"category": "فنية", |
|
"annual_cost": 1200000, |
|
"staff_count": 20, |
|
"allocation_method": "تكلفة ثابتة", |
|
"allocation_percentage": 0, |
|
"fixed_cost": 100000, |
|
"description": "مسؤولة عن إدارة المخزون والمستودعات" |
|
}, |
|
{ |
|
"id": "SUP-001", |
|
"name": "إدارة النقل", |
|
"category": "مساندة", |
|
"annual_cost": 2500000, |
|
"staff_count": 25, |
|
"allocation_method": "تكلفة ثابتة", |
|
"allocation_percentage": 0, |
|
"fixed_cost": 200000, |
|
"description": "مسؤولة عن نقل المواد والمعدات والعمالة" |
|
}, |
|
{ |
|
"id": "SUP-002", |
|
"name": "إدارة الصيانة", |
|
"category": "مساندة", |
|
"annual_cost": 1800000, |
|
"staff_count": 22, |
|
"allocation_method": "تكلفة ثابتة", |
|
"allocation_percentage": 0, |
|
"fixed_cost": 150000, |
|
"description": "مسؤولة عن صيانة المعدات والآليات" |
|
}, |
|
{ |
|
"id": "SUP-003", |
|
"name": "إدارة الأمن", |
|
"category": "مساندة", |
|
"annual_cost": 1000000, |
|
"staff_count": 30, |
|
"allocation_method": "تكلفة ثابتة", |
|
"allocation_percentage": 0, |
|
"fixed_cost": 80000, |
|
"description": "مسؤولة عن أمن المواقع والمنشآت" |
|
}, |
|
{ |
|
"id": "SUP-004", |
|
"name": "إدارة الخدمات العامة", |
|
"category": "مساندة", |
|
"annual_cost": 800000, |
|
"staff_count": 15, |
|
"allocation_method": "تكلفة ثابتة", |
|
"allocation_percentage": 0, |
|
"fixed_cost": 50000, |
|
"description": "مسؤولة عن الخدمات العامة والضيافة" |
|
} |
|
] |
|
|
|
|
|
projects = [ |
|
{ |
|
"id": "PRJ-001", |
|
"name": "مشروع تطوير طريق الملك عبدالله", |
|
"value": 50000000, |
|
"duration": 24, |
|
"start_date": "2025-01-01", |
|
"end_date": "2026-12-31", |
|
"status": "جاري", |
|
"location": "الرياض", |
|
"client": "وزارة النقل", |
|
"description": "مشروع تطوير وتوسعة طريق الملك عبدالله بطول 15 كم" |
|
}, |
|
{ |
|
"id": "PRJ-002", |
|
"name": "مشروع إنشاء شبكة صرف صحي", |
|
"value": 30000000, |
|
"duration": 18, |
|
"start_date": "2025-03-01", |
|
"end_date": "2026-08-31", |
|
"status": "جاري", |
|
"location": "جدة", |
|
"client": "شركة المياه الوطنية", |
|
"description": "مشروع إنشاء شبكة صرف صحي في حي النزهة بجدة" |
|
}, |
|
{ |
|
"id": "PRJ-003", |
|
"name": "مشروع إنشاء جسر تقاطع طريق الملك فهد", |
|
"value": 80000000, |
|
"duration": 30, |
|
"start_date": "2025-02-01", |
|
"end_date": "2027-07-31", |
|
"status": "جاري", |
|
"location": "الدمام", |
|
"client": "أمانة المنطقة الشرقية", |
|
"description": "مشروع إنشاء جسر علوي عند تقاطع طريق الملك فهد مع طريق الأمير محمد بن فهد" |
|
} |
|
] |
|
|
|
|
|
allocations = [] |
|
|
|
for project in projects: |
|
for department in departments: |
|
if department["allocation_method"] == "نسبة من قيمة المشروع": |
|
allocation_amount = project["value"] * department["allocation_percentage"] |
|
else: |
|
allocation_amount = department.get("fixed_cost", 0) |
|
|
|
allocations.append({ |
|
"project_id": project["id"], |
|
"department_id": department["id"], |
|
"allocation_amount": allocation_amount, |
|
"allocation_method": department["allocation_method"], |
|
"allocation_percentage": department["allocation_percentage"] if department["allocation_method"] == "نسبة من قيمة المشروع" else 0, |
|
"fixed_cost": department.get("fixed_cost", 0) if department["allocation_method"] == "تكلفة ثابتة" else 0, |
|
"notes": "" |
|
}) |
|
|
|
|
|
st.session_state.indirect_support = { |
|
"departments": pd.DataFrame(departments), |
|
"projects": pd.DataFrame(projects), |
|
"allocations": pd.DataFrame(allocations) |
|
} |
|
|
|
def render(self): |
|
"""عرض واجهة إدارة الإدارات المساندة""" |
|
|
|
st.markdown("## إدارة الإدارات المساندة") |
|
|
|
|
|
tabs = st.tabs([ |
|
"الإدارات المساندة", |
|
"المشاريع", |
|
"تخصيص التكاليف", |
|
"التقارير" |
|
]) |
|
|
|
with tabs[0]: |
|
self._render_departments_tab() |
|
|
|
with tabs[1]: |
|
self._render_projects_tab() |
|
|
|
with tabs[2]: |
|
self._render_allocations_tab() |
|
|
|
with tabs[3]: |
|
self._render_reports_tab() |
|
|
|
def _render_departments_tab(self): |
|
"""عرض تبويب الإدارات المساندة""" |
|
|
|
st.markdown("### الإدارات المساندة") |
|
|
|
|
|
departments = st.session_state.indirect_support["departments"] |
|
|
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
|
|
categories = ["الكل"] + sorted(departments["category"].unique().tolist()) |
|
selected_category = st.selectbox("اختر فئة الإدارة", categories, key="departments_category") |
|
|
|
with col2: |
|
|
|
allocation_methods = ["الكل"] + sorted(departments["allocation_method"].unique().tolist()) |
|
selected_allocation_method = st.selectbox("اختر طريقة التخصيص", allocation_methods, key="departments_allocation_method") |
|
|
|
|
|
filtered_df = departments.copy() |
|
|
|
if selected_category != "الكل": |
|
filtered_df = filtered_df[filtered_df["category"] == selected_category] |
|
|
|
if selected_allocation_method != "الكل": |
|
filtered_df = filtered_df[filtered_df["allocation_method"] == selected_allocation_method] |
|
|
|
|
|
if not filtered_df.empty: |
|
|
|
st.info(f"تم العثور على {len(filtered_df)} إدارة") |
|
|
|
|
|
display_df = filtered_df[["id", "name", "category", "annual_cost", "staff_count", "allocation_method"]].copy() |
|
display_df.columns = ["الكود", "الاسم", "الفئة", "التكلفة السنوية", "عدد الموظفين", "طريقة التخصيص"] |
|
|
|
|
|
st.dataframe(display_df, use_container_width=True) |
|
|
|
|
|
st.markdown("### إضافة إدارة جديدة") |
|
|
|
with st.form("add_department_form"): |
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
department_id = st.text_input("كود الإدارة", value=f"DEP-{len(departments) + 1:03d}") |
|
department_name = st.text_input("اسم الإدارة", placeholder="مثال: إدارة الموارد البشرية") |
|
|
|
with col2: |
|
department_category = st.selectbox("فئة الإدارة", ["إدارية", "فنية", "مساندة"]) |
|
department_staff_count = st.number_input("عدد الموظفين", min_value=1, step=1) |
|
|
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
department_annual_cost = st.number_input("التكلفة السنوية (ريال)", min_value=0, step=100000) |
|
|
|
with col2: |
|
department_allocation_method = st.selectbox("طريقة التخصيص", ["نسبة من قيمة المشروع", "تكلفة ثابتة"]) |
|
|
|
|
|
if department_allocation_method == "نسبة من قيمة المشروع": |
|
department_allocation_percentage = st.slider("نسبة التخصيص", min_value=0.0, max_value=0.1, value=0.01, step=0.001, format="%g%%") * 100 |
|
department_fixed_cost = 0 |
|
else: |
|
department_fixed_cost = st.number_input("التكلفة الثابتة (ريال)", min_value=0, step=10000) |
|
department_allocation_percentage = 0 |
|
|
|
|
|
department_description = st.text_area("وصف الإدارة", placeholder="أدخل وصفاً تفصيلياً للإدارة") |
|
|
|
|
|
submit_button = st.form_submit_button("إضافة الإدارة") |
|
|
|
if submit_button: |
|
|
|
if not department_name or not department_category: |
|
st.error("يرجى إدخال المعلومات الأساسية للإدارة") |
|
else: |
|
|
|
new_department = { |
|
"id": department_id, |
|
"name": department_name, |
|
"category": department_category, |
|
"annual_cost": department_annual_cost, |
|
"staff_count": department_staff_count, |
|
"allocation_method": department_allocation_method, |
|
"allocation_percentage": department_allocation_percentage / 100 if department_allocation_method == "نسبة من قيمة المشروع" else 0, |
|
"fixed_cost": department_fixed_cost if department_allocation_method == "تكلفة ثابتة" else 0, |
|
"description": department_description |
|
} |
|
|
|
|
|
st.session_state.indirect_support["departments"] = pd.concat([ |
|
st.session_state.indirect_support["departments"], |
|
pd.DataFrame([new_department]) |
|
], ignore_index=True) |
|
|
|
|
|
projects = st.session_state.indirect_support["projects"] |
|
allocations = st.session_state.indirect_support["allocations"] |
|
|
|
new_allocations = [] |
|
|
|
for _, project in projects.iterrows(): |
|
if department_allocation_method == "نسبة من قيمة المشروع": |
|
allocation_amount = project["value"] * (department_allocation_percentage / 100) |
|
else: |
|
allocation_amount = department_fixed_cost |
|
|
|
new_allocations.append({ |
|
"project_id": project["id"], |
|
"department_id": department_id, |
|
"allocation_amount": allocation_amount, |
|
"allocation_method": department_allocation_method, |
|
"allocation_percentage": department_allocation_percentage / 100 if department_allocation_method == "نسبة من قيمة المشروع" else 0, |
|
"fixed_cost": department_fixed_cost if department_allocation_method == "تكلفة ثابتة" else 0, |
|
"notes": "" |
|
}) |
|
|
|
|
|
st.session_state.indirect_support["allocations"] = pd.concat([ |
|
allocations, |
|
pd.DataFrame(new_allocations) |
|
], ignore_index=True) |
|
|
|
st.success(f"تمت إضافة الإدارة {department_name} بنجاح!") |
|
|
|
|
|
st.experimental_rerun() |
|
|
|
|
|
st.markdown("### تفاصيل الإدارات") |
|
|
|
selected_department_id = st.selectbox("اختر إدارة لعرض التفاصيل", filtered_df["id"].tolist(), key="department_details") |
|
|
|
|
|
selected_department = filtered_df[filtered_df["id"] == selected_department_id].iloc[0] |
|
|
|
|
|
st.markdown(f"**الإدارة:** {selected_department['name']} ({selected_department['id']})") |
|
st.markdown(f"**الفئة:** {selected_department['category']}") |
|
st.markdown(f"**التكلفة السنوية:** {selected_department['annual_cost']:,} ريال") |
|
st.markdown(f"**عدد الموظفين:** {selected_department['staff_count']} موظف") |
|
st.markdown(f"**طريقة التخصيص:** {selected_department['allocation_method']}") |
|
|
|
if selected_department["allocation_method"] == "نسبة من قيمة المشروع": |
|
st.markdown(f"**نسبة التخصيص:** {selected_department['allocation_percentage'] * 100:.2f}%") |
|
else: |
|
st.markdown(f"**التكلفة الثابتة:** {selected_department.get('fixed_cost', 0):,} ريال") |
|
|
|
if "description" in selected_department and selected_department["description"]: |
|
st.markdown(f"**الوصف:** {selected_department['description']}") |
|
|
|
|
|
st.markdown("#### تخصيصات الإدارة للمشاريع") |
|
|
|
|
|
allocations = st.session_state.indirect_support["allocations"] |
|
projects = st.session_state.indirect_support["projects"] |
|
|
|
department_allocations = allocations[allocations["department_id"] == selected_department_id] |
|
|
|
if not department_allocations.empty: |
|
|
|
merged_allocations = pd.merge( |
|
department_allocations, |
|
projects[["id", "name", "value"]], |
|
left_on="project_id", |
|
right_on="id", |
|
suffixes=("", "_project") |
|
) |
|
|
|
|
|
display_allocations = merged_allocations[["id_project", "name", "value", "allocation_amount"]].copy() |
|
display_allocations.columns = ["كود المشروع", "اسم المشروع", "قيمة المشروع", "مبلغ التخصيص"] |
|
|
|
|
|
st.dataframe(display_allocations, use_container_width=True) |
|
|
|
|
|
fig = px.bar( |
|
display_allocations, |
|
x="اسم المشروع", |
|
y="مبلغ التخصيص", |
|
title=f"تخصيصات إدارة {selected_department['name']} للمشاريع", |
|
color="اسم المشروع", |
|
text_auto=True |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
else: |
|
st.info("لا يوجد تخصيصات لهذه الإدارة") |
|
else: |
|
st.warning("لا يوجد إدارات تطابق معايير البحث") |
|
|
|
def _render_projects_tab(self): |
|
"""عرض تبويب المشاريع""" |
|
|
|
st.markdown("### المشاريع") |
|
|
|
|
|
projects = st.session_state.indirect_support["projects"] |
|
|
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
|
|
statuses = ["الكل"] + sorted(projects["status"].unique().tolist()) |
|
selected_status = st.selectbox("اختر حالة المشروع", statuses, key="projects_status") |
|
|
|
with col2: |
|
|
|
locations = ["الكل"] + sorted(projects["location"].unique().tolist()) |
|
selected_location = st.selectbox("اختر موقع المشروع", locations, key="projects_location") |
|
|
|
|
|
filtered_df = projects.copy() |
|
|
|
if selected_status != "الكل": |
|
filtered_df = filtered_df[filtered_df["status"] == selected_status] |
|
|
|
if selected_location != "الكل": |
|
filtered_df = filtered_df[filtered_df["location"] == selected_location] |
|
|
|
|
|
if not filtered_df.empty: |
|
|
|
st.info(f"تم العثور على {len(filtered_df)} مشروع") |
|
|
|
|
|
display_df = filtered_df[["id", "name", "value", "duration", "status", "location", "client"]].copy() |
|
display_df.columns = ["الكود", "الاسم", "القيمة", "المدة (شهر)", "الحالة", "الموقع", "العميل"] |
|
|
|
|
|
st.dataframe(display_df, use_container_width=True) |
|
|
|
|
|
st.markdown("### إضافة مشروع جديد") |
|
|
|
with st.form("add_project_form"): |
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
project_id = st.text_input("كود المشروع", value=f"PRJ-{len(projects) + 1:03d}") |
|
project_name = st.text_input("اسم المشروع", placeholder="مثال: مشروع تطوير طريق الملك عبدالله") |
|
|
|
with col2: |
|
project_value = st.number_input("قيمة المشروع (ريال)", min_value=0, step=1000000) |
|
project_duration = st.number_input("مدة المشروع (شهر)", min_value=1, step=1) |
|
|
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
project_start_date = st.date_input("تاريخ البدء") |
|
project_status = st.selectbox("حالة المشروع", ["جاري", "مكتمل", "متوقف", "ملغي"]) |
|
|
|
with col2: |
|
project_end_date = st.date_input("تاريخ الانتهاء") |
|
project_location = st.text_input("موقع المشروع", placeholder="مثال: الرياض") |
|
|
|
|
|
project_client = st.text_input("العميل", placeholder="مثال: وزارة النقل") |
|
project_description = st.text_area("وصف المشروع", placeholder="أدخل وصفاً تفصيلياً للمشروع") |
|
|
|
|
|
submit_button = st.form_submit_button("إضافة المشروع") |
|
|
|
if submit_button: |
|
|
|
if not project_name or not project_value or not project_location or not project_client: |
|
st.error("يرجى إدخال المعلومات الأساسية للمشروع") |
|
else: |
|
|
|
new_project = { |
|
"id": project_id, |
|
"name": project_name, |
|
"value": project_value, |
|
"duration": project_duration, |
|
"start_date": project_start_date.strftime("%Y-%m-%d"), |
|
"end_date": project_end_date.strftime("%Y-%m-%d"), |
|
"status": project_status, |
|
"location": project_location, |
|
"client": project_client, |
|
"description": project_description |
|
} |
|
|
|
|
|
st.session_state.indirect_support["projects"] = pd.concat([ |
|
st.session_state.indirect_support["projects"], |
|
pd.DataFrame([new_project]) |
|
], ignore_index=True) |
|
|
|
|
|
departments = st.session_state.indirect_support["departments"] |
|
allocations = st.session_state.indirect_support["allocations"] |
|
|
|
new_allocations = [] |
|
|
|
for _, department in departments.iterrows(): |
|
if department["allocation_method"] == "نسبة من قيمة المشروع": |
|
allocation_amount = project_value * department["allocation_percentage"] |
|
else: |
|
allocation_amount = department.get("fixed_cost", 0) |
|
|
|
new_allocations.append({ |
|
"project_id": project_id, |
|
"department_id": department["id"], |
|
"allocation_amount": allocation_amount, |
|
"allocation_method": department["allocation_method"], |
|
"allocation_percentage": department["allocation_percentage"] if department["allocation_method"] == "نسبة من قيمة المشروع" else 0, |
|
"fixed_cost": department.get("fixed_cost", 0) if department["allocation_method"] == "تكلفة ثابتة" else 0, |
|
"notes": "" |
|
}) |
|
|
|
|
|
st.session_state.indirect_support["allocations"] = pd.concat([ |
|
allocations, |
|
pd.DataFrame(new_allocations) |
|
], ignore_index=True) |
|
|
|
st.success(f"تمت إضافة المشروع {project_name} بنجاح!") |
|
|
|
|
|
st.experimental_rerun() |
|
|
|
|
|
st.markdown("### تفاصيل المشاريع") |
|
|
|
selected_project_id = st.selectbox("اختر مشروع لعرض التفاصيل", filtered_df["id"].tolist(), key="project_details") |
|
|
|
|
|
selected_project = filtered_df[filtered_df["id"] == selected_project_id].iloc[0] |
|
|
|
|
|
st.markdown(f"**المشروع:** {selected_project['name']} ({selected_project['id']})") |
|
st.markdown(f"**القيمة:** {selected_project['value']:,} ريال") |
|
st.markdown(f"**المدة:** {selected_project['duration']} شهر") |
|
st.markdown(f"**تاريخ البدء:** {selected_project['start_date']}") |
|
st.markdown(f"**تاريخ الانتهاء:** {selected_project['end_date']}") |
|
st.markdown(f"**الحالة:** {selected_project['status']}") |
|
st.markdown(f"**الموقع:** {selected_project['location']}") |
|
st.markdown(f"**العميل:** {selected_project['client']}") |
|
|
|
if "description" in selected_project and selected_project["description"]: |
|
st.markdown(f"**الوصف:** {selected_project['description']}") |
|
|
|
|
|
st.markdown("#### تخصيصات الإدارات المساندة للمشروع") |
|
|
|
|
|
allocations = st.session_state.indirect_support["allocations"] |
|
departments = st.session_state.indirect_support["departments"] |
|
|
|
project_allocations = allocations[allocations["project_id"] == selected_project_id] |
|
|
|
if not project_allocations.empty: |
|
|
|
merged_allocations = pd.merge( |
|
project_allocations, |
|
departments[["id", "name", "category"]], |
|
left_on="department_id", |
|
right_on="id", |
|
suffixes=("", "_department") |
|
) |
|
|
|
|
|
display_allocations = merged_allocations[["id_department", "name", "category", "allocation_amount", "allocation_method"]].copy() |
|
display_allocations.columns = ["كود الإدارة", "اسم الإدارة", "الفئة", "مبلغ التخصيص", "طريقة التخصيص"] |
|
|
|
|
|
st.dataframe(display_allocations, use_container_width=True) |
|
|
|
|
|
total_allocation = display_allocations["مبلغ التخصيص"].sum() |
|
|
|
st.markdown(f"**إجمالي تخصيصات الإدارات المساندة:** {total_allocation:,} ريال") |
|
st.markdown(f"**نسبة التخصيصات من قيمة المشروع:** {(total_allocation / selected_project['value']) * 100:.2f}%") |
|
|
|
|
|
fig = px.bar( |
|
display_allocations, |
|
x="اسم الإدارة", |
|
y="مبلغ التخصيص", |
|
title=f"تخصيصات الإدارات المساندة لمشروع {selected_project['name']}", |
|
color="الفئة", |
|
text_auto=True |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
category_allocations = display_allocations.groupby("الفئة")["مبلغ التخصيص"].sum().reset_index() |
|
|
|
fig = px.pie( |
|
category_allocations, |
|
values="مبلغ التخصيص", |
|
names="الفئة", |
|
title=f"توزيع تخصيصات الإدارات المساندة حسب الفئة لمشروع {selected_project['name']}", |
|
color="الفئة" |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
else: |
|
st.info("لا يوجد تخصيصات لهذا المشروع") |
|
else: |
|
st.warning("لا يوجد مشاريع تطابق معايير البحث") |
|
|
|
def _render_allocations_tab(self): |
|
"""عرض تبويب تخصيص التكاليف""" |
|
|
|
st.markdown("### تخصيص تكاليف الإدارات المساندة") |
|
|
|
|
|
allocations = st.session_state.indirect_support["allocations"] |
|
departments = st.session_state.indirect_support["departments"] |
|
projects = st.session_state.indirect_support["projects"] |
|
|
|
|
|
merged_allocations = pd.merge( |
|
allocations, |
|
departments[["id", "name", "category"]], |
|
left_on="department_id", |
|
right_on="id", |
|
suffixes=("", "_department") |
|
) |
|
|
|
merged_allocations = pd.merge( |
|
merged_allocations, |
|
projects[["id", "name", "value", "status"]], |
|
left_on="project_id", |
|
right_on="id", |
|
suffixes=("_department", "_project") |
|
) |
|
|
|
|
|
col1, col2, col3 = st.columns(3) |
|
|
|
with col1: |
|
|
|
project_options = ["الكل"] + sorted(projects["name"].unique().tolist()) |
|
selected_project = st.selectbox("اختر المشروع", project_options, key="allocations_project") |
|
|
|
with col2: |
|
|
|
department_categories = ["الكل"] + sorted(departments["category"].unique().tolist()) |
|
selected_department_category = st.selectbox("اختر فئة الإدارة", department_categories, key="allocations_department_category") |
|
|
|
with col3: |
|
|
|
allocation_methods = ["الكل"] + sorted(allocations["allocation_method"].unique().tolist()) |
|
selected_allocation_method = st.selectbox("اختر طريقة التخصيص", allocation_methods, key="allocations_method") |
|
|
|
|
|
filtered_df = merged_allocations.copy() |
|
|
|
if selected_project != "الكل": |
|
filtered_df = filtered_df[filtered_df["name_project"] == selected_project] |
|
|
|
if selected_department_category != "الكل": |
|
filtered_df = filtered_df[filtered_df["category"] == selected_department_category] |
|
|
|
if selected_allocation_method != "الكل": |
|
filtered_df = filtered_df[filtered_df["allocation_method"] == selected_allocation_method] |
|
|
|
|
|
if not filtered_df.empty: |
|
|
|
st.info(f"تم العثور على {len(filtered_df)} تخصيص") |
|
|
|
|
|
display_df = filtered_df[["id_project", "name_project", "id_department", "name_department", "category", "allocation_method", "allocation_amount"]].copy() |
|
display_df.columns = ["كود المشروع", "اسم المشروع", "كود الإدارة", "اسم الإدارة", "فئة الإدارة", "طريقة التخصيص", "مبلغ التخصيص"] |
|
|
|
|
|
st.dataframe(display_df, use_container_width=True) |
|
|
|
|
|
st.markdown("### تعديل التخصيصات") |
|
|
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
edit_project_id = st.selectbox("اختر المشروع", projects["id"].tolist(), key="edit_allocation_project") |
|
|
|
with col2: |
|
edit_department_id = st.selectbox("اختر الإدارة", departments["id"].tolist(), key="edit_allocation_department") |
|
|
|
|
|
selected_allocation = allocations[ |
|
(allocations["project_id"] == edit_project_id) & |
|
(allocations["department_id"] == edit_department_id) |
|
] |
|
|
|
if not selected_allocation.empty: |
|
selected_allocation = selected_allocation.iloc[0] |
|
|
|
|
|
selected_project = projects[projects["id"] == edit_project_id].iloc[0] |
|
selected_department = departments[departments["id"] == edit_department_id].iloc[0] |
|
|
|
st.markdown(f"**المشروع:** {selected_project['name']} ({selected_project['id']})") |
|
st.markdown(f"**الإدارة:** {selected_department['name']} ({selected_department['id']})") |
|
st.markdown(f"**طريقة التخصيص الحالية:** {selected_allocation['allocation_method']}") |
|
st.markdown(f"**مبلغ التخصيص الحالي:** {selected_allocation['allocation_amount']:,} ريال") |
|
|
|
|
|
with st.form("edit_allocation_form"): |
|
|
|
allocation_method = st.selectbox( |
|
"طريقة التخصيص", |
|
["نسبة من قيمة المشروع", "تكلفة ثابتة"], |
|
index=0 if selected_allocation["allocation_method"] == "نسبة من قيمة المشروع" else 1, |
|
key="edit_allocation_method" |
|
) |
|
|
|
|
|
if allocation_method == "نسبة من قيمة المشروع": |
|
allocation_percentage = st.slider( |
|
"نسبة التخصيص", |
|
min_value=0.0, |
|
max_value=0.1, |
|
value=float(selected_allocation["allocation_percentage"]), |
|
step=0.001, |
|
format="%g%%", |
|
key="edit_allocation_percentage" |
|
) * 100 |
|
|
|
|
|
allocation_amount = selected_project["value"] * (allocation_percentage / 100) |
|
|
|
st.markdown(f"**مبلغ التخصيص المحسوب:** {allocation_amount:,} ريال") |
|
|
|
fixed_cost = 0 |
|
else: |
|
fixed_cost = st.number_input( |
|
"التكلفة الثابتة (ريال)", |
|
min_value=0, |
|
value=int(selected_allocation["fixed_cost"]), |
|
step=10000, |
|
key="edit_allocation_fixed_cost" |
|
) |
|
|
|
allocation_amount = fixed_cost |
|
allocation_percentage = 0 |
|
|
|
|
|
notes = st.text_area( |
|
"ملاحظات", |
|
value=selected_allocation["notes"] if "notes" in selected_allocation else "", |
|
key="edit_allocation_notes" |
|
) |
|
|
|
|
|
submit_button = st.form_submit_button("حفظ التعديلات") |
|
|
|
if submit_button: |
|
|
|
allocation_index = allocations[ |
|
(allocations["project_id"] == edit_project_id) & |
|
(allocations["department_id"] == edit_department_id) |
|
].index[0] |
|
|
|
allocations.at[allocation_index, "allocation_method"] = allocation_method |
|
allocations.at[allocation_index, "allocation_percentage"] = allocation_percentage / 100 if allocation_method == "نسبة من قيمة المشروع" else 0 |
|
allocations.at[allocation_index, "fixed_cost"] = fixed_cost if allocation_method == "تكلفة ثابتة" else 0 |
|
allocations.at[allocation_index, "allocation_amount"] = allocation_amount |
|
allocations.at[allocation_index, "notes"] = notes |
|
|
|
|
|
st.session_state.indirect_support["allocations"] = allocations |
|
|
|
st.success("تم تحديث التخصيص بنجاح!") |
|
|
|
|
|
st.experimental_rerun() |
|
else: |
|
st.warning("لم يتم العثور على تخصيص للمشروع والإدارة المختارين") |
|
|
|
|
|
st.markdown("### ملخص التخصيصات") |
|
|
|
|
|
project_allocations = filtered_df.groupby("name_project")["allocation_amount"].sum().reset_index() |
|
project_allocations.columns = ["المشروع", "إجمالي التخصيصات"] |
|
|
|
|
|
st.dataframe(project_allocations, use_container_width=True) |
|
|
|
|
|
fig = px.bar( |
|
project_allocations, |
|
x="المشروع", |
|
y="إجمالي التخصيصات", |
|
title="إجمالي تخصيصات الإدارات المساندة حسب المشروع", |
|
color="المشروع", |
|
text_auto=True |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
category_allocations = filtered_df.groupby("category")["allocation_amount"].sum().reset_index() |
|
category_allocations.columns = ["فئة الإدارة", "إجمالي التخصيصات"] |
|
|
|
|
|
st.dataframe(category_allocations, use_container_width=True) |
|
|
|
|
|
fig = px.pie( |
|
category_allocations, |
|
values="إجمالي التخصيصات", |
|
names="فئة الإدارة", |
|
title="توزيع تخصيصات الإدارات المساندة حسب الفئة", |
|
color="فئة الإدارة" |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
else: |
|
st.warning("لا يوجد تخصيصات تطابق معايير البحث") |
|
|
|
def _render_reports_tab(self): |
|
"""عرض تبويب التقارير""" |
|
|
|
st.markdown("### تقارير الإدارات المساندة") |
|
|
|
|
|
allocations = st.session_state.indirect_support["allocations"] |
|
departments = st.session_state.indirect_support["departments"] |
|
projects = st.session_state.indirect_support["projects"] |
|
|
|
|
|
merged_allocations = pd.merge( |
|
allocations, |
|
departments[["id", "name", "category", "annual_cost", "staff_count"]], |
|
left_on="department_id", |
|
right_on="id", |
|
suffixes=("", "_department") |
|
) |
|
|
|
merged_allocations = pd.merge( |
|
merged_allocations, |
|
projects[["id", "name", "value", "status", "duration"]], |
|
left_on="project_id", |
|
right_on="id", |
|
suffixes=("_department", "_project") |
|
) |
|
|
|
|
|
report_type = st.selectbox( |
|
"اختر نوع التقرير", |
|
[ |
|
"تقرير تكاليف الإدارات المساندة", |
|
"تقرير تخصيصات المشاريع", |
|
"تقرير مقارنة التكاليف", |
|
"تقرير تحليل الكفاءة" |
|
], |
|
key="report_type" |
|
) |
|
|
|
if report_type == "تقرير تكاليف الإدارات المساندة": |
|
self._render_departments_cost_report(departments, merged_allocations) |
|
elif report_type == "تقرير تخصيصات المشاريع": |
|
self._render_projects_allocation_report(projects, merged_allocations) |
|
elif report_type == "تقرير مقارنة التكاليف": |
|
self._render_cost_comparison_report(departments, projects, merged_allocations) |
|
elif report_type == "تقرير تحليل الكفاءة": |
|
self._render_efficiency_analysis_report(departments, projects, merged_allocations) |
|
|
|
def _render_departments_cost_report(self, departments, merged_allocations): |
|
"""عرض تقرير تكاليف الإدارات المساندة""" |
|
|
|
st.markdown("#### تقرير تكاليف الإدارات المساندة") |
|
|
|
|
|
total_annual_cost = departments["annual_cost"].sum() |
|
total_staff_count = departments["staff_count"].sum() |
|
|
|
|
|
st.markdown(f"**إجمالي التكاليف السنوية للإدارات المساندة:** {total_annual_cost:,} ريال") |
|
st.markdown(f"**إجمالي عدد الموظفين:** {total_staff_count} موظف") |
|
st.markdown(f"**متوسط تكلفة الموظف السنوية:** {total_annual_cost / total_staff_count:,.2f} ريال") |
|
|
|
|
|
category_costs = departments.groupby("category").agg({ |
|
"annual_cost": "sum", |
|
"staff_count": "sum" |
|
}).reset_index() |
|
|
|
category_costs["نسبة التكلفة"] = category_costs["annual_cost"] / total_annual_cost * 100 |
|
category_costs["متوسط تكلفة الموظف"] = category_costs["annual_cost"] / category_costs["staff_count"] |
|
|
|
|
|
category_costs.columns = ["الفئة", "التكلفة السنوية", "عدد الموظفين", "نسبة التكلفة", "متوسط تكلفة الموظف"] |
|
|
|
|
|
st.dataframe(category_costs, use_container_width=True) |
|
|
|
|
|
fig = px.pie( |
|
category_costs, |
|
values="التكلفة السنوية", |
|
names="الفئة", |
|
title="توزيع تكاليف الإدارات المساندة حسب الفئة", |
|
color="الفئة" |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
fig = px.bar( |
|
category_costs, |
|
x="الفئة", |
|
y="متوسط تكلفة الموظف", |
|
title="متوسط تكلفة الموظف السنوية حسب فئة الإدارة", |
|
color="الفئة", |
|
text_auto=True |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
department_allocations = merged_allocations.groupby("name_department").agg({ |
|
"allocation_amount": "sum", |
|
"annual_cost": "first", |
|
"category": "first" |
|
}).reset_index() |
|
|
|
department_allocations["نسبة التغطية"] = department_allocations["allocation_amount"] / department_allocations["annual_cost"] * 100 |
|
|
|
|
|
department_allocations.columns = ["الإدارة", "إجمالي التخصيصات", "التكلفة السنوية", "الفئة", "نسبة التغطية"] |
|
|
|
|
|
department_allocations = department_allocations.sort_values(by="نسبة التغطية", ascending=False) |
|
|
|
|
|
st.dataframe(department_allocations, use_container_width=True) |
|
|
|
|
|
fig = px.bar( |
|
department_allocations, |
|
x="الإدارة", |
|
y="نسبة التغطية", |
|
title="نسبة تغطية تكاليف الإدارات المساندة من خلال التخصيصات", |
|
color="الفئة", |
|
text_auto=True |
|
) |
|
|
|
|
|
fig.add_shape( |
|
type="line", |
|
x0=-0.5, |
|
y0=100, |
|
x1=len(department_allocations) - 0.5, |
|
y1=100, |
|
line=dict( |
|
color="red", |
|
width=2, |
|
dash="dash" |
|
) |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
total_allocations = department_allocations["إجمالي التخصيصات"].sum() |
|
total_coverage = total_allocations / total_annual_cost * 100 |
|
|
|
st.markdown(f"**إجمالي التخصيصات:** {total_allocations:,} ريال") |
|
st.markdown(f"**نسبة التغطية الإجمالية:** {total_coverage:.2f}%") |
|
|
|
if total_coverage < 100: |
|
st.warning(f"هناك عجز في تغطية تكاليف الإدارات المساندة بنسبة {100 - total_coverage:.2f}%") |
|
elif total_coverage > 100: |
|
st.success(f"هناك فائض في تغطية تكاليف الإدارات المساندة بنسبة {total_coverage - 100:.2f}%") |
|
else: |
|
st.success("تمت تغطية تكاليف الإدارات المساندة بالكامل") |
|
|
|
def _render_projects_allocation_report(self, projects, merged_allocations): |
|
"""عرض تقرير تخصيصات المشاريع""" |
|
|
|
st.markdown("#### تقرير تخصيصات المشاريع") |
|
|
|
|
|
total_projects_value = projects["value"].sum() |
|
|
|
|
|
st.markdown(f"**عدد المشاريع:** {len(projects)}") |
|
st.markdown(f"**إجمالي قيم المشاريع:** {total_projects_value:,} ريال") |
|
|
|
|
|
project_allocations = merged_allocations.groupby("name_project").agg({ |
|
"allocation_amount": "sum", |
|
"value": "first", |
|
"status": "first", |
|
"duration": "first" |
|
}).reset_index() |
|
|
|
project_allocations["نسبة التخصيص"] = project_allocations["allocation_amount"] / project_allocations["value"] * 100 |
|
project_allocations["تكلفة التخصيص الشهرية"] = project_allocations["allocation_amount"] / project_allocations["duration"] |
|
|
|
|
|
project_allocations.columns = ["المشروع", "إجمالي التخصيصات", "قيمة المشروع", "الحالة", "المدة (شهر)", "نسبة التخصيص", "تكلفة التخصيص الشهرية"] |
|
|
|
|
|
project_allocations = project_allocations.sort_values(by="نسبة التخصيص", ascending=False) |
|
|
|
|
|
st.dataframe(project_allocations, use_container_width=True) |
|
|
|
|
|
fig = px.bar( |
|
project_allocations, |
|
x="المشروع", |
|
y="نسبة التخصيص", |
|
title="نسبة تخصيص الإدارات المساندة من قيمة المشروع", |
|
color="الحالة", |
|
text_auto=True |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
fig = px.bar( |
|
project_allocations, |
|
x="المشروع", |
|
y="تكلفة التخصيص الشهرية", |
|
title="تكلفة تخصيص الإدارات المساندة الشهرية لكل مشروع", |
|
color="الحالة", |
|
text_auto=True |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
category_allocations = merged_allocations.groupby(["name_project", "category"]).agg({ |
|
"allocation_amount": "sum" |
|
}).reset_index() |
|
|
|
|
|
category_allocations.columns = ["المشروع", "فئة الإدارة", "مبلغ التخصيص"] |
|
|
|
|
|
fig = px.bar( |
|
category_allocations, |
|
x="المشروع", |
|
y="مبلغ التخصيص", |
|
color="فئة الإدارة", |
|
title="توزيع تخصيصات الإدارات المساندة حسب الفئة لكل مشروع", |
|
barmode="stack", |
|
text_auto=True |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
avg_allocation_percentage = project_allocations["نسبة التخصيص"].mean() |
|
|
|
st.markdown(f"**متوسط نسبة تخصيص الإدارات المساندة من قيمة المشروع:** {avg_allocation_percentage:.2f}%") |
|
|
|
|
|
fig = px.scatter( |
|
project_allocations, |
|
x="قيمة المشروع", |
|
y="نسبة التخصيص", |
|
title="العلاقة بين قيمة المشروع ونسبة تخصيص الإدارات المساندة", |
|
color="الحالة", |
|
size="المدة (شهر)", |
|
hover_data=["المشروع"], |
|
trendline="ols" |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
fig = px.scatter( |
|
project_allocations, |
|
x="المدة (شهر)", |
|
y="تكلفة التخصيص الشهرية", |
|
title="العلاقة بين مدة المشروع وتكلفة تخصيص الإدارات المساندة الشهرية", |
|
color="الحالة", |
|
size="قيمة المشروع", |
|
hover_data=["المشروع"], |
|
trendline="ols" |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
def _render_cost_comparison_report(self, departments, projects, merged_allocations): |
|
"""عرض تقرير مقارنة التكاليف""" |
|
|
|
st.markdown("#### تقرير مقارنة التكاليف") |
|
|
|
|
|
total_annual_cost = departments["annual_cost"].sum() |
|
|
|
|
|
total_projects_value = projects["value"].sum() |
|
|
|
|
|
total_allocations = merged_allocations["allocation_amount"].sum() |
|
|
|
|
|
st.markdown(f"**إجمالي التكاليف السنوية للإدارات المساندة:** {total_annual_cost:,} ريال") |
|
st.markdown(f"**إجمالي قيم المشاريع:** {total_projects_value:,} ريال") |
|
st.markdown(f"**إجمالي التخصيصات:** {total_allocations:,} ريال") |
|
st.markdown(f"**نسبة التكاليف السنوية من إجمالي قيم المشاريع:** {(total_annual_cost / total_projects_value) * 100:.2f}%") |
|
st.markdown(f"**نسبة التخصيصات من إجمالي قيم المشاريع:** {(total_allocations / total_projects_value) * 100:.2f}%") |
|
st.markdown(f"**نسبة تغطية التكاليف السنوية من خلال التخصيصات:** {(total_allocations / total_annual_cost) * 100:.2f}%") |
|
|
|
|
|
comparison_data = pd.DataFrame({ |
|
"البند": ["التكاليف السنوية", "التخصيصات"], |
|
"القيمة": [total_annual_cost, total_allocations] |
|
}) |
|
|
|
|
|
fig = px.bar( |
|
comparison_data, |
|
x="البند", |
|
y="القيمة", |
|
title="مقارنة بين التكاليف السنوية والتخصيصات", |
|
color="البند", |
|
text_auto=True |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
category_costs = departments.groupby("category").agg({ |
|
"annual_cost": "sum" |
|
}).reset_index() |
|
|
|
category_allocations = merged_allocations.groupby("category").agg({ |
|
"allocation_amount": "sum" |
|
}).reset_index() |
|
|
|
|
|
category_comparison = pd.merge( |
|
category_costs, |
|
category_allocations, |
|
on="category", |
|
how="left" |
|
) |
|
|
|
category_comparison["نسبة التغطية"] = category_comparison["allocation_amount"] / category_comparison["annual_cost"] * 100 |
|
|
|
|
|
category_comparison.columns = ["الفئة", "التكلفة السنوية", "التخصيصات", "نسبة التغطية"] |
|
|
|
|
|
st.dataframe(category_comparison, use_container_width=True) |
|
|
|
|
|
category_comparison_data = [] |
|
|
|
for _, row in category_comparison.iterrows(): |
|
category_comparison_data.extend([ |
|
{"الفئة": row["الفئة"], "البند": "التكلفة السنوية", "القيمة": row["التكلفة السنوية"]}, |
|
{"الفئة": row["الفئة"], "البند": "التخصيصات", "القيمة": row["التخصيصات"]} |
|
]) |
|
|
|
category_comparison_df = pd.DataFrame(category_comparison_data) |
|
|
|
fig = px.bar( |
|
category_comparison_df, |
|
x="الفئة", |
|
y="القيمة", |
|
color="البند", |
|
title="مقارنة بين التكاليف السنوية والتخصيصات حسب فئة الإدارة", |
|
barmode="group", |
|
text_auto=True |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
fig = px.bar( |
|
category_comparison, |
|
x="الفئة", |
|
y="نسبة التغطية", |
|
title="نسبة تغطية التكاليف السنوية من خلال التخصيصات حسب فئة الإدارة", |
|
color="الفئة", |
|
text_auto=True |
|
) |
|
|
|
|
|
fig.add_shape( |
|
type="line", |
|
x0=-0.5, |
|
y0=100, |
|
x1=len(category_comparison) - 0.5, |
|
y1=100, |
|
line=dict( |
|
color="red", |
|
width=2, |
|
dash="dash" |
|
) |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
project_allocations = merged_allocations.groupby("name_project").agg({ |
|
"allocation_amount": "sum", |
|
"value": "first" |
|
}).reset_index() |
|
|
|
project_allocations["نسبة التخصيص"] = project_allocations["allocation_amount"] / project_allocations["value"] * 100 |
|
|
|
|
|
project_allocations.columns = ["المشروع", "التخصيصات", "قيمة المشروع", "نسبة التخصيص"] |
|
|
|
|
|
project_allocations = project_allocations.sort_values(by="نسبة التخصيص", ascending=False) |
|
|
|
|
|
st.dataframe(project_allocations, use_container_width=True) |
|
|
|
|
|
fig = px.bar( |
|
project_allocations, |
|
x="المشروع", |
|
y=["قيمة المشروع", "التخصيصات"], |
|
title="تأثير تخصيصات الإدارات المساندة على تكلفة المشاريع", |
|
barmode="stack", |
|
text_auto=True |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
def _render_efficiency_analysis_report(self, departments, projects, merged_allocations): |
|
"""عرض تقرير تحليل الكفاءة""" |
|
|
|
st.markdown("#### تقرير تحليل الكفاءة") |
|
|
|
|
|
department_efficiency = departments.copy() |
|
|
|
|
|
department_allocations = merged_allocations.groupby("department_id").agg({ |
|
"allocation_amount": "sum" |
|
}).reset_index() |
|
|
|
|
|
department_efficiency = pd.merge( |
|
department_efficiency, |
|
department_allocations, |
|
left_on="id", |
|
right_on="department_id", |
|
how="left" |
|
) |
|
|
|
|
|
department_efficiency["allocation_amount"] = department_efficiency["allocation_amount"].fillna(0) |
|
department_efficiency["نسبة التغطية"] = department_efficiency["allocation_amount"] / department_efficiency["annual_cost"] * 100 |
|
department_efficiency["تكلفة الموظف السنوية"] = department_efficiency["annual_cost"] / department_efficiency["staff_count"] |
|
department_efficiency["تخصيص الموظف"] = department_efficiency["allocation_amount"] / department_efficiency["staff_count"] |
|
department_efficiency["مؤشر الكفاءة"] = department_efficiency["تخصيص الموظف"] / department_efficiency["تكلفة الموظف السنوية"] * 100 |
|
|
|
|
|
efficiency_display = department_efficiency[["name", "category", "annual_cost", "staff_count", "allocation_amount", "نسبة التغطية", "تكلفة الموظف السنوية", "تخصيص الموظف", "مؤشر الكفاءة"]].copy() |
|
efficiency_display.columns = ["الإدارة", "الفئة", "التكلفة السنوية", "عدد الموظفين", "التخصيصات", "نسبة التغطية", "تكلفة الموظف السنوية", "تخصيص الموظف", "مؤشر الكفاءة"] |
|
|
|
|
|
efficiency_display = efficiency_display.sort_values(by="مؤشر الكفاءة", ascending=False) |
|
|
|
|
|
st.dataframe(efficiency_display, use_container_width=True) |
|
|
|
|
|
fig = px.bar( |
|
efficiency_display, |
|
x="الإدارة", |
|
y="مؤشر الكفاءة", |
|
title="مؤشر كفاءة الإدارات المساندة", |
|
color="الفئة", |
|
text_auto=True |
|
) |
|
|
|
|
|
fig.add_shape( |
|
type="line", |
|
x0=-0.5, |
|
y0=100, |
|
x1=len(efficiency_display) - 0.5, |
|
y1=100, |
|
line=dict( |
|
color="red", |
|
width=2, |
|
dash="dash" |
|
) |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
fig = px.scatter( |
|
efficiency_display, |
|
x="عدد الموظفين", |
|
y="مؤشر الكفاءة", |
|
title="العلاقة بين عدد الموظفين ومؤشر الكفاءة", |
|
color="الفئة", |
|
size="التكلفة السنوية", |
|
hover_data=["الإدارة"], |
|
trendline="ols" |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
fig = px.scatter( |
|
efficiency_display, |
|
x="تكلفة الموظف السنوية", |
|
y="مؤشر الكفاءة", |
|
title="العلاقة بين تكلفة الموظف السنوية ومؤشر الكفاءة", |
|
color="الفئة", |
|
size="عدد الموظفين", |
|
hover_data=["الإدارة"], |
|
trendline="ols" |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
category_efficiency = efficiency_display.groupby("الفئة").agg({ |
|
"التكلفة السنوية": "sum", |
|
"عدد الموظفين": "sum", |
|
"التخصيصات": "sum", |
|
"مؤشر الكفاءة": "mean" |
|
}).reset_index() |
|
|
|
category_efficiency["نسبة التغطية"] = category_efficiency["التخصيصات"] / category_efficiency["التكلفة السنوية"] * 100 |
|
category_efficiency["تكلفة الموظف السنوية"] = category_efficiency["التكلفة السنوية"] / category_efficiency["عدد الموظفين"] |
|
|
|
|
|
st.dataframe(category_efficiency, use_container_width=True) |
|
|
|
|
|
fig = px.bar( |
|
category_efficiency, |
|
x="الفئة", |
|
y="مؤشر الكفاءة", |
|
title="متوسط مؤشر كفاءة الإدارات المساندة حسب الفئة", |
|
color="الفئة", |
|
text_auto=True |
|
) |
|
|
|
|
|
fig.add_shape( |
|
type="line", |
|
x0=-0.5, |
|
y0=100, |
|
x1=len(category_efficiency) - 0.5, |
|
y1=100, |
|
line=dict( |
|
color="red", |
|
width=2, |
|
dash="dash" |
|
) |
|
) |
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
st.markdown("#### توصيات لتحسين الكفاءة") |
|
|
|
|
|
low_efficiency_departments = efficiency_display[efficiency_display["مؤشر الكفاءة"] < 80].sort_values(by="مؤشر الكفاءة") |
|
|
|
if not low_efficiency_departments.empty: |
|
st.markdown("##### الإدارات ذات الكفاءة المنخفضة") |
|
|
|
for _, row in low_efficiency_departments.iterrows(): |
|
st.markdown(f"**{row['الإدارة']} (مؤشر الكفاءة: {row['مؤشر الكفاءة']:.2f}%):**") |
|
|
|
if row["نسبة التغطية"] < 80: |
|
st.markdown("- زيادة التخصيصات للإدارة من خلال مراجعة طريقة التخصيص") |
|
|
|
if row["تكلفة الموظف السنوية"] > category_efficiency[category_efficiency["الفئة"] == row["الفئة"]]["تكلفة الموظف السنوية"].values[0]: |
|
st.markdown("- مراجعة تكلفة الموظفين في الإدارة") |
|
|
|
st.markdown("- تحسين إنتاجية الإدارة من خلال تطوير العمليات وأتمتة الأعمال") |
|
st.markdown("- مراجعة عدد الموظفين في الإدارة") |
|
|
|
st.markdown("---") |
|
else: |
|
st.success("جميع الإدارات تتمتع بمستوى كفاءة جيد (أكثر من 80%)") |
|
|
|
|
|
high_efficiency_departments = efficiency_display[efficiency_display["مؤشر الكفاءة"] > 120].sort_values(by="مؤشر الكفاءة", ascending=False) |
|
|
|
if not high_efficiency_departments.empty: |
|
st.markdown("##### الإدارات ذات الكفاءة العالية") |
|
|
|
for _, row in high_efficiency_departments.iterrows(): |
|
st.markdown(f"**{row['الإدارة']} (مؤشر الكفاءة: {row['مؤشر الكفاءة']:.2f}%):**") |
|
|
|
if row["نسبة التغطية"] > 120: |
|
st.markdown("- مراجعة طريقة التخصيص للتأكد من عدم المبالغة في التخصيصات") |
|
|
|
st.markdown("- دراسة أسباب ارتفاع الكفاءة والاستفادة منها في تطوير الإدارات الأخرى") |
|
st.markdown("- تقييم جودة الخدمات المقدمة للتأكد من عدم تأثرها بارتفاع الكفاءة") |
|
|
|
st.markdown("---") |
|
|
|
|
|
st.markdown("##### توصيات عامة لتحسين كفاءة الإدارات المساندة") |
|
|
|
st.markdown("1. مراجعة طرق تخصيص تكاليف الإدارات المساندة للمشاريع") |
|
st.markdown("2. تطوير نظام لقياس أداء الإدارات المساندة") |
|
st.markdown("3. تحسين عمليات الإدارات المساندة من خلال أتمتة الأعمال") |
|
st.markdown("4. تطوير برامج تدريبية لرفع كفاءة الموظفين") |
|
st.markdown("5. مراجعة الهيكل التنظيمي للإدارات المساندة") |
|
st.markdown("6. تطبيق مبادئ الإدارة الرشيقة (Lean Management) في الإدارات المساندة") |
|
st.markdown("7. تحسين التنسيق بين الإدارات المساندة والمشاريع") |
|
|
|
def calculate_project_indirect_cost(self, project_id): |
|
"""حساب تكلفة الإدارات المساندة لمشروع معين""" |
|
|
|
|
|
allocations = st.session_state.indirect_support["allocations"] |
|
|
|
|
|
project_allocations = allocations[allocations["project_id"] == project_id] |
|
|
|
if not project_allocations.empty: |
|
return project_allocations["allocation_amount"].sum() |
|
|
|
return 0 |
|
|
|
def calculate_department_allocations(self, department_id): |
|
"""حساب تخصيصات إدارة معينة""" |
|
|
|
|
|
allocations = st.session_state.indirect_support["allocations"] |
|
|
|
|
|
department_allocations = allocations[allocations["department_id"] == department_id] |
|
|
|
if not department_allocations.empty: |
|
return department_allocations["allocation_amount"].sum() |
|
|
|
return 0 |
|
|
|
def get_department_by_id(self, department_id): |
|
"""الحصول على إدارة بواسطة الكود""" |
|
|
|
|
|
departments = st.session_state.indirect_support["departments"] |
|
|
|
|
|
department = departments[departments["id"] == department_id] |
|
|
|
if not department.empty: |
|
return department.iloc[0].to_dict() |
|
|
|
return None |
|
|
|
def get_project_by_id(self, project_id): |
|
"""الحصول على مشروع بواسطة الكود""" |
|
|
|
|
|
projects = st.session_state.indirect_support["projects"] |
|
|
|
|
|
project = projects[projects["id"] == project_id] |
|
|
|
if not project.empty: |
|
return project.iloc[0].to_dict() |
|
|
|
return None |
|
|