v3 / modules /pricing /services /construction_cost_calculator.py
EGYADMIN's picture
Upload 115 files
82676b8 verified
"""
خدمة حاسبة تكاليف البناء
تقوم هذه الخدمة بحساب تكاليف البناء بشكل تفصيلي بناءً على المكونات المختلفة:
- المواد الخام
- العمالة
- المعدات
- المصاريف الإدارية
- هامش الربح
"""
import pandas as pd
import numpy as np
from datetime import datetime
import os
import json
import sys
from typing import Dict, List, Optional, Union, Any
# إضافة مسار النظام للوصول لملفات التكوين
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../")))
try:
import config
except ImportError:
# إذا لم يتم العثور على ملف التكوين، نستخدم قيم افتراضية
class DefaultConfig:
DATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../data"))
config = DefaultConfig
# إنشاء مجلد البيانات إذا لم يكن موجودًا
if not os.path.exists(config.DATA_DIR):
os.makedirs(config.DATA_DIR)
class ConstructionCostCalculator:
"""خدمة حاسبة تكاليف البناء"""
def __init__(self):
"""تهيئة حاسبة تكاليف البناء"""
# تحميل بيانات المواد والأسعار المرجعية
self.material_rates = self._load_material_rates()
self.labor_rates = self._load_labor_rates()
self.equipment_rates = self._load_equipment_rates()
# النسب الافتراضية للمصاريف الإدارية وهامش الربح
self.default_admin_expenses_percentage = 0.05 # 5%
self.default_profit_margin_percentage = 0.10 # 10%
# معاملات التعديل الافتراضية
self.default_adjustment_factors = {
'location_factor': 1.0, # معامل الموقع
'time_factor': 1.0, # معامل الوقت
'risk_factor': 1.0, # معامل المخاطر
'market_factor': 1.0 # معامل السوق
}
def _load_material_rates(self) -> Dict[str, Dict[str, Any]]:
"""تحميل أسعار المواد"""
# محاكاة تحميل البيانات من مصدر بيانات
material_rates = {
# مواد الخرسانة
'خرسانة جاهزة': {
'وحدة': 'م3',
'سعر_الوحدة': 750.0,
'وصف': 'خرسانة جاهزة بقوة 350 كجم/سم2',
'فئة': 'أعمال خرسانية'
},
'حديد تسليح': {
'وحدة': 'طن',
'سعر_الوحدة': 5500.0,
'وصف': 'حديد تسليح قطر 8-32 مم',
'فئة': 'أعمال خرسانية'
},
'أسمنت': {
'وحدة': 'كيس',
'سعر_الوحدة': 30.0,
'وصف': 'أسمنت بورتلاندي عادي',
'فئة': 'أعمال خرسانية'
},
'رمل': {
'وحدة': 'م3',
'سعر_الوحدة': 120.0,
'وصف': 'رمل خشن للخرسانة',
'فئة': 'أعمال خرسانية'
},
'زلط': {
'وحدة': 'م3',
'سعر_الوحدة': 150.0,
'وصف': 'زلط مقاس 10-20 مم للخرسانة',
'فئة': 'أعمال خرسانية'
},
# مواد البناء
'طوب أحمر': {
'وحدة': '1000 قطعة',
'سعر_الوحدة': 900.0,
'وصف': 'طوب أحمر مقاس 25×12×6 سم',
'فئة': 'أعمال بناء'
},
'طوب أسمنتي': {
'وحدة': 'قطعة',
'سعر_الوحدة': 4.5,
'وصف': 'بلوك أسمنتي مقاس 20×20×40 سم',
'فئة': 'أعمال بناء'
},
'مونة بناء': {
'وحدة': 'م3',
'سعر_الوحدة': 350.0,
'وصف': 'مونة أسمنتية للبناء',
'فئة': 'أعمال بناء'
},
# مواد التشطيبات
'بلاط سيراميك': {
'وحدة': 'م2',
'سعر_الوحدة': 120.0,
'وصف': 'بلاط سيراميك للأرضيات مقاس 40×40 سم',
'فئة': 'تشطيبات'
},
'بلاط بورسلين': {
'وحدة': 'م2',
'سعر_الوحدة': 180.0,
'وصف': 'بلاط بورسلين للأرضيات مقاس 60×60 سم',
'فئة': 'تشطيبات'
},
'دهانات بلاستيك': {
'وحدة': 'لتر',
'سعر_الوحدة': 35.0,
'وصف': 'دهان بلاستيك أساس وتشطيب',
'فئة': 'تشطيبات'
},
'جبس بورد': {
'وحدة': 'م2',
'سعر_الوحدة': 95.0,
'وصف': 'ألواح جبس بورد سمك 12 مم',
'فئة': 'تشطيبات'
},
# مواد العزل
'عزل مائي': {
'وحدة': 'م2',
'سعر_الوحدة': 45.0,
'وصف': 'عزل مائي من البيتومين المؤكسد',
'فئة': 'أعمال عزل'
},
'عزل حراري': {
'وحدة': 'م2',
'سعر_الوحدة': 65.0,
'وصف': 'ألواح عزل حراري من البوليسترين سمك 5 سم',
'فئة': 'أعمال عزل'
}
}
# محاولة تحميل البيانات من ملف إذا كان متاحًا
try:
file_path = os.path.join(config.DATA_DIR, 'material_rates.json')
if os.path.exists(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
loaded_data = json.load(f)
material_rates.update(loaded_data)
except Exception as e:
print(f"خطأ في تحميل بيانات أسعار المواد: {str(e)}")
return material_rates
def _load_labor_rates(self) -> Dict[str, Dict[str, Any]]:
"""تحميل أسعار العمالة"""
# محاكاة تحميل البيانات من مصدر بيانات
labor_rates = {
# عمالة الخرسانات
'نجار مسلح': {
'وحدة': 'يوم',
'سعر_الوحدة': 250.0,
'وصف': 'نجار مسلح لأعمال الشدات والفرم',
'فئة': 'أعمال خرسانية',
'إنتاجية_يومية': {
'شدة أساسات': 12, # متر مربع
'شدة أعمدة': 10, # متر مربع
'شدة أسقف': 12 # متر مربع
}
},
'حداد مسلح': {
'وحدة': 'يوم',
'سعر_الوحدة': 250.0,
'وصف': 'حداد مسلح لأعمال حديد التسليح',
'فئة': 'أعمال خرسانية',
'إنتاجية_يومية': {
'تجهيز وتركيب حديد أساسات': 700, # كجم
'تجهيز وتركيب حديد أعمدة': 600, # كجم
'تجهيز وتركيب حديد أسقف': 650 # كجم
}
},
'عامل خرسانة': {
'وحدة': 'يوم',
'سعر_الوحدة': 150.0,
'وصف': 'عامل لصب وتسوية الخرسانة',
'فئة': 'أعمال خرسانية',
'إنتاجية_يومية': {
'صب خرسانة': 15 # متر مكعب
}
},
# عمالة البناء
'بناء': {
'وحدة': 'يوم',
'سعر_الوحدة': 200.0,
'وصف': 'عامل بناء للطوب والبلوك',
'فئة': 'أعمال بناء',
'إنتاجية_يومية': {
'بناء طوب أحمر': 500, # قطعة
'بناء بلوك أسمنتي': 80 # قطعة
}
},
'مساعد بناء': {
'وحدة': 'يوم',
'سعر_الوحدة': 120.0,
'وصف': 'مساعد عامل بناء',
'فئة': 'أعمال بناء',
'إنتاجية_يومية': {}
},
# عمالة التشطيبات
'مبلط': {
'وحدة': 'يوم',
'سعر_الوحدة': 250.0,
'وصف': 'عامل تركيب بلاط وسيراميك',
'فئة': 'تشطيبات',
'إنتاجية_يومية': {
'تركيب سيراميك أرضيات': 15, # متر مربع
'تركيب سيراميك حوائط': 12, # متر مربع
'تركيب بورسلين': 12 # متر مربع
}
},
'نقاش': {
'وحدة': 'يوم',
'سعر_الوحدة': 200.0,
'وصف': 'عامل دهانات',
'فئة': 'تشطيبات',
'إنتاجية_يومية': {
'دهانات بلاستيك': 35, # متر مربع
'دهانات زيتية': 25 # متر مربع
}
},
'كهربائي': {
'وحدة': 'يوم',
'سعر_الوحدة': 270.0,
'وصف': 'فني كهرباء',
'فئة': 'تشطيبات',
'إنتاجية_يومية': {
'تأسيس نقاط كهرباء': 15, # نقطة
'تركيب لوحات توزيع': 2 # لوحة
}
},
'سباك': {
'وحدة': 'يوم',
'سعر_الوحدة': 250.0,
'وصف': 'فني سباكة',
'فئة': 'تشطيبات',
'إنتاجية_يومية': {
'تأسيس نقاط صرف': 8, # نقطة
'تأسيس نقاط تغذية': 10, # نقطة
'تركيب أطقم حمامات': 2 # طقم
}
},
# مراقبة وإشراف
'مهندس موقع': {
'وحدة': 'يوم',
'سعر_الوحدة': 500.0,
'وصف': 'مهندس إشراف موقع',
'فئة': 'إشراف'
},
'مراقب فني': {
'وحدة': 'يوم',
'سعر_الوحدة': 300.0,
'وصف': 'مراقب فني للتنفيذ',
'فئة': 'إشراف'
}
}
# محاولة تحميل البيانات من ملف إذا كان متاحًا
try:
file_path = os.path.join(config.DATA_DIR, 'labor_rates.json')
if os.path.exists(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
loaded_data = json.load(f)
labor_rates.update(loaded_data)
except Exception as e:
print(f"خطأ في تحميل بيانات أسعار العمالة: {str(e)}")
return labor_rates
def _load_equipment_rates(self) -> Dict[str, Dict[str, Any]]:
"""تحميل أسعار المعدات"""
# محاكاة تحميل البيانات من مصدر بيانات
equipment_rates = {
# معدات الحفر والتسوية
'حفار صغير': {
'وحدة': 'يوم',
'سعر_الوحدة': 1200.0,
'وصف': 'حفار صغير (بوبكات) بقدرة 70 حصان',
'فئة': 'معدات حفر',
'إنتاجية_يومية': {
'حفر في تربة عادية': 60 # متر مكعب
}
},
'حفار متوسط': {
'وحدة': 'يوم',
'سعر_الوحدة': 2500.0,
'وصف': 'حفار متوسط الحجم بقدرة 150 حصان',
'فئة': 'معدات حفر',
'إنتاجية_يومية': {
'حفر في تربة عادية': 200 # متر مكعب
}
},
'لودر': {
'وحدة': 'يوم',
'سعر_الوحدة': 2000.0,
'وصف': 'لودر أمامي لنقل التربة',
'فئة': 'معدات حفر',
'إنتاجية_يومية': {
'تحميل تربة': 300, # متر مكعب
'تسوية موقع': 1500 # متر مربع
}
},
'جريدر': {
'وحدة': 'يوم',
'سعر_الوحدة': 2200.0,
'وصف': 'جريدر لتسوية الموقع',
'فئة': 'معدات حفر',
'إنتاجية_يومية': {
'تسوية طرق': 3000 # متر مربع
}
},
# معدات الخرسانة
'خلاطة خرسانة': {
'وحدة': 'يوم',
'سعر_الوحدة': 350.0,
'وصف': 'خلاطة خرسانة بسعة 0.5 متر مكعب',
'فئة': 'معدات خرسانة',
'إنتاجية_يومية': {
'خلط خرسانة': 15 # متر مكعب
}
},
'هزاز خرسانة': {
'وحدة': 'يوم',
'سعر_الوحدة': 150.0,
'وصف': 'هزاز خرسانة كهربائي',
'فئة': 'معدات خرسانة',
'إنتاجية_يومية': {
'دمك خرسانة': 40 # متر مكعب
}
},
'شاحنة خرسانة جاهزة': {
'وحدة': 'يوم',
'سعر_الوحدة': 3000.0,
'وصف': 'شاحنة خرسانة جاهزة (مكسر) سعة 8 متر مكعب',
'فئة': 'معدات خرسانة',
'إنتاجية_يومية': {
'نقل وصب خرسانة': 50 # متر مكعب
}
},
'مضخة خرسانة': {
'وحدة': 'يوم',
'سعر_الوحدة': 5000.0,
'وصف': 'مضخة خرسانة بذراع 42 متر',
'فئة': 'معدات خرسانة',
'إنتاجية_يومية': {
'ضخ خرسانة': 120 # متر مكعب
}
},
# معدات رفع ونقل
'رافعة برجية': {
'وحدة': 'شهر',
'سعر_الوحدة': 35000.0,
'وصف': 'رافعة برجية بارتفاع 40 متر',
'فئة': 'معدات رفع',
},
'ونش شوكة': {
'وحدة': 'يوم',
'سعر_الوحدة': 1500.0,
'وصف': 'ونش شوكة لرفع مواد البناء',
'فئة': 'معدات رفع',
'إنتاجية_يومية': {
'رفع ونقل مواد': 100 # طن
}
},
'شاحنة نقل': {
'وحدة': 'يوم',
'سعر_الوحدة': 1200.0,
'وصف': 'شاحنة نقل حمولة 20 طن',
'فئة': 'معدات نقل',
'إنتاجية_يومية': {
'نقل مواد': 80 # طن
}
}
}
# محاولة تحميل البيانات من ملف إذا كان متاحًا
try:
file_path = os.path.join(config.DATA_DIR, 'equipment_rates.json')
if os.path.exists(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
loaded_data = json.load(f)
equipment_rates.update(loaded_data)
except Exception as e:
print(f"خطأ في تحميل بيانات أسعار المعدات: {str(e)}")
return equipment_rates
def calculate_item_cost(self, item_data: Dict[str, Any]) -> Dict[str, Any]:
"""
حساب تكلفة بند محدد بكافة مكوناته
المعلمات:
item_data (dict): بيانات البند، تتضمن:
- وصف_البند (str): وصف البند
- الكمية (float): كمية البند
- الوحدة (str): وحدة القياس
- المواد (list): قائمة المواد المستخدمة وكمياتها
- العمالة (list): قائمة العمالة المستخدمة وعددها
- المعدات (list): قائمة المعدات المستخدمة وساعات عملها
- المصاريف_الإدارية (float, optional): نسبة المصاريف الإدارية (افتراضياً 5%)
- هامش_الربح (float, optional): نسبة هامش الربح (افتراضياً 10%)
- عوامل_التعديل (dict, optional): عوامل تعديل التكلفة
العوائد:
dict: تفاصيل تكلفة البند بكافة عناصرها
"""
# استخراج البيانات الأساسية للبند
item_description = item_data.get('وصف_البند', 'بند غير محدد')
quantity = item_data.get('الكمية', 0.0)
unit = item_data.get('الوحدة', 'وحدة')
# حساب تكلفة المواد
materials_cost = self._calculate_materials_cost(item_data.get('المواد', []))
# حساب تكلفة العمالة
labor_cost = self._calculate_labor_cost(item_data.get('العمالة', []))
# حساب تكلفة المعدات
equipment_cost = self._calculate_equipment_cost(item_data.get('المعدات', []))
# حساب التكلفة المباشرة الإجمالية
direct_cost = materials_cost['الإجمالي'] + labor_cost['الإجمالي'] + equipment_cost['الإجمالي']
# حساب المصاريف الإدارية
admin_percentage = item_data.get('المصاريف_الإدارية', self.default_admin_expenses_percentage)
admin_cost = direct_cost * admin_percentage
# حساب هامش الربح
profit_percentage = item_data.get('هامش_الربح', self.default_profit_margin_percentage)
profit_margin = (direct_cost + admin_cost) * profit_percentage
# حساب التكلفة الإجمالية
total_cost = direct_cost + admin_cost + profit_margin
# حساب سعر الوحدة
unit_price = total_cost / quantity if quantity > 0 else 0.0
# تطبيق عوامل التعديل إذا وجدت
adjustment_factors = item_data.get('عوامل_التعديل', self.default_adjustment_factors)
adjustment_factor = self._calculate_adjustment_factor(adjustment_factors)
adjusted_unit_price = unit_price * adjustment_factor
adjusted_total_cost = total_cost * adjustment_factor
# إعداد النتائج
result = {
'وصف_البند': item_description,
'الكمية': quantity,
'الوحدة': unit,
'تكاليف_مباشرة': {
'المواد': materials_cost,
'العمالة': labor_cost,
'المعدات': equipment_cost,
'إجمالي_تكاليف_مباشرة': direct_cost
},
'مصاريف_إدارية': {
'نسبة': admin_percentage * 100,
'قيمة': admin_cost
},
'هامش_ربح': {
'نسبة': profit_percentage * 100,
'قيمة': profit_margin
},
'التكلفة_الإجمالية': total_cost,
'سعر_الوحدة': unit_price,
'عوامل_التعديل': {
'المعامل_الإجمالي': adjustment_factor,
'التفاصيل': adjustment_factors
},
'السعر_المعدل': {
'سعر_الوحدة': adjusted_unit_price,
'إجمالي': adjusted_total_cost
}
}
return result
def _calculate_materials_cost(self, materials: List[Dict[str, Any]]) -> Dict[str, Any]:
"""
حساب تكلفة المواد
المعلمات:
materials (list): قائمة المواد المستخدمة وكمياتها
- الاسم (str): اسم المادة
- الكمية (float): الكمية المستخدمة
- الوحدة (str, optional): وحدة القياس
- سعر_الوحدة (float, optional): سعر الوحدة (يستخدم السعر من البيانات المرجعية إذا لم يتم تحديده)
العوائد:
dict: تفاصيل تكلفة المواد
"""
materials_details = []
total_cost = 0.0
for material in materials:
material_name = material.get('الاسم', '')
quantity = material.get('الكمية', 0.0)
# البحث عن سعر المادة من البيانات المرجعية إذا لم يتم تحديده
if 'سعر_الوحدة' in material:
unit_price = material.get('سعر_الوحدة', 0.0)
unit = material.get('الوحدة', 'وحدة')
elif material_name in self.material_rates:
ref_material = self.material_rates[material_name]
unit_price = ref_material.get('سعر_الوحدة', 0.0)
unit = ref_material.get('وحدة', 'وحدة')
else:
unit_price = 0.0
unit = material.get('الوحدة', 'وحدة')
# حساب التكلفة
cost = quantity * unit_price
total_cost += cost
# إضافة التفاصيل
materials_details.append({
'الاسم': material_name,
'الكمية': quantity,
'الوحدة': unit,
'سعر_الوحدة': unit_price,
'التكلفة': cost
})
return {
'التفاصيل': materials_details,
'الإجمالي': total_cost
}
def _calculate_labor_cost(self, labor: List[Dict[str, Any]]) -> Dict[str, Any]:
"""
حساب تكلفة العمالة
المعلمات:
labor (list): قائمة العمالة المستخدمة وعددها
- النوع (str): نوع العامل
- العدد (int): عدد العمال
- المدة (float): مدة العمل بالأيام
- سعر_اليوم (float, optional): أجر اليوم (يستخدم السعر من البيانات المرجعية إذا لم يتم تحديده)
العوائد:
dict: تفاصيل تكلفة العمالة
"""
labor_details = []
total_cost = 0.0
for worker in labor:
worker_type = worker.get('النوع', '')
count = worker.get('العدد', 0)
duration = worker.get('المدة', 0.0)
# البحث عن سعر العامل من البيانات المرجعية إذا لم يتم تحديده
if 'سعر_اليوم' in worker:
daily_rate = worker.get('سعر_اليوم', 0.0)
elif worker_type in self.labor_rates:
daily_rate = self.labor_rates[worker_type].get('سعر_الوحدة', 0.0)
else:
daily_rate = 0.0
# حساب التكلفة
cost = count * duration * daily_rate
total_cost += cost
# إضافة التفاصيل
labor_details.append({
'النوع': worker_type,
'العدد': count,
'المدة': duration,
'سعر_اليوم': daily_rate,
'التكلفة': cost
})
return {
'التفاصيل': labor_details,
'الإجمالي': total_cost
}
def _calculate_equipment_cost(self, equipment: List[Dict[str, Any]]) -> Dict[str, Any]:
"""
حساب تكلفة المعدات
المعلمات:
equipment (list): قائمة المعدات المستخدمة وساعات عملها
- النوع (str): نوع المعدة
- العدد (int): عدد المعدات
- المدة (float): مدة الاستخدام بالأيام
- سعر_اليوم (float, optional): أجر اليوم (يستخدم السعر من البيانات المرجعية إذا لم يتم تحديده)
العوائد:
dict: تفاصيل تكلفة المعدات
"""
equipment_details = []
total_cost = 0.0
for equip in equipment:
equip_type = equip.get('النوع', '')
count = equip.get('العدد', 0)
duration = equip.get('المدة', 0.0)
# البحث عن سعر المعدة من البيانات المرجعية إذا لم يتم تحديده
if 'سعر_اليوم' in equip:
daily_rate = equip.get('سعر_اليوم', 0.0)
elif equip_type in self.equipment_rates:
daily_rate = self.equipment_rates[equip_type].get('سعر_الوحدة', 0.0)
else:
daily_rate = 0.0
# حساب التكلفة
cost = count * duration * daily_rate
total_cost += cost
# إضافة التفاصيل
equipment_details.append({
'النوع': equip_type,
'العدد': count,
'المدة': duration,
'سعر_اليوم': daily_rate,
'التكلفة': cost
})
return {
'التفاصيل': equipment_details,
'الإجمالي': total_cost
}
def _calculate_adjustment_factor(self, factors: Dict[str, float]) -> float:
"""
حساب المعامل الإجمالي لتعديل التكلفة
المعلمات:
factors (dict): عوامل التعديل
العوائد:
float: المعامل الإجمالي
"""
# دمج العوامل المحددة مع العوامل الافتراضية
effective_factors = self.default_adjustment_factors.copy()
effective_factors.update(factors)
# حساب المعامل الإجمالي
total_factor = 1.0
for factor in effective_factors.values():
total_factor *= factor
return total_factor
def calculate_project_cost(self, project_data: Dict[str, Any]) -> Dict[str, Any]:
"""
حساب التكلفة الإجمالية لمشروع بناء كامل
المعلمات:
project_data (dict): بيانات المشروع، تتضمن:
- اسم_المشروع (str): اسم المشروع
- وصف_المشروع (str): وصف المشروع
- البنود (list): قائمة بنود المشروع
- المصاريف_الإدارية (float, optional): نسبة المصاريف الإدارية الإجمالية (افتراضياً 5%)
- هامش_الربح (float, optional): نسبة هامش الربح الإجمالي (افتراضياً 10%)
- عوامل_التعديل (dict, optional): عوامل تعديل التكلفة للمشروع
العوائد:
dict: تفاصيل تكلفة المشروع بكافة عناصرها
"""
# استخراج البيانات الأساسية للمشروع
project_name = project_data.get('اسم_المشروع', 'مشروع غير محدد')
project_description = project_data.get('وصف_المشروع', '')
items = project_data.get('البنود', [])
# استخراج النسب الإجمالية
admin_percentage = project_data.get('المصاريف_الإدارية', self.default_admin_expenses_percentage)
profit_percentage = project_data.get('هامش_الربح', self.default_profit_margin_percentage)
# حساب تكلفة كل بند
items_costs = []
total_direct_cost = 0.0
total_materials_cost = 0.0
total_labor_cost = 0.0
total_equipment_cost = 0.0
for item_data in items:
# تحديث نسب المصاريف والربح للبند إذا لم تكن محددة
if 'المصاريف_الإدارية' not in item_data:
item_data['المصاريف_الإدارية'] = admin_percentage
if 'هامش_الربح' not in item_data:
item_data['هامش_الربح'] = profit_percentage
# حساب تكلفة البند
item_cost = self.calculate_item_cost(item_data)
items_costs.append(item_cost)
# تحديث الإجماليات
total_materials_cost += item_cost['تكاليف_مباشرة']['المواد']['الإجمالي']
total_labor_cost += item_cost['تكاليف_مباشرة']['العمالة']['الإجمالي']
total_equipment_cost += item_cost['تكاليف_مباشرة']['المعدات']['الإجمالي']
total_direct_cost += item_cost['تكاليف_مباشرة']['إجمالي_تكاليف_مباشرة']
# حساب المصاريف الإدارية
admin_cost = total_direct_cost * admin_percentage
# حساب هامش الربح
profit_margin = (total_direct_cost + admin_cost) * profit_percentage
# حساب التكلفة الإجمالية
total_cost = total_direct_cost + admin_cost + profit_margin
# تطبيق عوامل التعديل إذا وجدت
adjustment_factors = project_data.get('عوامل_التعديل', self.default_adjustment_factors)
adjustment_factor = self._calculate_adjustment_factor(adjustment_factors)
adjusted_total_cost = total_cost * adjustment_factor
# إعداد النتائج
result = {
'اسم_المشروع': project_name,
'وصف_المشروع': project_description,
'تكاليف_مباشرة': {
'المواد': {
'الإجمالي': total_materials_cost,
'النسبة_المئوية': (total_materials_cost / total_direct_cost * 100) if total_direct_cost > 0 else 0
},
'العمالة': {
'الإجمالي': total_labor_cost,
'النسبة_المئوية': (total_labor_cost / total_direct_cost * 100) if total_direct_cost > 0 else 0
},
'المعدات': {
'الإجمالي': total_equipment_cost,
'النسبة_المئوية': (total_equipment_cost / total_direct_cost * 100) if total_direct_cost > 0 else 0
},
'إجمالي_تكاليف_مباشرة': total_direct_cost
},
'مصاريف_إدارية': {
'نسبة': admin_percentage * 100,
'قيمة': admin_cost
},
'هامش_ربح': {
'نسبة': profit_percentage * 100,
'قيمة': profit_margin
},
'التكلفة_الإجمالية': total_cost,
'عوامل_التعديل': {
'المعامل_الإجمالي': adjustment_factor,
'التفاصيل': adjustment_factors
},
'التكلفة_النهائية_المعدلة': adjusted_total_cost,
'تفاصيل_البنود': items_costs,
'عدد_البنود': len(items)
}
return result
def get_rate_info(self, item_type: str, item_name: str) -> Dict[str, Any]:
"""
الحصول على معلومات تفصيلية عن معدل وسعر عنصر محدد (مادة، عمالة، معدة)
المعلمات:
item_type (str): نوع العنصر - 'مادة'، 'عمالة'، 'معدة'
item_name (str): اسم العنصر
العوائد:
dict: معلومات تفصيلية عن العنصر
"""
# تحديد القاموس المناسب حسب نوع العنصر
if item_type == 'مادة':
rates_dict = self.material_rates
elif item_type == 'عمالة':
rates_dict = self.labor_rates
elif item_type == 'معدة':
rates_dict = self.equipment_rates
else:
return {'خطأ': 'نوع العنصر غير صحيح'}
# البحث عن العنصر في القاموس
if item_name in rates_dict:
return rates_dict[item_name]
else:
return {'خطأ': 'العنصر غير موجود'}
def get_all_rates(self, item_type: str = None, category: str = None) -> Dict[str, Any]:
"""
الحصول على قوائم معدلات الأسعار (لجميع المواد أو العمالة أو المعدات)
المعلمات:
item_type (str, optional): نوع العنصر - 'مادة'، 'عمالة'، 'معدة'، أو None لجميع الأنواع
category (str, optional): فئة محددة للتصفية
العوائد:
dict: قوائم معدلات الأسعار
"""
result = {}
# جمع المواد حسب الفئة
if item_type is None or item_type == 'مادة':
materials = {}
for name, info in self.material_rates.items():
if category is None or info.get('فئة') == category:
materials[name] = info
result['المواد'] = materials
# جمع العمالة حسب الفئة
if item_type is None or item_type == 'عمالة':
labor = {}
for name, info in self.labor_rates.items():
if category is None or info.get('فئة') == category:
labor[name] = info
result['العمالة'] = labor
# جمع المعدات حسب الفئة
if item_type is None or item_type == 'معدة':
equipment = {}
for name, info in self.equipment_rates.items():
if category is None or info.get('فئة') == category:
equipment[name] = info
result['المعدات'] = equipment
return result
def generate_sample_project_data(self) -> Dict[str, Any]:
"""
توليد بيانات نموذجية لمشروع بناء صغير للاختبار
العوائد:
dict: بيانات المشروع النموذجية
"""
# إنشاء بيانات المشروع
project_data = {
'اسم_المشروع': 'مبنى سكني صغير',
'وصف_المشروع': 'مبنى سكني مكون من دور أرضي بمساحة 250 متر مربع',
'المصاريف_الإدارية': 0.05, # 5%
'هامش_الربح': 0.10, # 10%
'عوامل_التعديل': {
'location_factor': 1.2, # معامل الموقع (منطقة مرتفعة التكلفة)
'time_factor': 1.0, # معامل الوقت
'risk_factor': 1.05, # معامل المخاطر
'market_factor': 1.0 # معامل السوق
},
'البنود': [
# الأساسات
{
'وصف_البند': 'حفر الأساسات بعمق 2 متر',
'الكمية': 150.0,
'الوحدة': 'م3',
'المواد': [],
'العمالة': [
{'النوع': 'عامل خرسانة', 'العدد': 4, 'المدة': 3}
],
'المعدات': [
{'النوع': 'حفار متوسط', 'العدد': 1, 'المدة': 2}
]
},
{
'وصف_البند': 'توريد وصب خرسانة عادية للأساسات',
'الكمية': 25.0,
'الوحدة': 'م3',
'المواد': [
{'الاسم': 'خرسانة جاهزة', 'الكمية': 25.0}
],
'العمالة': [
{'النوع': 'عامل خرسانة', 'العدد': 6, 'المدة': 1}
],
'المعدات': [
{'النوع': 'مضخة خرسانة', 'العدد': 1, 'المدة': 0.5}
]
},
{
'وصف_البند': 'توريد وتركيب حديد تسليح للأساسات',
'الكمية': 3.5,
'الوحدة': 'طن',
'المواد': [
{'الاسم': 'حديد تسليح', 'الكمية': 3.5}
],
'العمالة': [
{'النوع': 'حداد مسلح', 'العدد': 4, 'المدة': 3}
],
'المعدات': []
},
{
'وصف_البند': 'نجارة وفك شدة الأساسات',
'الكمية': 120.0,
'الوحدة': 'م2',
'المواد': [],
'العمالة': [
{'النوع': 'نجار مسلح', 'العدد': 4, 'المدة': 3}
],
'المعدات': []
},
{
'وصف_البند': 'توريد وصب خرسانة مسلحة للأساسات',
'الكمية': 30.0,
'الوحدة': 'م3',
'المواد': [
{'الاسم': 'خرسانة جاهزة', 'الكمية': 30.0}
],
'العمالة': [
{'النوع': 'عامل خرسانة', 'العدد': 6, 'المدة': 1}
],
'المعدات': [
{'النوع': 'مضخة خرسانة', 'العدد': 1, 'المدة': 0.5},
{'النوع': 'هزاز خرسانة', 'العدد': 2, 'المدة': 1}
]
},
# الأعمدة والأسقف
{
'وصف_البند': 'توريد وتركيب حديد تسليح للأعمدة',
'الكمية': 2.8,
'الوحدة': 'طن',
'المواد': [
{'الاسم': 'حديد تسليح', 'الكمية': 2.8}
],
'العمالة': [
{'النوع': 'حداد مسلح', 'العدد': 4, 'المدة': 3}
],
'المعدات': []
},
{
'وصف_البند': 'نجارة وفك شدة الأعمدة',
'الكمية': 85.0,
'الوحدة': 'م2',
'المواد': [],
'العمالة': [
{'النوع': 'نجار مسلح', 'العدد': 3, 'المدة': 3}
],
'المعدات': []
},
{
'وصف_البند': 'توريد وصب خرسانة مسلحة للأعمدة',
'الكمية': 12.0,
'الوحدة': 'م3',
'المواد': [
{'الاسم': 'خرسانة جاهزة', 'الكمية': 12.0}
],
'العمالة': [
{'النوع': 'عامل خرسانة', 'العدد': 4, 'المدة': 1}
],
'المعدات': [
{'النوع': 'مضخة خرسانة', 'العدد': 1, 'المدة': 0.5},
{'النوع': 'هزاز خرسانة', 'العدد': 2, 'المدة': 1}
]
},
# أعمال البناء
{
'وصف_البند': 'توريد وبناء حوائط من الطوب الأحمر',
'الكمية': 220.0,
'الوحدة': 'م2',
'المواد': [
{'الاسم': 'طوب أحمر', 'الكمية': 16.5} # بالألف
],
'العمالة': [
{'النوع': 'بناء', 'العدد': 4, 'المدة': 8},
{'النوع': 'مساعد بناء', 'العدد': 4, 'المدة': 8}
],
'المعدات': []
},
# أعمال التشطيبات
{
'وصف_البند': 'توريد وتركيب بلاط سيراميك للأرضيات',
'الكمية': 250.0,
'الوحدة': 'م2',
'المواد': [
{'الاسم': 'بلاط سيراميك', 'الكمية': 250.0}
],
'العمالة': [
{'النوع': 'مبلط', 'العدد': 4, 'المدة': 7}
],
'المعدات': []
},
{
'وصف_البند': 'توريد وتنفيذ دهانات للحوائط',
'الكمية': 450.0,
'الوحدة': 'م2',
'المواد': [
{'الاسم': 'دهانات بلاستيك', 'الكمية': 90.0} # بالتر
],
'العمالة': [
{'النوع': 'نقاش', 'العدد': 3, 'المدة': 8}
],
'المعدات': []
}
]
}
return project_data