Spaces:
Paused
Paused
| # الحصول على معلومات العمالة | |
| labor = project_data.get("labor", []) | |
| # الحصول على معلومات الخدمات | |
| services = project_data.get("services", []) | |
| # حساب نسبة المحتوى المحلي للمواد | |
| materials_local_content = self._calculate_materials_local_content(materials, sector) | |
| # حساب نسبة المحتوى المحلي للعمالة | |
| labor_local_content = self._calculate_labor_local_content(labor) | |
| # حساب نسبة المحتوى المحلي للخدمات | |
| services_local_content = self._calculate_services_local_content(services, sector) | |
| # حساب نسبة المحتوى المحلي الإجمالية | |
| total_local_content = self._calculate_total_local_content( | |
| materials_local_content, | |
| labor_local_content, | |
| services_local_content, | |
| sector | |
| ) | |
| # تحديد النسبة المستهدفة للمحتوى المحلي | |
| target_local_content = self._get_target_local_content(sector) | |
| # تقييم الامتثال | |
| compliance_status = "مستوفي" if total_local_content >= target_local_content else "غير مستوفي" | |
| # إعداد النتائج | |
| results = { | |
| "total_local_content": total_local_content, | |
| "target_local_content": target_local_content, | |
| "compliance_status": compliance_status, | |
| "materials_local_content": materials_local_content, | |
| "labor_local_content": labor_local_content, | |
| "services_local_content": services_local_content, | |
| "details": { | |
| "materials": self._get_materials_details(materials), | |
| "labor": self._get_labor_details(labor), | |
| "services": self._get_services_details(services) | |
| }, | |
| "recommendations": self._generate_recommendations( | |
| total_local_content, | |
| target_local_content, | |
| materials_local_content, | |
| labor_local_content, | |
| services_local_content, | |
| sector | |
| ) | |
| } | |
| logger.info(f"اكتمل حساب نسب المحتوى المحلي: إجمالي {total_local_content:.1f}%، مستهدف {target_local_content:.1f}%") | |
| return results | |
| except Exception as e: | |
| logger.error(f"فشل في حساب نسب المحتوى المحلي: {str(e)}") | |
| return { | |
| "total_local_content": 0, | |
| "target_local_content": 0, | |
| "compliance_status": "غير مستوفي", | |
| "materials_local_content": 0, | |
| "labor_local_content": 0, | |
| "services_local_content": 0, | |
| "details": {}, | |
| "recommendations": [], | |
| "error": str(e) | |
| } | |
| def _calculate_materials_local_content(self, materials: List[Dict[str, Any]], sector: str) -> float: | |
| """ | |
| حساب نسبة المحتوى المحلي للمواد | |
| المعاملات: | |
| ---------- | |
| materials : List[Dict[str, Any]] | |
| قائمة المواد | |
| sector : str | |
| القطاع | |
| المخرجات: | |
| -------- | |
| float | |
| نسبة المحتوى المحلي للمواد | |
| """ | |
| if not materials: | |
| return 0.0 | |
| total_cost = 0.0 | |
| local_cost = 0.0 | |
| for material in materials: | |
| cost = material.get("cost", 0) | |
| local_percentage = material.get("local_percentage", 0) | |
| total_cost += cost | |
| local_cost += cost * (local_percentage / 100) | |
| if total_cost == 0: | |
| return 0.0 | |
| # تطبيق المعاملات حسب القطاع | |
| sector_weight = self.calculation_rules.get("sector_weights", {}).get(sector, {}).get("materials", 1.0) | |
| local_content = (local_cost / total_cost) * 100 * sector_weight | |
| return min(100.0, local_content) | |
| def _calculate_labor_local_content(self, labor: List[Dict[str, Any]]) -> float: | |
| """ | |
| حساب نسبة المحتوى المحلي للعمالة | |
| المعاملات: | |
| ---------- | |
| labor : List[Dict[str, Any]] | |
| قائمة العمالة | |
| المخرجات: | |
| -------- | |
| float | |
| نسبة المحتوى المحلي للعمالة | |
| """ | |
| if not labor: | |
| return 0.0 | |
| total_cost = 0.0 | |
| local_cost = 0.0 | |
| for worker in labor: | |
| cost = worker.get("cost", 0) | |
| is_saudi = worker.get("is_saudi", False) | |
| total_cost += cost | |
| if is_saudi: | |
| local_cost += cost | |
| if total_cost == 0: | |
| return 0.0 | |
| local_content = (local_cost / total_cost) * 100 | |
| return min(100.0, local_content) | |
| def _calculate_services_local_content(self, services: List[Dict[str, Any]], sector: str) -> float: | |
| """ | |
| حساب نسبة المحتوى المحلي للخدمات | |
| المعاملات: | |
| ---------- | |
| services : List[Dict[str, Any]] | |
| قائمة الخدمات | |
| sector : str | |
| القطاع | |
| المخرجات: | |
| -------- | |
| float | |
| نسبة المحتوى المحلي للخدمات | |
| """ | |
| if not services: | |
| return 0.0 | |
| total_cost = 0.0 | |
| local_cost = 0.0 | |
| for service in services: | |
| cost = service.get("cost", 0) | |
| local_percentage = service.get("local_percentage", 0) | |
| total_cost += cost | |
| local_cost += cost * (local_percentage / 100) | |
| if total_cost == 0: | |
| return 0.0 | |
| # تطبيق المعاملات حسب القطاع | |
| sector_weight = self.calculation_rules.get("sector_weights", {}).get(sector, {}).get("services", 1.0) | |
| local_content = (local_cost / total_cost) * 100 * sector_weight | |
| return min(100.0, local_content) | |
| def _calculate_total_local_content(self, materials_local_content: float, | |
| labor_local_content: float, | |
| services_local_content: float, | |
| sector: str) -> float: | |
| """ | |
| حساب نسبة المحتوى المحلي الإجمالية | |
| المعاملات: | |
| ---------- | |
| materials_local_content : float | |
| نسبة المحتوى المحلي للمواد | |
| labor_local_content : float | |
| نسبة المحتوى المحلي للعمالة | |
| services_local_content : float | |
| نسبة المحتوى المحلي للخدمات | |
| sector : str | |
| القطاع | |
| المخرجات: | |
| -------- | |
| float | |
| نسبة المحتوى المحلي الإجمالية | |
| """ | |
| # الحصول على أوزان القطاع | |
| sector_weights = self.calculation_rules.get("sector_weights", {}).get(sector, {}) | |
| materials_weight = sector_weights.get("materials_weight", 0.5) | |
| labor_weight = sector_weights.get("labor_weight", 0.3) | |
| services_weight = sector_weights.get("services_weight", 0.2) | |
| # حساب المتوسط المرجح | |
| total_local_content = ( | |
| materials_local_content * materials_weight + | |
| labor_local_content * labor_weight + | |
| services_local_content * services_weight | |
| ) | |
| return min(100.0, total_local_content) | |
| def _get_target_local_content(self, sector: str) -> float: | |
| """ | |
| تحديد النسبة المستهدفة للمحتوى المحلي | |
| المعاملات: | |
| ---------- | |
| sector : str | |
| القطاع | |
| المخرجات: | |
| -------- | |
| float | |
| النسبة المستهدفة للمحتوى المحلي | |
| """ | |
| # الحصول على النسبة المستهدفة حسب القطاع | |
| sector_targets = self.calculation_rules.get("sector_targets", {}) | |
| target = sector_targets.get(sector, 0.0) | |
| if target > 0: | |
| return target | |
| # إذا لم يكن هناك هدف محدد للقطاع، استخدم الهدف الافتراضي | |
| return self.calculation_rules.get("default_target", 30.0) | |
| def _get_materials_details(self, materials: List[Dict[str, Any]]) -> List[Dict[str, Any]]: | |
| """ | |
| الحصول على تفاصيل المواد | |
| المعاملات: | |
| ---------- | |
| materials : List[Dict[str, Any]] | |
| قائمة المواد | |
| المخرجات: | |
| -------- | |
| List[Dict[str, Any]] | |
| تفاصيل المواد | |
| """ | |
| details = [] | |
| for material in materials: | |
| details.append({ | |
| "name": material.get("name", ""), | |
| "cost": material.get("cost", 0), | |
| "local_percentage": material.get("local_percentage", 0), | |
| "local_amount": material.get("cost", 0) * material.get("local_percentage", 0) / 100, | |
| "manufacturer": material.get("manufacturer", ""), | |
| "country_of_origin": material.get("country_of_origin", "") | |
| }) | |
| return details | |
| def _get_labor_details(self, labor: List[Dict[str, Any]]) -> List[Dict[str, Any]]: | |
| """ | |
| الحصول على تفاصيل العمالة | |
| المعاملات: | |
| ---------- | |
| labor : List[Dict[str, Any]] | |
| قائمة العمالة | |
| المخرجات: | |
| -------- | |
| List[Dict[str, Any]] | |
| تفاصيل العمالة | |
| """ | |
| details = [] | |
| for worker in labor: | |
| details.append({ | |
| "position": worker.get("position", ""), | |
| "cost": worker.get("cost", 0), | |
| "is_saudi": worker.get("is_saudi", False), | |
| "local_amount": worker.get("cost", 0) if worker.get("is_saudi", False) else 0, | |
| "qualification": worker.get("qualification", ""), | |
| "experience": worker.get("experience", "") | |
| }) | |
| return details | |
| def _get_services_details(self, services: List[Dict[str, Any]]) -> List[Dict[str, Any]]: | |
| """ | |
| الحصول على تفاصيل الخدمات | |
| المعاملات: | |
| ---------- | |
| services : List[Dict[str, Any]] | |
| قائمة الخدمات | |
| المخرجات: | |
| -------- | |
| List[Dict[str, Any]] | |
| تفاصيل الخدمات | |
| """ | |
| details = [] | |
| for service in services: | |
| details.append({ | |
| "name": service.get("name", ""), | |
| "cost": service.get("cost", 0), | |
| "local_percentage": service.get("local_percentage", 0), | |
| "local_amount": service.get("cost", 0) * service.get("local_percentage", 0) / 100, | |
| "provider": service.get("provider", ""), | |
| "description": service.get("description", "") | |
| }) | |
| return details | |
| def _generate_recommendations(self, total_local_content: float, | |
| target_local_content: float, | |
| materials_local_content: float, | |
| labor_local_content: float, | |
| services_local_content: float, | |
| sector: str) -> List[str]: | |
| """ | |
| إنشاء توصيات لتحسين نسبة المحتوى المحلي | |
| المعاملات: | |
| ---------- | |
| total_local_content : float | |
| نسبة المحتوى المحلي الإجمالية | |
| target_local_content : float | |
| النسبة المستهدفة للمحتوى المحلي | |
| materials_local_content : float | |
| نسبة المحتوى المحلي للمواد | |
| labor_local_content : float | |
| نسبة المحتوى المحلي للعمالة | |
| services_local_content : float | |
| نسبة المحتوى المحلي للخدمات | |
| sector : str | |
| القطاع | |
| المخرجات: | |
| -------- | |
| List[str] | |
| قائمة التوصيات | |
| """ | |
| recommendations = [] | |
| # التحقق مما إذا كانت النسبة الإجمالية تلبي الهدف | |
| if total_local_content < target_local_content: | |
| gap = target_local_content - total_local_content | |
| recommendations.append(f"زيادة نسبة المحتوى المحلي الإجمالية بمقدار {gap:.1f}% لتلبية الهدف المطلوب.") | |
| # تحديد أي المكونات تحتاج إلى تحسين | |
| sector_weights = self.calculation_rules.get("sector_weights", {}).get(sector, {}) | |
| materials_weight = sector_weights.get("materials_weight", 0.5) | |
| labor_weight = sector_weights.get("labor_weight", 0.3) | |
| services_weight = sector_weights.get("services_weight", 0.2) | |
| # تقييم المكونات | |
| component_gaps = [ | |
| ("المواد", materials_local_content, materials_weight), | |
| ("العمالة", labor_local_content, labor_weight), | |
| ("الخدمات", services_local_content, services_weight) | |
| ] | |
| # ترتيب المكونات حسب الفجوة المرجحة (أكبر فجوة في المساهمة) | |
| component_gaps.sort(key=lambda x: (100 - x[1]) * x[2], reverse=True) | |
| # إضافة توصيات محددة للمكونات ذات الأولوية | |
| for component, content, weight in component_gaps: | |
| if component == "المواد" and content < 70: | |
| recommendations.append(f"زيادة نسبة المحتوى المحلي للمواد من {content:.1f}% إلى ما لا يقل عن 70% من خلال:") | |
| recommendations.append(" - البحث عن موردين محليين للمواد الأساسية") | |
| recommendations.append(" - استبدال المواد المستوردة ببدائل محلية الصنع") | |
| recommendations.append(" - التعاون مع المصنعين المحليين لتطوير المنتجات المطلوبة") | |
| elif component == "العمالة" and content < 60: | |
| recommendations.append(f"زيادة نسبة المحتوى المحلي للعمالة من {content:.1f}% إلى ما لا يقل عن 60% من خلال:") | |
| recommendations.append(" - توظيف المزيد من الكوادر السعودية") | |
| recommendations.append(" - تدريب وتأهيل الكوادر الوطنية للوظائف الفنية") | |
| recommendations.append(" - الاستفادة من برامج دعم التوظيف المقدمة من هدف وصندوق تنمية الموارد البشرية") | |
| elif component == "الخدمات" and content < 50: | |
| recommendations.append(f"زيادة نسبة المحتوى المحلي للخدمات من {content:.1f}% إلى ما لا يقل عن 50% من خلال:") | |
| recommendations.append(" - التعاقد مع شركات خدمات محلية") | |
| recommendations.append(" - الاستعانة بمكاتب استشارية سعودية") | |
| recommendations.append(" - تطوير القدرات المحلية في مجالات الخدمات المتخصصة") | |
| else: | |
| recommendations.append(f"نسبة المحتوى المحلي الحالية ({total_local_content:.1f}%) تلبي الهدف المطلوب ({target_local_content:.1f}%).") | |
| recommendations.append("للحفاظ على هذا المستوى وتحسينه:") | |
| recommendations.append(" - توثيق مصادر المواد والخدمات المحلية بشكل دقيق") | |
| recommendations.append(" - مراجعة خطة المحتوى المحلي بانتظام") | |
| recommendations.append(" - بناء علاقات طويلة الأمد مع الموردين المحليين") | |
| # توصيات عامة | |
| recommendations.append("\nتوصيات عامة لتعزيز المحتوى المحلي:") | |
| recommendations.append(" - الاستفادة من برامج ومبادرات هيئة المحتوى المحلي وتنمية القطاع الخاص") | |
| recommendations.append(" - المشاركة في المعارض والفعاليات المحلية للتعرف على الموردين المحليين") | |
| recommendations.append(" - الاستثمار في نقل التقنية وتوطينها") | |
| recommendations.append(" - تطوير قاعدة بيانات للموردين المحليين وتحديثها بانتظام") | |
| return recommendations | |
| def _load_calculation_rules(self) -> Dict[str, Any]: | |
| """ | |
| تحميل قواعد حساب المحتوى المحلي | |
| المخرجات: | |
| -------- | |
| Dict[str, Any] | |
| قواعد حساب المحتوى المحلي | |
| """ | |
| try: | |
| file_path = 'data/templates/local_content_calculation_rules.json' | |
| if os.path.exists(file_path): | |
| with open(file_path, 'r', encoding='utf-8') as f: | |
| return json.load(f) | |
| else: | |
| logger.warning(f"ملف قواعد حساب المحتوى المحلي غير موجود: {file_path}") | |
| # إنشاء قواعد افتراضية | |
| return self._create_default_calculation_rules() | |
| except Exception as e: | |
| logger.error(f"فشل في تحميل قواعد حساب المحتوى المحلي: {str(e)}") | |
| return self._create_default_calculation_rules() | |
| def _create_default_calculation_rules(self) -> Dict[str, Any]: | |
| """ | |
| إنشاء قواعد حساب المحتوى المحلي الافتراضية | |
| المخرجات: | |
| -------- | |
| Dict[str, Any] | |
| قواعد حساب المحتوى المحلي الافتراضية | |
| """ | |
| return { | |
| "default_target": 30.0, | |
| "sector_targets": { | |
| "oil_and_gas": 40.0, | |
| "petrochemicals": 35.0, | |
| "energy": 35.0, | |
| "water": 25.0, | |
| "construction": 20.0, | |
| "infrastructure": 25.0, | |
| "transportation": 30.0, | |
| "telecommunications": 20.0, | |
| "healthcare": 25.0, | |
| "education": 35.0, | |
| "tourism": 30.0, | |
| "military": 50.0, | |
| "industrial": 35.0, | |
| "commercial": 25.0, | |
| "residential": 20.0, | |
| "general": 30.0 | |
| }, | |
| "sector_weights": { | |
| "oil_and_gas": { | |
| "materials_weight": 0.6, | |
| "labor_weight": 0.25, | |
| "services_weight": 0.15, | |
| "materials": 1.1, | |
| "services": 0.9 | |
| }, | |
| "construction": { | |
| "materials_weight": 0.5, | |
| "labor_weight": 0.35, | |
| "services_weight": 0.15, | |
| "materials": 1.0, | |
| "services": 1.0 | |
| }, | |
| "infrastructure": { | |
| "materials_weight": 0.55, | |
| "labor_weight": 0.3, | |
| "services_weight": 0.15, | |
| "materials": 1.0, | |
| "services": 1.0 | |
| }, | |
| "telecommunications": { | |
| "materials_weight": 0.4, | |
| "labor_weight": 0.3, | |
| "services_weight": 0.3, | |
| "materials": 0.9, | |
| "services": 1.1 | |
| }, | |
| "healthcare": { | |
| "materials_weight": 0.4, | |
| "labor_weight": 0.4, | |
| "services_weight": 0.2, | |
| "materials": 0.9, | |
| """ | |
| حاسبة نسب المحتوى المحلي | |
| تقوم بحساب نسب المحتوى المحلي وفقًا للوائح هيئة المحتوى المحلي وتنمية القطاع الخاص | |
| """ | |
| import logging | |
| import json | |
| import os | |
| from typing import Dict, List, Any, Tuple, Optional, Union | |
| logger = logging.getLogger(__name__) | |
| class LocalContentCalculator: | |
| """ | |
| حاسبة نسب المحتوى المحلي | |
| """ | |
| def __init__(self, config=None): | |
| """ | |
| تهيئة حاسبة المحتوى المحلي | |
| المعاملات: | |
| ---------- | |
| config : Dict, optional | |
| إعدادات الحاسبة | |
| """ | |
| self.config = config or {} | |
| # تحميل قواعد حساب المحتوى المحلي | |
| self.calculation_rules = self._load_calculation_rules() | |
| logger.info("تم تهيئة حاسبة المحتوى المحلي") | |
| def calculate(self, project_data: Dict[str, Any]) -> Dict[str, Any]: | |
| """ | |
| حساب نسب المحتوى المحلي للمشروع | |
| المعاملات: | |
| ---------- | |
| project_data : Dict[str, Any] | |
| بيانات المشروع | |
| المخرجات: | |
| -------- | |
| Dict[str, Any] | |
| نتائج حساب المحتوى المحلي | |
| """ | |
| try: | |
| logger.info("بدء حساب نسب المحتوى المحلي") | |
| # الحصول على معلومات القطاع | |
| sector = project_data.get("sector", "general") | |
| # الحصول على معلومات المواد | |
| materials = project_data.get("materials", []) |