v3 / modules /pricing /services /construction_templates.py
EGYADMIN's picture
Upload 115 files
82676b8 verified
"""
كتالوج بنود نموذجية للمقاولات
يحتوي هذا الملف على قائمة كاملة من النماذج الجاهزة للبنود الشائعة في مشاريع المقاولات، مثل:
- أعمال الخرسانة بأنواعها
- المناهل وأنواع المواسير
- التركيبات المختلفة
- الطرق والأسفلت
- وغيرها من أعمال المقاولات
"""
import os
import json
import sys
from typing import Dict, List, Any, Optional
from datetime import datetime
# إضافة مسار النظام للوصول لملفات التكوين
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 ConstructionTemplates:
"""كتالوج بنود نموذجية للمقاولات"""
def __init__(self):
"""تهيئة كتالوج البنود النموذجية"""
self.templates_file = os.path.join(config.DATA_DIR, 'construction_templates.json')
self.market_prices_file = os.path.join(config.DATA_DIR, 'saudi_market_prices.json')
# تحميل قوالب البنود النموذجية
self.templates = self._load_templates()
# تحميل أسعار السوق السعودي
self.market_prices = self._load_market_prices()
def _load_templates(self) -> Dict[str, Dict[str, Any]]:
"""تحميل قوالب البنود النموذجية من الملف"""
if os.path.exists(self.templates_file):
try:
with open(self.templates_file, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
print(f"خطأ في تحميل قوالب البنود النموذجية: {str(e)}")
# إنشاء بيانات افتراضية إذا لم يتم العثور على الملف
default_templates = self._create_default_templates()
# حفظ البيانات الافتراضية
self._save_templates(default_templates)
return default_templates
def _save_templates(self, templates: Dict[str, Dict[str, Any]]) -> None:
"""حفظ قوالب البنود النموذجية إلى الملف"""
try:
with open(self.templates_file, 'w', encoding='utf-8') as f:
json.dump(templates, f, ensure_ascii=False, indent=4)
except Exception as e:
print(f"خطأ في حفظ قوالب البنود النموذجية: {str(e)}")
def _load_market_prices(self) -> Dict[str, Dict[str, Any]]:
"""تحميل أسعار السوق السعودي من الملف"""
if os.path.exists(self.market_prices_file):
try:
with open(self.market_prices_file, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
print(f"خطأ في تحميل أسعار السوق السعودي: {str(e)}")
# إنشاء بيانات افتراضية إذا لم يتم العثور على الملف
default_prices = self._create_default_market_prices()
# حفظ البيانات الافتراضية
self._save_market_prices(default_prices)
return default_prices
def _save_market_prices(self, prices: Dict[str, Dict[str, Any]]) -> None:
"""حفظ أسعار السوق السعودي إلى الملف"""
try:
with open(self.market_prices_file, 'w', encoding='utf-8') as f:
json.dump(prices, f, ensure_ascii=False, indent=4)
except Exception as e:
print(f"خطأ في حفظ أسعار السوق السعودي: {str(e)}")
def _create_default_templates(self) -> Dict[str, Dict[str, Any]]:
"""إنشاء قوالب افتراضية للبنود النموذجية"""
templates = {
"categories": {
"أعمال_خرسانية": {
"name": "أعمال خرسانية",
"description": "بنود أعمال الخرسانة المسلحة والعادية",
"icon": "building"
},
"أعمال_صحية": {
"name": "أعمال صحية",
"description": "بنود أعمال المناهل والمواسير والتركيبات الصحية",
"icon": "pipe"
},
"أعمال_طرق": {
"name": "أعمال طرق",
"description": "بنود أعمال الطرق والأسفلت والرصف",
"icon": "road"
},
"أعمال_كهربائية": {
"name": "أعمال كهربائية",
"description": "بنود أعمال الكهرباء والإنارة",
"icon": "zap"
},
"أعمال_ميكانيكية": {
"name": "أعمال ميكانيكية",
"description": "بنود أعمال التكييف والتهوية والتبريد",
"icon": "thermometer"
}
},
"templates": {
# نماذج أعمال خرسانية
"خرسانة_مسلحة_أساسات": {
"category": "أعمال_خرسانية",
"name": "خرسانة مسلحة للأساسات",
"description": "توريد وصب خرسانة مسلحة للأساسات بقوة لا تقل عن 300 كجم/سم2",
"unit": "م3",
"components": {
"materials": [
{"الاسم": "خرسانة جاهزة", "الكمية": 1.0, "الوحدة": "م3", "سعر_الوحدة": 750.0},
{"الاسم": "حديد تسليح", "الكمية": 0.12, "الوحدة": "طن", "سعر_الوحدة": 5500.0}
],
"labor": [
{"النوع": "عامل خرسانة", "العدد": 4, "المدة": 0.3, "سعر_اليوم": 150.0},
{"النوع": "نجار مسلح", "العدد": 2, "المدة": 0.5, "سعر_اليوم": 250.0},
{"النوع": "حداد مسلح", "العدد": 2, "المدة": 0.5, "سعر_اليوم": 250.0}
],
"equipment": [
{"النوع": "هزاز خرسانة", "العدد": 1, "المدة": 0.3, "سعر_اليوم": 150.0}
]
},
"admin_expenses": 0.05,
"profit_margin": 0.10,
"tags": ["خرسانة", "أساسات", "مسلحة"]
},
"خرسانة_مسلحة_أعمدة": {
"category": "أعمال_خرسانية",
"name": "خرسانة مسلحة للأعمدة",
"description": "توريد وصب خرسانة مسلحة للأعمدة بقوة لا تقل عن 350 كجم/سم2",
"unit": "م3",
"components": {
"materials": [
{"الاسم": "خرسانة جاهزة", "الكمية": 1.0, "الوحدة": "م3", "سعر_الوحدة": 750.0},
{"الاسم": "حديد تسليح", "الكمية": 0.18, "الوحدة": "طن", "سعر_الوحدة": 5500.0}
],
"labor": [
{"النوع": "عامل خرسانة", "العدد": 4, "المدة": 0.4, "سعر_اليوم": 150.0},
{"النوع": "نجار مسلح", "العدد": 2, "المدة": 0.7, "سعر_اليوم": 250.0},
{"النوع": "حداد مسلح", "العدد": 2, "المدة": 0.7, "سعر_اليوم": 250.0}
],
"equipment": [
{"النوع": "هزاز خرسانة", "العدد": 2, "المدة": 0.4, "سعر_اليوم": 150.0}
]
},
"admin_expenses": 0.05,
"profit_margin": 0.10,
"tags": ["خرسانة", "أعمدة", "مسلحة"]
},
"خرسانة_مسلحة_أسقف": {
"category": "أعمال_خرسانية",
"name": "خرسانة مسلحة للأسقف",
"description": "توريد وصب خرسانة مسلحة للأسقف والبلاطات بقوة لا تقل عن 350 كجم/سم2",
"unit": "م3",
"components": {
"materials": [
{"الاسم": "خرسانة جاهزة", "الكمية": 1.0, "الوحدة": "م3", "سعر_الوحدة": 750.0},
{"الاسم": "حديد تسليح", "الكمية": 0.16, "الوحدة": "طن", "سعر_الوحدة": 5500.0}
],
"labor": [
{"النوع": "عامل خرسانة", "العدد": 5, "المدة": 0.5, "سعر_اليوم": 150.0},
{"النوع": "نجار مسلح", "العدد": 3, "المدة": 0.8, "سعر_اليوم": 250.0},
{"النوع": "حداد مسلح", "العدد": 3, "المدة": 0.8, "سعر_اليوم": 250.0}
],
"equipment": [
{"النوع": "هزاز خرسانة", "العدد": 2, "المدة": 0.5, "سعر_اليوم": 150.0}
]
},
"admin_expenses": 0.05,
"profit_margin": 0.10,
"tags": ["خرسانة", "أسقف", "بلاطات", "مسلحة"]
},
# نماذج أعمال صحية
"منهل_تفتيش_خرساني": {
"category": "أعمال_صحية",
"name": "منهل تفتيش خرساني",
"description": "توريد وتركيب منهل تفتيش خرساني قطر 1 متر وعمق 2 متر",
"unit": "عدد",
"components": {
"materials": [
{"الاسم": "خرسانة جاهزة", "الكمية": 1.5, "الوحدة": "م3", "سعر_الوحدة": 750.0},
{"الاسم": "حديد تسليح", "الكمية": 0.15, "الوحدة": "طن", "سعر_الوحدة": 5500.0},
{"الاسم": "غطاء منهل حديد", "الكمية": 1, "الوحدة": "عدد", "سعر_الوحدة": 1500.0}
],
"labor": [
{"النوع": "عامل خرسانة", "العدد": 3, "المدة": 1, "سعر_اليوم": 150.0},
{"النوع": "نجار مسلح", "العدد": 2, "المدة": 1, "سعر_اليوم": 250.0},
{"النوع": "حداد مسلح", "العدد": 1, "المدة": 1, "سعر_اليوم": 250.0},
{"النوع": "سباك", "العدد": 2, "المدة": 1, "سعر_اليوم": 250.0}
],
"equipment": [
{"النوع": "حفار صغير", "العدد": 1, "المدة": 0.5, "سعر_اليوم": 1200.0}
]
},
"admin_expenses": 0.05,
"profit_margin": 0.12,
"tags": ["صرف صحي", "منهل", "تفتيش"]
},
"مواسير_بلاستيك_قطر_200_مم": {
"category": "أعمال_صحية",
"name": "مواسير بلاستيك قطر 200 مم",
"description": "توريد وتركيب مواسير بلاستيك UPVC قطر 200 مم لشبكات الصرف الصحي",
"unit": "م.ط",
"components": {
"materials": [
{"الاسم": "مواسير بلاستيك UPVC قطر 200 مم", "الكمية": 1.05, "الوحدة": "م.ط", "سعر_الوحدة": 180.0},
{"الاسم": "وصلات ومثبتات", "الكمية": 1, "الوحدة": "مجموعة", "سعر_الوحدة": 35.0},
{"الاسم": "مواد لاصقة", "الكمية": 0.1, "الوحدة": "لتر", "سعر_الوحدة": 120.0}
],
"labor": [
{"النوع": "سباك", "العدد": 2, "المدة": 0.2, "سعر_اليوم": 250.0},
{"النوع": "مساعد سباك", "العدد": 2, "المدة": 0.2, "سعر_اليوم": 120.0}
],
"equipment": [
{"النوع": "حفار صغير", "العدد": 1, "المدة": 0.1, "سعر_اليوم": 1200.0}
]
},
"admin_expenses": 0.05,
"profit_margin": 0.12,
"tags": ["صرف صحي", "مواسير", "بلاستيك"]
},
# نماذج أعمال طرق
"طبقة_أساس_للطرق": {
"category": "أعمال_طرق",
"name": "طبقة أساس للطرق",
"description": "توريد وفرد ودمك طبقة أساس للطرق سمك 20 سم، درجة دمك 98%",
"unit": "م3",
"components": {
"materials": [
{"الاسم": "مواد طبقة أساس", "الكمية": 1.25, "الوحدة": "م3", "سعر_الوحدة": 90.0},
{"الاسم": "مياه للدمك", "الكمية": 0.2, "الوحدة": "م3", "سعر_الوحدة": 10.0}
],
"labor": [
{"النوع": "عامل طرق", "العدد": 4, "المدة": 0.05, "سعر_اليوم": 150.0},
{"النوع": "مراقب فني", "العدد": 1, "المدة": 0.05, "سعر_اليوم": 300.0}
],
"equipment": [
{"النوع": "جريدر", "العدد": 1, "المدة": 0.05, "سعر_اليوم": 2200.0},
{"النوع": "رصاصة دمك", "العدد": 1, "المدة": 0.05, "سعر_اليوم": 1800.0},
{"النوع": "شاحنة نقل", "العدد": 2, "المدة": 0.05, "سعر_اليوم": 1200.0}
]
},
"admin_expenses": 0.05,
"profit_margin": 0.12,
"tags": ["طرق", "أساس", "دمك"]
},
"طبقة_إسفلت_سطحية": {
"category": "أعمال_طرق",
"name": "طبقة إسفلت سطحية",
"description": "توريد وفرد ودمك طبقة إسفلت سطحية سمك 5 سم",
"unit": "م2",
"components": {
"materials": [
{"الاسم": "خلطة إسفلتية ساخنة", "الكمية": 0.125, "الوحدة": "طن", "سعر_الوحدة": 400.0},
{"الاسم": "مواد رش تأسيسي", "الكمية": 0.5, "الوحدة": "لتر", "سعر_الوحدة": 8.0}
],
"labor": [
{"النوع": "عامل طرق", "العدد": 6, "المدة": 0.01, "سعر_اليوم": 150.0},
{"النوع": "مراقب فني", "العدد": 1, "المدة": 0.01, "سعر_اليوم": 300.0}
],
"equipment": [
{"النوع": "فرادة إسفلت", "العدد": 1, "المدة": 0.01, "سعر_اليوم": 4000.0},
{"النوع": "رصاصة دمك", "العدد": 2, "المدة": 0.01, "سعر_اليوم": 1800.0},
{"النوع": "سيارة رش إسفلت", "العدد": 1, "المدة": 0.01, "سعر_اليوم": 2000.0},
{"النوع": "شاحنة نقل", "العدد": 4, "المدة": 0.01, "سعر_اليوم": 1200.0}
]
},
"admin_expenses": 0.05,
"profit_margin": 0.12,
"tags": ["طرق", "إسفلت", "سطحية"]
},
# نماذج أعمال كهربائية
"عمود_إنارة_10_متر": {
"category": "أعمال_كهربائية",
"name": "عمود إنارة 10 متر",
"description": "توريد وتركيب عمود إنارة جلفانيزي بارتفاع 10 متر مع ذراع مفردة وكشاف LED بقدرة 150 واط",
"unit": "عدد",
"components": {
"materials": [
{"الاسم": "عمود إنارة جلفانيزي 10 متر", "الكمية": 1, "الوحدة": "عدد", "سعر_الوحدة": 3500.0},
{"الاسم": "ذراع إنارة مفردة", "الكمية": 1, "الوحدة": "عدد", "سعر_الوحدة": 450.0},
{"الاسم": "كشاف LED 150 واط", "الكمية": 1, "الوحدة": "عدد", "سعر_الوحدة": 850.0},
{"الاسم": "كابل كهرباء 3×4 مم²", "الكمية": 15, "الوحدة": "م.ط", "سعر_الوحدة": 32.0},
{"الاسم": "قاعدة خرسانية مسلحة", "الكمية": 0.25, "الوحدة": "م3", "سعر_الوحدة": 750.0}
],
"labor": [
{"النوع": "كهربائي", "العدد": 2, "المدة": 1, "سعر_اليوم": 270.0},
{"النوع": "مساعد كهربائي", "العدد": 2, "المدة": 1, "سعر_اليوم": 120.0},
{"النوع": "عامل خرسانة", "العدد": 2, "المدة": 0.5, "سعر_اليوم": 150.0}
],
"equipment": [
{"النوع": "ونش شوكة", "العدد": 1, "المدة": 0.5, "سعر_اليوم": 1500.0},
{"النوع": "حفار صغير", "العدد": 1, "المدة": 0.2, "سعر_اليوم": 1200.0}
]
},
"admin_expenses": 0.05,
"profit_margin": 0.12,
"tags": ["كهرباء", "إنارة", "LED"]
}
}
}
return templates
def _create_default_market_prices(self) -> Dict[str, Dict[str, Any]]:
"""إنشاء بيانات افتراضية لأسعار السوق السعودي"""
current_date = datetime.now().strftime("%Y-%m-%d")
prices = {
"metadata": {
"last_update": current_date,
"source": "أسعار السوق السعودي الافتراضية",
"disclaimer": "هذه الأسعار تقريبية وقد تختلف حسب المنطقة والكميات والموردين"
},
"materials": {
# مواد الخرسانة
"خرسانة_جاهزة": {
"name": "خرسانة جاهزة",
"unit": "م3",
"current_price": 750.0,
"previous_price": 730.0,
"price_trend": "up",
"category": "أعمال خرسانية",
"specifications": "خرسانة جاهزة بقوة 350 كجم/سم2",
"note": "السعر يشمل توريد فقط، الضخ بتكلفة إضافية",
"price_history": [
{"date": "2023-06-01", "price": 700.0},
{"date": "2023-09-01", "price": 715.0},
{"date": "2023-12-01", "price": 730.0},
{"date": current_date, "price": 750.0}
]
},
"حديد_تسليح": {
"name": "حديد تسليح",
"unit": "طن",
"current_price": 5500.0,
"previous_price": 5200.0,
"price_trend": "up",
"category": "أعمال خرسانية",
"specifications": "حديد تسليح قطر 8-32 مم، انتاج سابك",
"note": "السعر يتغير بشكل دوري حسب أسعار الحديد العالمية",
"price_history": [
{"date": "2023-06-01", "price": 4800.0},
{"date": "2023-09-01", "price": 5000.0},
{"date": "2023-12-01", "price": 5200.0},
{"date": current_date, "price": 5500.0}
]
},
"أسمنت": {
"name": "أسمنت",
"unit": "كيس",
"current_price": 30.0,
"previous_price": 28.0,
"price_trend": "up",
"category": "أعمال خرسانية",
"specifications": "أسمنت بورتلاندي عادي، كيس 50 كجم",
"note": "السعر للكميات الكبيرة",
"price_history": [
{"date": "2023-06-01", "price": 25.0},
{"date": "2023-09-01", "price": 27.0},
{"date": "2023-12-01", "price": 28.0},
{"date": current_date, "price": 30.0}
]
},
# مواد الطرق والإسفلت
"خلطة_إسفلتية_ساخنة": {
"name": "خلطة إسفلتية ساخنة",
"unit": "طن",
"current_price": 400.0,
"previous_price": 380.0,
"price_trend": "up",
"category": "أعمال طرق",
"specifications": "خلطة إسفلتية ساخنة للطبقة السطحية",
"note": "السعر يشمل التوريد من المصنع، النقل بتكلفة إضافية",
"price_history": [
{"date": "2023-06-01", "price": 350.0},
{"date": "2023-09-01", "price": 370.0},
{"date": "2023-12-01", "price": 380.0},
{"date": current_date, "price": 400.0}
]
},
# مواد صحية
"مواسير_بلاستيك_UPVC": {
"name": "مواسير بلاستيك UPVC قطر 200 مم",
"unit": "م.ط",
"current_price": 180.0,
"previous_price": 165.0,
"price_trend": "up",
"category": "أعمال صحية",
"specifications": "مواسير بلاستيك UPVC قطر 200 مم لشبكات الصرف الصحي",
"note": "السعر للكميات الكبيرة",
"price_history": [
{"date": "2023-06-01", "price": 150.0},
{"date": "2023-09-01", "price": 160.0},
{"date": "2023-12-01", "price": 165.0},
{"date": current_date, "price": 180.0}
]
},
# مواد كهربائية
"كشاف_LED": {
"name": "كشاف LED 150 واط",
"unit": "عدد",
"current_price": 850.0,
"previous_price": 820.0,
"price_trend": "up",
"category": "أعمال كهربائية",
"specifications": "كشاف إنارة LED بقدرة 150 واط للاستخدام الخارجي، IP65",
"note": "السعر شامل الضريبة",
"price_history": [
{"date": "2023-06-01", "price": 780.0},
{"date": "2023-09-01", "price": 800.0},
{"date": "2023-12-01", "price": 820.0},
{"date": current_date, "price": 850.0}
]
}
},
"labor": {
"عامل_خرسانة": {
"name": "عامل خرسانة",
"unit": "يوم",
"current_price": 150.0,
"previous_price": 140.0,
"price_trend": "up",
"category": "عمالة",
"specifications": "عامل لصب وتسوية الخرسانة",
"note": "أجرة اليوم الواحد لا تشمل السكن والمواصلات",
"price_history": [
{"date": "2023-06-01", "price": 130.0},
{"date": "2023-09-01", "price": 135.0},
{"date": "2023-12-01", "price": 140.0},
{"date": current_date, "price": 150.0}
]
},
"مهندس_موقع": {
"name": "مهندس موقع",
"unit": "يوم",
"current_price": 500.0,
"previous_price": 480.0,
"price_trend": "up",
"category": "إشراف",
"specifications": "مهندس إشراف موقع",
"note": "أجرة اليوم الواحد لا تشمل السكن والمواصلات",
"price_history": [
{"date": "2023-06-01", "price": 450.0},
{"date": "2023-09-01", "price": 470.0},
{"date": "2023-12-01", "price": 480.0},
{"date": current_date, "price": 500.0}
]
}
},
"equipment": {
"حفار_صغير": {
"name": "حفار صغير",
"unit": "يوم",
"current_price": 1200.0,
"previous_price": 1150.0,
"price_trend": "up",
"category": "معدات حفر",
"specifications": "حفار صغير (بوبكات) بقدرة 70 حصان",
"note": "السعر يشمل المشغل والوقود",
"price_history": [
{"date": "2023-06-01", "price": 1100.0},
{"date": "2023-09-01", "price": 1120.0},
{"date": "2023-12-01", "price": 1150.0},
{"date": current_date, "price": 1200.0}
]
},
"فرادة_إسفلت": {
"name": "فرادة إسفلت",
"unit": "يوم",
"current_price": 4000.0,
"previous_price": 3800.0,
"price_trend": "up",
"category": "معدات طرق",
"specifications": "فرادة إسفلت بعرض 3 متر",
"note": "السعر يشمل المشغل والوقود",
"price_history": [
{"date": "2023-06-01", "price": 3500.0},
{"date": "2023-09-01", "price": 3650.0},
{"date": "2023-12-01", "price": 3800.0},
{"date": current_date, "price": 4000.0}
]
}
}
}
return prices
def get_all_templates(self) -> Dict[str, Dict[str, Any]]:
"""الحصول على جميع القوالب النموذجية"""
return self.templates
def get_templates_by_category(self, category_id: str) -> List[Dict[str, Any]]:
"""الحصول على القوالب النموذجية حسب الفئة"""
result = []
# التحقق من وجود الفئة
if category_id not in self.templates["categories"]:
return result
# جمع القوالب التي تنتمي إلى الفئة المحددة
for template_id, template in self.templates["templates"].items():
if template["category"] == category_id:
template_copy = template.copy()
template_copy["id"] = template_id
result.append(template_copy)
return result
def get_template_by_id(self, template_id: str) -> Optional[Dict[str, Any]]:
"""الحصول على قالب نموذجي بواسطة المعرف"""
if template_id in self.templates["templates"]:
template = self.templates["templates"][template_id].copy()
template["id"] = template_id
return template
return None
def add_template(self, template_data: Dict[str, Any]) -> str:
"""إضافة قالب نموذجي جديد"""
# إنشاء معرف فريد للقالب
template_name = template_data.get("name", "").strip()
if not template_name:
raise ValueError("يجب تحديد اسم القالب")
# تحويل الاسم إلى معرف (باستبدال المسافات بالشرطات السفلية وإزالة الأحرف الخاصة)
import re
template_id = re.sub(r'[^\w\s]', '', template_name)
template_id = template_id.replace(" ", "_")
# إضافة رقم عشوائي لتجنب التكرار
import random
if template_id in self.templates["templates"]:
template_id = f"{template_id}_{random.randint(1000, 9999)}"
# إضافة القالب إلى القائمة
self.templates["templates"][template_id] = template_data
# حفظ التغييرات
self._save_templates(self.templates)
return template_id
def update_template(self, template_id: str, template_data: Dict[str, Any]) -> bool:
"""تحديث قالب نموذجي موجود"""
if template_id not in self.templates["templates"]:
return False
# تحديث القالب
self.templates["templates"][template_id] = template_data
# حفظ التغييرات
self._save_templates(self.templates)
return True
def delete_template(self, template_id: str) -> bool:
"""حذف قالب نموذجي"""
if template_id not in self.templates["templates"]:
return False
# حذف القالب
del self.templates["templates"][template_id]
# حفظ التغييرات
self._save_templates(self.templates)
return True
def get_market_prices(self, category: Optional[str] = None, item_type: Optional[str] = None) -> Dict[str, Any]:
"""الحصول على أسعار السوق السعودي"""
result = {
"metadata": self.market_prices["metadata"]
}
# تحديد نوع العناصر المطلوبة
sections = []
if item_type:
if item_type in ["materials", "المواد"]:
sections = ["materials"]
elif item_type in ["labor", "العمالة"]:
sections = ["labor"]
elif item_type in ["equipment", "المعدات"]:
sections = ["equipment"]
else:
sections = ["materials", "labor", "equipment"]
# جمع العناصر
for section in sections:
result[section] = {}
for item_id, item_data in self.market_prices[section].items():
if not category or (item_data.get("category", "") == category):
result[section][item_id] = item_data
return result
def update_market_price(self, item_type: str, item_id: str, new_price: float) -> bool:
"""تحديث سعر في قائمة أسعار السوق"""
section = ""
if item_type in ["materials", "المواد"]:
section = "materials"
elif item_type in ["labor", "العمالة"]:
section = "labor"
elif item_type in ["equipment", "المعدات"]:
section = "equipment"
else:
return False
if item_id not in self.market_prices[section]:
return False
# تحديث السعر
current_price = self.market_prices[section][item_id]["current_price"]
self.market_prices[section][item_id]["previous_price"] = current_price
self.market_prices[section][item_id]["current_price"] = new_price
# تحديد اتجاه السعر
if new_price > current_price:
self.market_prices[section][item_id]["price_trend"] = "up"
elif new_price < current_price:
self.market_prices[section][item_id]["price_trend"] = "down"
else:
self.market_prices[section][item_id]["price_trend"] = "stable"
# إضافة السعر الجديد إلى تاريخ الأسعار
current_date = datetime.now().strftime("%Y-%m-%d")
self.market_prices[section][item_id]["price_history"].append({
"date": current_date,
"price": new_price
})
# تحديث تاريخ آخر تحديث
self.market_prices["metadata"]["last_update"] = current_date
# حفظ التغييرات
self._save_market_prices(self.market_prices)
return True
def add_market_price_item(self, item_type: str, item_data: Dict[str, Any]) -> str:
"""إضافة عنصر جديد إلى قائمة أسعار السوق"""
section = ""
if item_type in ["materials", "المواد"]:
section = "materials"
elif item_type in ["labor", "العمالة"]:
section = "labor"
elif item_type in ["equipment", "المعدات"]:
section = "equipment"
else:
raise ValueError("نوع العنصر غير صحيح")
# التحقق من البيانات الأساسية
if "name" not in item_data or "current_price" not in item_data or "unit" not in item_data:
raise ValueError("يجب تحديد الاسم والسعر الحالي والوحدة")
# إنشاء معرف فريد للعنصر
item_name = item_data["name"].strip()
import re
item_id = re.sub(r'[^\w\s]', '', item_name)
item_id = item_id.replace(" ", "_")
# إضافة رقم عشوائي لتجنب التكرار
import random
if item_id in self.market_prices[section]:
item_id = f"{item_id}_{random.randint(1000, 9999)}"
# إعداد بيانات العنصر
current_date = datetime.now().strftime("%Y-%m-%d")
new_item = {
"name": item_name,
"unit": item_data["unit"],
"current_price": item_data["current_price"],
"previous_price": item_data.get("previous_price", item_data["current_price"]),
"price_trend": "stable",
"category": item_data.get("category", ""),
"specifications": item_data.get("specifications", ""),
"note": item_data.get("note", ""),
"price_history": [
{"date": current_date, "price": item_data["current_price"]}
]
}
# إضافة العنصر إلى القائمة
self.market_prices[section][item_id] = new_item
# تحديث تاريخ آخر تحديث
self.market_prices["metadata"]["last_update"] = current_date
# حفظ التغييرات
self._save_market_prices(self.market_prices)
return item_id
def convert_template_to_item(self, template_id: str) -> Dict[str, Any]:
"""تحويل قالب نموذجي إلى بند للاستخدام في حاسبة تكاليف البناء"""
template = self.get_template_by_id(template_id)
if not template:
raise ValueError("القالب غير موجود")
# تحويل القالب إلى صيغة بند
item = {
"وصف_البند": template["description"],
"الكمية": 1.0,
"الوحدة": template["unit"],
"المواد": template["components"]["materials"],
"العمالة": template["components"]["labor"],
"المعدات": template["components"]["equipment"],
"المصاريف_الإدارية": template["admin_expenses"],
"هامش_الربح": template["profit_margin"],
"عوامل_التعديل": {
"location_factor": 1.0,
"time_factor": 1.0,
"risk_factor": 1.0,
"market_factor": 1.0
}
}
return item