v3 / modules /pricing /construction_calculator.py
EGYADMIN's picture
Upload 115 files
82676b8 verified
"""
حاسبة تكاليف البناء المتكاملة
تتضمن العناصر التالية:
- المواد الخام
- المعدات
- العمالة
- المصاريف الإدارية
- هامش الربح
"""
import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
def render_construction_calculator():
"""
عرض حاسبة تكاليف البناء المتكاملة
"""
# التأكد من وجود المتغيرات في حالة الجلسة
if 'materials_cost' not in st.session_state:
st.session_state.materials_cost = 0.0
if 'equipment_cost' not in st.session_state:
st.session_state.equipment_cost = 0.0
if 'labor_cost' not in st.session_state:
st.session_state.labor_cost = 0.0
if 'admin_cost' not in st.session_state:
st.session_state.admin_cost = 0.0
if 'profit_margin' not in st.session_state:
st.session_state.profit_margin = 15.0
st.markdown("<h2 class='module-title'>حاسبة تكاليف البناء المتكاملة</h2>", unsafe_allow_html=True)
# معلومات المشروع
st.markdown("<h3>معلومات المشروع</h3>", unsafe_allow_html=True)
col1, col2 = st.columns(2)
with col1:
project_name = st.text_input("اسم المشروع", "مشروع سكني")
project_location = st.text_input("موقع المشروع", "الرياض - حي النرجس")
with col2:
project_area = st.number_input("المساحة الإجمالية (م²)", min_value=1, value=500)
project_type = st.selectbox(
"نوع المشروع",
options=[
"سكني", "تجاري", "صناعي", "إداري", "صحي", "تعليمي",
"بنية تحتية", "طرق", "جسور", "أخرى"
]
)
# التبويبات الرئيسية للحاسبة
tabs = st.tabs([
"المواد الخام", "المعدات", "العمالة", "المصاريف الإدارية", "هامش الربح", "التقرير النهائي"
])
# تعريف المتغيرات العامة
if "materials_cost" not in st.session_state:
st.session_state.materials_cost = 0.0
if "equipment_cost" not in st.session_state:
st.session_state.equipment_cost = 0.0
if "labor_cost" not in st.session_state:
st.session_state.labor_cost = 0.0
if "admin_cost" not in st.session_state:
st.session_state.admin_cost = 0.0
if "profit_margin" not in st.session_state:
st.session_state.profit_margin = 10.0
if "materials" not in st.session_state:
st.session_state.materials = []
if "equipment" not in st.session_state:
st.session_state.equipment = []
if "labor" not in st.session_state:
st.session_state.labor = []
if "admin_expenses" not in st.session_state:
st.session_state.admin_expenses = []
# تبويب المواد الخام
with tabs[0]:
render_materials_tab()
# تبويب المعدات
with tabs[1]:
render_equipment_tab()
# تبويب العمالة
with tabs[2]:
render_labor_tab()
# تبويب المصاريف الإدارية
with tabs[3]:
render_admin_tab()
# تبويب هامش الربح
with tabs[4]:
render_profit_tab()
# تبويب التقرير النهائي
with tabs[5]:
render_final_report(project_name, project_location, project_area, project_type)
def render_materials_tab():
"""
عرض تبويب المواد الخام
"""
st.markdown("<h3>تكاليف المواد الخام</h3>", unsafe_allow_html=True)
# إضافة مادة جديدة
st.markdown("<h4>إضافة مادة جديدة</h4>", unsafe_allow_html=True)
col1, col2, col3, col4 = st.columns(4)
with col1:
material_name = st.text_input("اسم المادة", key="new_material_name")
with col2:
material_quantity = st.number_input("الكمية", min_value=0.0, step=0.1, key="new_material_quantity")
with col3:
material_unit = st.selectbox(
"الوحدة",
options=["م²", "م³", "طن", "كجم", "لتر", "قطعة", "لفة", "كيس", "أخرى"],
key="new_material_unit"
)
with col4:
material_price = st.number_input("السعر للوحدة (ريال)", min_value=0.0, step=0.01, key="new_material_price")
if st.button("إضافة مادة", key="add_material_btn"):
total_price = material_quantity * material_price
new_material = {
"name": material_name,
"quantity": material_quantity,
"unit": material_unit,
"price": material_price,
"total": total_price
}
st.session_state.materials.append(new_material)
st.success(f"تمت إضافة {material_name} بنجاح!")
# عرض قائمة المواد المضافة
if st.session_state.materials:
st.markdown("<h4>قائمة المواد المضافة</h4>", unsafe_allow_html=True)
materials_df = pd.DataFrame(st.session_state.materials)
materials_df.columns = ["اسم المادة", "الكمية", "الوحدة", "السعر للوحدة", "التكلفة الإجمالية"]
st.dataframe(materials_df)
total_materials_cost = sum(item["total"] for item in st.session_state.materials)
st.session_state.materials_cost = total_materials_cost
st.markdown(f"<h4>إجمالي تكلفة المواد: <span style='color:var(--primary-color)'>{total_materials_cost:,.2f} ريال</span></h4>", unsafe_allow_html=True)
# رسم بياني للمواد حسب التكلفة
if len(st.session_state.materials) > 1:
st.markdown("<h4>توزيع تكاليف المواد</h4>", unsafe_allow_html=True)
fig = px.pie(
materials_df,
values="التكلفة الإجمالية",
names="اسم المادة",
title="توزيع تكاليف المواد",
color_discrete_sequence=px.colors.sequential.Teal,
hole=0.4
)
fig.update_layout(
font=dict(family="Almarai, Arial", size=14),
margin=dict(t=50, b=50, l=20, r=20)
)
st.plotly_chart(fig, use_container_width=True)
st.markdown("---")
# استيراد بيانات المواد من ملف
st.markdown("<h4>استيراد بيانات المواد من ملف</h4>", unsafe_allow_html=True)
uploaded_file = st.file_uploader("اختر ملف Excel أو CSV", type=["xlsx", "csv"], key="materials_upload")
if uploaded_file is not None:
if uploaded_file.name.endswith('.csv'):
df = pd.read_csv(uploaded_file)
else:
df = pd.read_excel(uploaded_file)
st.success("تم استيراد البيانات بنجاح!")
st.dataframe(df)
if st.button("إضافة المواد من الملف"):
try:
# تحويل أسماء الأعمدة للمطابقة مع النظام
column_mapping = {
"المادة": "name",
"اسم المادة": "name",
"الكمية": "quantity",
"الوحدة": "unit",
"السعر": "price",
"سعر الوحدة": "price"
}
mapped_df = df.rename(columns=column_mapping)
# حساب التكلفة الإجمالية لكل مادة
for _, row in mapped_df.iterrows():
total_price = row["quantity"] * row["price"]
new_material = {
"name": row["name"],
"quantity": row["quantity"],
"unit": row["unit"],
"price": row["price"],
"total": total_price
}
st.session_state.materials.append(new_material)
st.success("تمت إضافة جميع المواد من الملف بنجاح!")
except Exception as e:
st.error(f"حدث خطأ: {str(e)}")
st.error("تأكد من أن الملف يحتوي على الأعمدة المطلوبة: اسم المادة، الكمية، الوحدة، السعر للوحدة")
def render_equipment_tab():
"""
عرض تبويب المعدات
"""
st.markdown("<h3>تكاليف المعدات</h3>", unsafe_allow_html=True)
# إضافة معدة جديدة
st.markdown("<h4>إضافة معدة جديدة</h4>", unsafe_allow_html=True)
col1, col2, col3 = st.columns(3)
with col1:
equipment_name = st.text_input("اسم المعدة", key="new_equipment_name")
with col2:
rental_type = st.selectbox(
"نوع الإيجار",
options=["يومي", "أسبوعي", "شهري", "سنوي", "مملوكة (استهلاك)"],
key="rental_type"
)
with col3:
usage_period = st.number_input(f"مدة الاستخدام ({rental_type})", min_value=1, value=1, key="usage_period")
col4, col5, col6 = st.columns(3)
with col4:
equipment_rate = st.number_input(f"سعر الإيجار لكل ({rental_type}) (ريال)", min_value=0.0, step=0.01, key="equipment_rate")
with col5:
fuel_cost = st.number_input("تكلفة الوقود اليومية (ريال)", min_value=0.0, step=0.01, key="fuel_cost")
with col6:
operator_cost = st.number_input("تكلفة المشغل اليومية (ريال)", min_value=0.0, step=0.01, key="operator_cost")
# حساب إجمالي التكلفة
rental_days = {
"يومي": 1,
"أسبوعي": 7,
"شهري": 30,
"سنوي": 365,
"مملوكة (استهلاك)": 1
}
total_days = usage_period * rental_days[rental_type]
total_equipment_cost = equipment_rate * usage_period
total_fuel_cost = fuel_cost * total_days
total_operator_cost = operator_cost * total_days
total_cost = total_equipment_cost + total_fuel_cost + total_operator_cost
if st.button("إضافة معدة", key="add_equipment_btn"):
new_equipment = {
"name": equipment_name,
"rental_type": rental_type,
"usage_period": usage_period,
"equipment_rate": equipment_rate,
"fuel_cost": fuel_cost,
"operator_cost": operator_cost,
"total": total_cost
}
st.session_state.equipment.append(new_equipment)
st.success(f"تمت إضافة {equipment_name} بنجاح!")
# عرض تفاصيل الحساب
st.markdown("<div class='card' style='margin-top: 10px;'>", unsafe_allow_html=True)
st.markdown(f"<p>عدد أيام الاستخدام الإجمالية: {total_days} يوم</p>", unsafe_allow_html=True)
st.markdown(f"<p>تكلفة إيجار المعدة: {total_equipment_cost:,.2f} ريال</p>", unsafe_allow_html=True)
st.markdown(f"<p>تكلفة الوقود: {total_fuel_cost:,.2f} ريال</p>", unsafe_allow_html=True)
st.markdown(f"<p>تكلفة المشغل: {total_operator_cost:,.2f} ريال</p>", unsafe_allow_html=True)
st.markdown(f"<h4>التكلفة الإجمالية للمعدة: {total_cost:,.2f} ريال</h4>", unsafe_allow_html=True)
st.markdown("</div>", unsafe_allow_html=True)
# عرض قائمة المعدات المضافة
if st.session_state.equipment:
st.markdown("<h4>قائمة المعدات المضافة</h4>", unsafe_allow_html=True)
equipment_data = []
for item in st.session_state.equipment:
equipment_data.append({
"اسم المعدة": item["name"],
"نوع الإيجار": item["rental_type"],
"مدة الاستخدام": item["usage_period"],
"إيجار الوحدة": item["equipment_rate"],
"تكلفة الوقود": item["fuel_cost"],
"تكلفة المشغل": item["operator_cost"],
"التكلفة الإجمالية": item["total"]
})
equipment_df = pd.DataFrame(equipment_data)
st.dataframe(equipment_df)
total_equipment_cost = sum(item["total"] for item in st.session_state.equipment)
st.session_state.equipment_cost = total_equipment_cost
st.markdown(f"<h4>إجمالي تكلفة المعدات: <span style='color:var(--primary-color)'>{total_equipment_cost:,.2f} ريال</span></h4>", unsafe_allow_html=True)
# رسم بياني للمعدات حسب التكلفة
if len(st.session_state.equipment) > 1:
st.markdown("<h4>توزيع تكاليف المعدات</h4>", unsafe_allow_html=True)
fig = go.Figure()
fig.add_trace(go.Bar(
x=[item["اسم المعدة"] for item in equipment_data],
y=[item["التكلفة الإجمالية"] for item in equipment_data],
name="التكلفة الإجمالية",
marker_color="teal"
))
fig.update_layout(
title="تكاليف المعدات",
xaxis_title="المعدة",
yaxis_title="التكلفة (ريال)",
font=dict(family="Almarai, Arial", size=14),
margin=dict(t=50, b=50, l=20, r=20)
)
st.plotly_chart(fig, use_container_width=True)
def render_labor_tab():
"""
عرض تبويب العمالة
"""
st.markdown("<h3>تكاليف العمالة</h3>", unsafe_allow_html=True)
# إضافة عامل أو مجموعة عمال
st.markdown("<h4>إضافة عمالة جديدة</h4>", unsafe_allow_html=True)
col1, col2, col3 = st.columns(3)
with col1:
labor_type = st.text_input("نوع العمالة", key="new_labor_type")
with col2:
labor_count = st.number_input("العدد", min_value=1, value=1, key="new_labor_count")
with col3:
payment_type = st.selectbox(
"نوع الدفع",
options=["يومي", "أسبوعي", "شهري", "بالقطعة"],
key="new_payment_type"
)
col4, col5, col6 = st.columns(3)
with col4:
wage_rate = st.number_input(f"الأجرة ({payment_type}) (ريال)", min_value=0.0, step=0.01, key="new_wage_rate")
with col5:
work_period = st.number_input(f"مدة العمل ({payment_type})", min_value=1, value=30, key="new_work_period")
with col6:
benefits_percent = st.slider("نسبة البدلات والتأمين (%)", min_value=0, max_value=50, value=15, key="new_benefits_percent")
# حساب إجمالي التكلفة
days_factor = {
"يومي": 1,
"أسبوعي": 7,
"شهري": 30,
"بالقطعة": 1
}
monthly_days = work_period * days_factor[payment_type] / 30 # تحويل الأيام إلى شهور
if payment_type == "بالقطعة":
total_labor_cost = labor_count * wage_rate * work_period
else:
# حساب الراتب الشهري
monthly_wage = wage_rate * 30 / days_factor[payment_type]
# حساب تكلفة البدلات والتأمين
benefits_cost = monthly_wage * (benefits_percent / 100)
# إجمالي التكلفة الشهرية
monthly_total_cost = monthly_wage + benefits_cost
# إجمالي التكلفة
total_labor_cost = labor_count * monthly_total_cost * monthly_days
if st.button("إضافة عمالة"):
new_labor = {
"type": labor_type,
"count": labor_count,
"payment_type": payment_type,
"wage_rate": wage_rate,
"work_period": work_period,
"benefits_percent": benefits_percent,
"total": total_labor_cost
}
st.session_state.labor.append(new_labor)
st.success(f"تمت إضافة {labor_type} بنجاح!")
# عرض تفاصيل الحساب
st.markdown("<div class='card' style='margin-top: 10px;'>", unsafe_allow_html=True)
if payment_type != "بالقطعة":
monthly_wage = wage_rate * 30 / days_factor[payment_type]
benefits_cost = monthly_wage * (benefits_percent / 100)
monthly_total_cost = monthly_wage + benefits_cost
st.markdown(f"<p>الراتب الشهري للعامل: {monthly_wage:,.2f} ريال</p>", unsafe_allow_html=True)
st.markdown(f"<p>تكلفة البدلات والتأمين الشهرية: {benefits_cost:,.2f} ريال</p>", unsafe_allow_html=True)
st.markdown(f"<p>إجمالي التكلفة الشهرية للعامل: {monthly_total_cost:,.2f} ريال</p>", unsafe_allow_html=True)
st.markdown(f"<p>مدة العمل بالشهور: {monthly_days:.2f} شهر</p>", unsafe_allow_html=True)
else:
st.markdown(f"<p>سعر القطعة: {wage_rate:,.2f} ريال</p>", unsafe_allow_html=True)
st.markdown(f"<p>عدد القطع: {work_period}</p>", unsafe_allow_html=True)
st.markdown(f"<p>عدد العمال: {labor_count}</p>", unsafe_allow_html=True)
st.markdown(f"<h4>التكلفة الإجمالية للعمالة: {total_labor_cost:,.2f} ريال</h4>", unsafe_allow_html=True)
st.markdown("</div>", unsafe_allow_html=True)
# عرض قائمة العمالة المضافة
if st.session_state.labor:
st.markdown("<h4>قائمة العمالة المضافة</h4>", unsafe_allow_html=True)
labor_data = []
for item in st.session_state.labor:
labor_data.append({
"نوع العمالة": item["type"],
"العدد": item["count"],
"نوع الدفع": item["payment_type"],
"معدل الأجرة": item["wage_rate"],
"مدة العمل": item["work_period"],
"نسبة البدلات": f"{item['benefits_percent']}%",
"التكلفة الإجمالية": item["total"]
})
labor_df = pd.DataFrame(labor_data)
st.dataframe(labor_df)
total_labor_cost = sum(item["total"] for item in st.session_state.labor)
st.session_state.labor_cost = total_labor_cost
st.markdown(f"<h4>إجمالي تكلفة العمالة: <span style='color:var(--primary-color)'>{total_labor_cost:,.2f} ريال</span></h4>", unsafe_allow_html=True)
# رسم بياني للعمالة حسب التكلفة
if len(st.session_state.labor) > 1:
st.markdown("<h4>توزيع تكاليف العمالة</h4>", unsafe_allow_html=True)
fig = px.bar(
labor_df,
x="نوع العمالة",
y="التكلفة الإجمالية",
color="العدد",
title="توزيع تكاليف العمالة",
color_continuous_scale=px.colors.sequential.Teal
)
fig.update_layout(
font=dict(family="Almarai, Arial", size=14),
margin=dict(t=50, b=50, l=20, r=20)
)
st.plotly_chart(fig, use_container_width=True)
def render_admin_tab():
"""
عرض تبويب المصاريف الإدارية
"""
st.markdown("<h3>المصاريف الإدارية والعمومية</h3>", unsafe_allow_html=True)
# إضافة مصروف جديد
st.markdown("<h4>إضافة مصروف جديد</h4>", unsafe_allow_html=True)
col1, col2, col3 = st.columns(3)
with col1:
expense_name = st.text_input("اسم المصروف", key="new_expense_name")
with col2:
expense_type = st.selectbox(
"نوع المصروف",
options=[
"رواتب إدارية", "إيجارات", "مكتبية", "سفر", "تأمين",
"استشارات", "رسوم حكومية", "منافع", "أخرى"
],
key="new_expense_type"
)
with col3:
expense_amount = st.number_input("المبلغ (ريال)", min_value=0.0, step=100.0, key="new_expense_amount")
if st.button("إضافة مصروف"):
new_expense = {
"name": expense_name,
"type": expense_type,
"amount": expense_amount
}
st.session_state.admin_expenses.append(new_expense)
st.success(f"تمت إضافة {expense_name} بنجاح!")
# عرض قائمة المصاريف المضافة
if st.session_state.admin_expenses:
st.markdown("<h4>قائمة المصاريف الإدارية</h4>", unsafe_allow_html=True)
admin_data = []
for item in st.session_state.admin_expenses:
admin_data.append({
"اسم المصروف": item["name"],
"نوع المصروف": item["type"],
"المبلغ": item["amount"]
})
admin_df = pd.DataFrame(admin_data)
st.dataframe(admin_df)
total_admin_cost = sum(item["amount"] for item in st.session_state.admin_expenses)
st.session_state.admin_cost = total_admin_cost
st.markdown(f"<h4>إجمالي المصاريف الإدارية: <span style='color:var(--primary-color)'>{total_admin_cost:,.2f} ريال</span></h4>", unsafe_allow_html=True)
# رسم بياني للمصاريف حسب النوع
if len(st.session_state.admin_expenses) > 1:
st.markdown("<h4>توزيع المصاريف الإدارية حسب النوع</h4>", unsafe_allow_html=True)
# تجميع المصاريف حسب النوع
expense_by_type = admin_df.groupby("نوع المصروف")["المبلغ"].sum().reset_index()
fig = px.pie(
expense_by_type,
values="المبلغ",
names="نوع المصروف",
title="توزيع المصاريف الإدارية",
color_discrete_sequence=px.colors.sequential.Teal,
hole=0.4
)
fig.update_layout(
font=dict(family="Almarai, Arial", size=14),
margin=dict(t=50, b=50, l=20, r=20)
)
st.plotly_chart(fig, use_container_width=True)
# نسبة المصاريف الإدارية
st.markdown("<h4>احتساب المصاريف الإدارية بالنسبة المئوية</h4>", unsafe_allow_html=True)
# حساب التكاليف المباشرة
direct_costs = st.session_state.materials_cost + st.session_state.equipment_cost + st.session_state.labor_cost
col1, col2 = st.columns(2)
with col1:
admin_percent = st.slider("نسبة المصاريف الإدارية من التكاليف المباشرة (%)", min_value=0, max_value=30, value=10, key="admin_percent")
with col2:
calculated_admin_cost = direct_costs * (admin_percent / 100)
st.markdown(f"<div class='card'><h4>المصاريف الإدارية بالنسبة: <span style='color:var(--primary-color)'>{calculated_admin_cost:,.2f} ريال</span></h4></div>", unsafe_allow_html=True)
if st.button("استخدام النسبة المئوية للمصاريف الإدارية"):
st.session_state.admin_cost = calculated_admin_cost
st.success("تم تحديث إجمالي المصاريف الإدارية بناء على النسبة المئوية!")
def render_profit_tab():
"""
عرض تبويب هامش الربح
"""
st.markdown("<h3>هامش الربح</h3>", unsafe_allow_html=True)
# حساب التكاليف المباشرة والإجمالية
direct_costs = st.session_state.materials_cost + st.session_state.equipment_cost + st.session_state.labor_cost
total_costs = direct_costs + st.session_state.admin_cost
# عرض ملخص التكاليف
st.markdown("<div class='card'>", unsafe_allow_html=True)
st.markdown("<h4>ملخص التكاليف</h4>", unsafe_allow_html=True)
st.markdown(f"<p>إجمالي تكلفة المواد: <span style='color:var(--text-medium)'>{st.session_state.materials_cost:,.2f} ريال</span></p>", unsafe_allow_html=True)
st.markdown(f"<p>إجمالي تكلفة المعدات: <span style='color:var(--text-medium)'>{st.session_state.equipment_cost:,.2f} ريال</span></p>", unsafe_allow_html=True)
st.markdown(f"<p>إجمالي تكلفة العمالة: <span style='color:var(--text-medium)'>{st.session_state.labor_cost:,.2f} ريال</span></p>", unsafe_allow_html=True)
st.markdown(f"<p>إجمالي التكاليف المباشرة: <span style='color:var(--primary-color)'>{direct_costs:,.2f} ريال</span></p>", unsafe_allow_html=True)
st.markdown(f"<p>إجمالي المصاريف الإدارية: <span style='color:var(--text-medium)'>{st.session_state.admin_cost:,.2f} ريال</span></p>", unsafe_allow_html=True)
st.markdown(f"<h4>إجمالي التكاليف: <span style='color:var(--primary-color)'>{total_costs:,.2f} ريال</span></h4>", unsafe_allow_html=True)
st.markdown("</div>", unsafe_allow_html=True)
# تحديد هامش الربح
st.markdown("<h4>تحديد هامش الربح</h4>", unsafe_allow_html=True)
col1, col2 = st.columns(2)
with col1:
profit_margin = st.slider("نسبة هامش الربح (%)", min_value=0, max_value=30, value=int(st.session_state.profit_margin), key="profit_margin_slider")
st.session_state.profit_margin = profit_margin
with col2:
profit_amount = total_costs * (profit_margin / 100)
st.markdown(f"<div class='card'><h4>قيمة هامش الربح: <span style='color:var(--primary-color)'>{profit_amount:,.2f} ريال</span></h4></div>", unsafe_allow_html=True)
# إجمالي قيمة العرض
total_price = total_costs + profit_amount
st.markdown("<div class='card' style='background: var(--primary-light);'>", unsafe_allow_html=True)
st.markdown(f"<h3>إجمالي قيمة العرض: <span style='color:var(--primary-color)'>{total_price:,.2f} ريال</span></h3>", unsafe_allow_html=True)
st.markdown("</div>", unsafe_allow_html=True)
# تحليل الحساسية لهامش الربح
st.markdown("<h4>تحليل حساسية هامش الربح</h4>", unsafe_allow_html=True)
sensitivity_data = []
for margin in range(5, 31, 5):
profit = total_costs * (margin / 100)
total = total_costs + profit
sensitivity_data.append({
"نسبة الربح": f"{margin}%",
"قيمة الربح": profit,
"إجمالي العرض": total
})
sensitivity_df = pd.DataFrame(sensitivity_data)
# رسم بياني لتحليل الحساسية
fig = go.Figure()
fig.add_trace(go.Bar(
x=[item["نسبة الربح"] for item in sensitivity_data],
y=[item["قيمة الربح"] for item in sensitivity_data],
name="قيمة الربح",
marker_color="rgba(14, 165, 165, 0.7)"
))
fig.add_trace(go.Scatter(
x=[item["نسبة الربح"] for item in sensitivity_data],
y=[item["إجمالي العرض"] for item in sensitivity_data],
name="إجمالي العرض",
mode="lines+markers",
marker=dict(size=8, color="rgba(255, 154, 60, 1.0)"),
line=dict(width=3, color="rgba(255, 154, 60, 0.7)")
))
fig.update_layout(
title="تحليل حساسية هامش الربح",
xaxis_title="نسبة الربح",
yaxis_title="القيمة (ريال)",
font=dict(family="Almarai, Arial", size=14),
margin=dict(t=50, b=50, l=20, r=20),
hovermode="x unified"
)
st.plotly_chart(fig, use_container_width=True)
# جدول تحليل الحساسية
st.dataframe(sensitivity_df)
def render_final_report(project_name, project_location, project_area, project_type):
"""
عرض التقرير النهائي للتكاليف
"""
st.markdown("<h3>التقرير النهائي لتكاليف المشروع</h3>", unsafe_allow_html=True)
# التأكد من وجود المتغيرات المطلوبة في حالة الجلسة وضمان أن لديهم قيم صحيحة
required_fields = {
'materials_cost': 0.0,
'equipment_cost': 0.0,
'labor_cost': 0.0,
'admin_cost': 0.0,
'profit_margin': 15.0,
'materials': [],
'equipment': [],
'labor': [],
'admin_expenses': []
}
# مرور على كافة الحقول المطلوبة للتأكد من وجودها
for field, default_value in required_fields.items():
if field not in st.session_state:
st.session_state[field] = default_value
# التحقق من أن القيم العددية صالحة (غير None وليست NaN)
if field in ['materials_cost', 'equipment_cost', 'labor_cost', 'admin_cost', 'profit_margin']:
# إذا كانت القيمة None أو NaN، استخدم القيمة الافتراضية
if st.session_state[field] is None or pd.isna(st.session_state[field]):
st.session_state[field] = default_value
# حساب التكاليف المباشرة والإجمالية
direct_costs = st.session_state.materials_cost + st.session_state.equipment_cost + st.session_state.labor_cost
total_costs = direct_costs + st.session_state.admin_cost
profit_amount = total_costs * (st.session_state.profit_margin / 100)
total_price = total_costs + profit_amount
# معلومات المشروع
st.markdown("<div class='card'>", unsafe_allow_html=True)
st.markdown("<h4>معلومات المشروع</h4>", unsafe_allow_html=True)
col1, col2 = st.columns(2)
with col1:
st.markdown(f"<p><strong>اسم المشروع:</strong> {project_name}</p>", unsafe_allow_html=True)
st.markdown(f"<p><strong>نوع المشروع:</strong> {project_type}</p>", unsafe_allow_html=True)
with col2:
st.markdown(f"<p><strong>موقع المشروع:</strong> {project_location}</p>", unsafe_allow_html=True)
st.markdown(f"<p><strong>المساحة الإجمالية:</strong> {project_area} م²</p>", unsafe_allow_html=True)
st.markdown("</div>", unsafe_allow_html=True)
# ملخص التكاليف
st.markdown("<div class='card'>", unsafe_allow_html=True)
st.markdown("<h4>ملخص التكاليف</h4>", unsafe_allow_html=True)
col1, col2 = st.columns(2)
with col1:
st.markdown(f"<p><strong>تكلفة المواد:</strong> {st.session_state.materials_cost:,.2f} ريال</p>", unsafe_allow_html=True)
st.markdown(f"<p><strong>تكلفة المعدات:</strong> {st.session_state.equipment_cost:,.2f} ريال</p>", unsafe_allow_html=True)
st.markdown(f"<p><strong>تكلفة العمالة:</strong> {st.session_state.labor_cost:,.2f} ريال</p>", unsafe_allow_html=True)
st.markdown(f"<p><strong>إجمالي التكاليف المباشرة:</strong> {direct_costs:,.2f} ريال</p>", unsafe_allow_html=True)
with col2:
st.markdown(f"<p><strong>المصاريف الإدارية:</strong> {st.session_state.admin_cost:,.2f} ريال</p>", unsafe_allow_html=True)
st.markdown(f"<p><strong>إجمالي التكاليف:</strong> {total_costs:,.2f} ريال</p>", unsafe_allow_html=True)
st.markdown(f"<p><strong>هامش الربح ({st.session_state.profit_margin}%):</strong> {profit_amount:,.2f} ريال</p>", unsafe_allow_html=True)
st.markdown(f"<h4>إجمالي قيمة العرض: {total_price:,.2f} ريال</h4>", unsafe_allow_html=True)
st.markdown("</div>", unsafe_allow_html=True)
# عرض التفاصيل بالمتر المربع
if project_area > 0:
per_sqm_cost = total_price / project_area
st.markdown("<div class='card'>", unsafe_allow_html=True)
st.markdown("<h4>تكلفة المتر المربع</h4>", unsafe_allow_html=True)
st.markdown(f"<p>تكلفة المتر المربع الإجمالية: <strong>{per_sqm_cost:,.2f} ريال/م²</strong></p>", unsafe_allow_html=True)
st.markdown("</div>", unsafe_allow_html=True)
else:
st.markdown("<div class='card'>", unsafe_allow_html=True)
st.markdown("<h4>تكلفة المتر المربع</h4>", unsafe_allow_html=True)
st.markdown("<p>يرجى إدخال مساحة صحيحة للمشروع لحساب تكلفة المتر المربع</p>", unsafe_allow_html=True)
st.markdown("</div>", unsafe_allow_html=True)
# رسم بياني لتوزيع التكاليف
st.markdown("<h4>توزيع التكاليف</h4>", unsafe_allow_html=True)
# تجنب القسمة على صفر
if total_price > 0:
cost_distribution = [
{"النوع": "المواد", "القيمة": st.session_state.materials_cost, "النسبة": st.session_state.materials_cost / total_price * 100},
{"النوع": "المعدات", "القيمة": st.session_state.equipment_cost, "النسبة": st.session_state.equipment_cost / total_price * 100},
{"النوع": "العمالة", "القيمة": st.session_state.labor_cost, "النسبة": st.session_state.labor_cost / total_price * 100},
{"النوع": "المصاريف الإدارية", "القيمة": st.session_state.admin_cost, "النسبة": st.session_state.admin_cost / total_price * 100},
{"النوع": "هامش الربح", "القيمة": profit_amount, "النسبة": profit_amount / total_price * 100}
]
else:
# إذا كان المجموع صفر، اجعل جميع النسب المئوية صفر
cost_distribution = [
{"النوع": "المواد", "القيمة": st.session_state.materials_cost, "النسبة": 0},
{"النوع": "المعدات", "القيمة": st.session_state.equipment_cost, "النسبة": 0},
{"النوع": "العمالة", "القيمة": st.session_state.labor_cost, "النسبة": 0},
{"النوع": "المصاريف الإدارية", "القيمة": st.session_state.admin_cost, "النسبة": 0},
{"النوع": "هامش الربح", "القيمة": profit_amount, "النسبة": 0}
]
cost_df = pd.DataFrame(cost_distribution)
fig = px.pie(
cost_df,
values="القيمة",
names="النوع",
title="توزيع التكاليف والأرباح",
color_discrete_sequence=px.colors.sequential.Teal,
hole=0.4
)
fig.update_traces(textposition='inside', textinfo='percent+label')
fig.update_layout(
annotations=[dict(text=f"{total_price:,.0f} ريال", x=0.5, y=0.5, font_size=14, showarrow=False)],
font=dict(family="Almarai, Arial", size=14),
margin=dict(t=50, b=50, l=20, r=20)
)
st.plotly_chart(fig, use_container_width=True)
# جدول توزيع التكاليف
st.dataframe(cost_df)
# زر لإنشاء تقرير PDF
col1, col2 = st.columns(2)
with col1:
if st.button("تصدير التقرير إلى PDF"):
st.success("تم تصدير التقرير بنجاح!")
with col2:
if st.button("حفظ التقرير في قاعدة البيانات"):
st.success("تم حفظ التقرير في قاعدة البيانات بنجاح!")