Spaces:
Sleeping
Sleeping
""" | |
خدمة حاسبة تكاليف البناء | |
تقوم هذه الخدمة بحساب تكاليف البناء بشكل تفصيلي بناءً على المكونات المختلفة: | |
- المواد الخام | |
- العمالة | |
- المعدات | |
- المصاريف الإدارية | |
- هامش الربح | |
""" | |
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 |