|
""" |
|
خدمة حاسبة تكاليف البناء |
|
تقوم هذه الخدمة بحساب تكاليف البناء بشكل تفصيلي بناءً على المكونات المختلفة: |
|
- المواد الخام |
|
- العمالة |
|
- المعدات |
|
- المصاريف الإدارية |
|
- هامش الربح |
|
""" |
|
|
|
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 |
|
self.default_profit_margin_percentage = 0.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, |
|
'هامش_الربح': 0.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 |