EGYADMIN's picture
Upload 70 files
d9e7bdd verified
"""
وحدة استراتيجيات التسعير المتقدمة
"""
import streamlit as st
import pandas as pd
import numpy as np
from datetime import datetime
class PricingStrategies:
def __init__(self):
if 'pricing_strategies' not in st.session_state:
self._initialize_pricing_strategies()
if 'items' not in st.session_state:
st.session_state.items = []
def _initialize_pricing_strategies(self):
"""تهيئة استراتيجيات التسعير"""
st.session_state.pricing_strategies = {
"strategies": [
{
"id": "MTR-001",
"name": "تسعير المواد",
"description": "استراتيجية خاصة بتسعير المواد تأخذ في الاعتبار تقلبات الأسعار وتكاليف النقل والتخزين",
"profit_margin": 0.12,
"risk_factor": 0.05,
"storage_cost": 0.03,
"transport_cost": 0.04,
"market_volatility": 0.02,
"applicable_to": "materials"
},
{
"id": "LBR-001",
"name": "تسعير العمالة",
"description": "استراتيجية مخصصة للعمالة تراعي المهارات والخبرات ومعدلات الإنتاجية",
"profit_margin": 0.15,
"risk_factor": 0.03,
"productivity_factor": 1.0,
"overtime_factor": 1.5,
"skill_premium": 0.1,
"applicable_to": "labor"
},
{
"id": "EQP-001",
"name": "تسعير المعدات",
"description": "استراتيجية لتسعير المعدات تشمل تكاليف التشغيل والصيانة والاستهلاك",
"profit_margin": 0.18,
"risk_factor": 0.07,
"maintenance_factor": 0.1,
"depreciation_rate": 0.15,
"utilization_rate": 0.8,
"applicable_to": "equipment"
},
{
"id": "SUB-001",
"name": "تسعير المقاولين",
"description": "استراتيجية لتسعير أعمال المقاولين من الباطن مع مراعاة جودة العمل والالتزام",
"profit_margin": 0.10,
"risk_factor": 0.08,
"quality_factor": 1.0,
"reliability_factor": 1.0,
"market_competition": 0.05,
"applicable_to": "subcontractors"
}
]
}
def apply_strategy(self, strategy_id, item_data):
"""تطبيق استراتيجية التسعير حسب نوع البند"""
strategy = next((s for s in st.session_state.pricing_strategies["strategies"]
if s["id"] == strategy_id), None)
if not strategy:
return None
base_cost = self._calculate_base_cost(item_data, strategy)
adjustments = self._apply_strategy_adjustments(base_cost, strategy, item_data)
return {
"base_cost": base_cost,
"adjustments": adjustments,
"total_price": base_cost + sum(adjustments.values())
}
def _calculate_base_cost(self, item_data, strategy):
"""حساب التكلفة الأساسية حسب نوع البند"""
if strategy["applicable_to"] == "materials":
return self._calculate_materials_cost(item_data, strategy)
elif strategy["applicable_to"] == "labor":
return self._calculate_labor_cost(item_data, strategy)
elif strategy["applicable_to"] == "equipment":
return self._calculate_equipment_cost(item_data, strategy)
elif strategy["applicable_to"] == "subcontractors":
return self._calculate_subcontractor_cost(item_data, strategy)
return 0
def _calculate_materials_cost(self, item_data, strategy):
"""حساب تكلفة المواد مع العوامل المؤثرة"""
base_cost = item_data.get("unit_price", 0) * item_data.get("quantity", 0)
storage_cost = base_cost * strategy["storage_cost"]
transport_cost = base_cost * strategy["transport_cost"]
market_adjustment = base_cost * strategy["market_volatility"]
return base_cost + storage_cost + transport_cost + market_adjustment
def _calculate_labor_cost(self, item_data, strategy):
"""حساب تكلفة العمالة مع عوامل الإنتاجية والمهارة"""
daily_rate = item_data.get("daily_rate", 0)
productivity = item_data.get("productivity", 1.0) * strategy["productivity_factor"]
skill_level = item_data.get("skill_level", 1.0)
skill_premium = daily_rate * strategy["skill_premium"] * (skill_level - 1)
return (daily_rate + skill_premium) * productivity
def _calculate_equipment_cost(self, item_data, strategy):
"""حساب تكلفة المعدات مع الصيانة والاستهلاك"""
daily_rate = item_data.get("daily_rate", 0)
utilization = strategy["utilization_rate"]
maintenance = daily_rate * strategy["maintenance_factor"]
depreciation = daily_rate * strategy["depreciation_rate"]
return (daily_rate + maintenance + depreciation) / utilization
def _calculate_subcontractor_cost(self, item_data, strategy):
"""حساب تكلفة المقاولين من الباطن مع عوامل الجودة"""
base_cost = item_data.get("quoted_price", 0)
quality_adjustment = base_cost * (strategy["quality_factor"] - 1)
reliability_adjustment = base_cost * (strategy["reliability_factor"] - 1)
market_adjustment = base_cost * strategy["market_competition"]
return base_cost + quality_adjustment + reliability_adjustment + market_adjustment
def _apply_strategy_adjustments(self, base_cost, strategy, item_data):
"""تطبيق التعديلات حسب الاستراتيجية"""
return {
"profit": base_cost * strategy["profit_margin"],
"risk": base_cost * strategy["risk_factor"]
}
def render_strategy_selection(self):
"""عرض واجهة اختيار الاستراتيجية"""
st.subheader("اختيار استراتيجية التسعير")
item_type = st.selectbox(
"نوع البند",
["المواد", "العمالة", "المعدات", "المقاولين من الباطن"]
)
strategies = [s for s in st.session_state.pricing_strategies["strategies"]
if s["applicable_to"] == self._get_type_key(item_type)]
selected_strategy = st.selectbox(
"اختر الاستراتيجية المناسبة",
options=[s["id"] for s in strategies],
format_func=lambda x: next(s["name"] for s in strategies if s["id"] == x)
)
if selected_strategy:
strategy = next(s for s in strategies if s["id"] == selected_strategy)
st.info(strategy["description"])
self._render_strategy_params(strategy)
return selected_strategy
def _get_type_key(self, display_type):
"""تحويل النوع المعروض إلى المفتاح المناسب"""
type_map = {
"المواد": "materials",
"العمالة": "labor",
"المعدات": "equipment",
"المقاولين من الباطن": "subcontractors"
}
return type_map.get(display_type, "")
def _render_strategy_params(self, strategy):
"""عرض وتعديل معاملات الاستراتيجية"""
st.write("معاملات الاستراتيجية:")
cols = st.columns(2)
with cols[0]:
st.metric("هامش الربح", f"{strategy['profit_margin']*100:.1f}%")
st.metric("عامل المخاطرة", f"{strategy['risk_factor']*100:.1f}%")
with cols[1]:
if strategy["applicable_to"] == "materials":
st.metric("تكلفة التخزين", f"{strategy['storage_cost']*100:.1f}%")
st.metric("تكلفة النقل", f"{strategy['transport_cost']*100:.1f}%")
elif strategy["applicable_to"] == "labor":
st.metric("معامل الإنتاجية", f"{strategy['productivity_factor']:.2f}")
st.metric("علاوة المهارة", f"{strategy['skill_premium']*100:.1f}%")
elif strategy["applicable_to"] == "equipment":
st.metric("معدل الاستهلاك", f"{strategy['depreciation_rate']*100:.1f}%")
st.metric("معدل الاستغلال", f"{strategy['utilization_rate']*100:.1f}%")
elif strategy["applicable_to"] == "subcontractors":
st.metric("معامل الجودة", f"{strategy['quality_factor']:.2f}")
st.metric("معامل الموثوقية", f"{strategy['reliability_factor']:.2f}")
def render_strategy_results(self, strategy_id, items_data):
"""عرض نتائج تطبيق الاستراتيجية"""
if not items_data:
st.warning("لا توجد بنود لعرض النتائج")
return
results = []
for item in items_data:
result = self.apply_strategy(strategy_id, item)
if result:
results.append({
**item,
**result
})
if results:
df = pd.DataFrame(results)
st.dataframe(df)
# عرض الرسم البياني
st.bar_chart(df[["base_cost", "profit", "risk_cost", "local_content_adjustment"]])
def calculate_local_content(self, items_data):
"""حساب نسبة المحتوى المحلي"""
total_cost = 0
local_content_cost = 0
for item in items_data:
total_cost += item.get("total_cost", 0)
if item.get("is_local", False):
local_content_cost += item.get("total_cost", 0)
if total_cost > 0:
return (local_content_cost / total_cost) * 100
return 0
def get_strategy_by_id(self, strategy_id):
"""الحصول على استراتيجية بواسطة المعرف"""
strategies = st.session_state.pricing_strategies.get("strategies", [])
strategy = next((s for s in strategies if s["id"] == strategy_id), None)
return strategy
def apply_strategy_to_project(self, project_id, strategy_id):
"""تطبيق استراتيجية على مشروع"""
pass
def get_project_by_id(self, project_id):
"""الحصول على مشروع بواسطة الكود"""
projects = st.session_state.pricing_strategies["projects"]
project = projects[projects["id"] == project_id]
return project.iloc[0].to_dict() if not project.empty else None
def calculate_local_content(self, materials_percentage, local_materials_percentage, equipment_percentage, local_equipment_percentage, labor_percentage, local_labor_percentage, subcontractors_percentage, local_subcontractors_percentage):
"""حساب نسبة المحتوى المحلي"""
total_percentage = materials_percentage + equipment_percentage + labor_percentage + subcontractors_percentage
if total_percentage != 100:
return False, f"إجمالي النسب يجب أن يكون 100%، الإجمالي الحالي: {total_percentage}%"
local_content = (
materials_percentage * local_materials_percentage / 100 +
equipment_percentage * local_equipment_percentage / 100 +
labor_percentage * local_labor_percentage / 100 +
subcontractors_percentage * local_subcontractors_percentage / 100
)
return True, local_content
def compare_strategies(self, project_data, price_analysis):
"""مقارنة استراتيجيات التسعير المختلفة"""
strategies = self.get_strategies_list()
if not strategies:
return {"success": False, "message": "لا توجد استراتيجيات للمقارنة"}
try:
strategies_result = []
for strategy in strategies:
result = self.apply_strategy(strategy['id'], project_data) #modified to handle item data
if result['success']:
strategies_result.append(result)
return {
"success": True,
"strategies_result": strategies_result
}
except Exception as e:
return {"success": False, "message": str(e)}
def get_strategies_list(self):
"""الحصول على قائمة الاستراتيجيات النشطة"""
strategies = st.session_state.pricing_strategies.get("strategies", []) # Handle case where strategies might not exist yet.
return strategies
def render(self):
"""عرض واجهة استراتيجيات التسعير"""
st.markdown("## استراتيجيات التسعير المتقدمة")
# إنشاء تبويبات
tabs = st.tabs([
"الاستراتيجيات المتاحة",
"تطبيق الاستراتيجيات",
"إعدادات التسعير"
])
with tabs[0]:
self._render_strategies_list()
with tabs[1]:
self._render_strategy_application()
with tabs[2]:
self._render_pricing_settings()
def _render_strategies_list(self):
"""عرض قائمة الاستراتيجيات"""
st.markdown("### الاستراتيجيات المتاحة")
strategies = st.session_state.pricing_strategies.get("strategies", []) # Handle missing strategies
# تحويل البيانات للعرض
if strategies: #Added check for empty list
display_df = pd.DataFrame(strategies)
display_df = display_df[["name", "description", "profit_margin", "risk_factor", "local_content_factor"]].copy()
display_df.columns = ["الاستراتيجية", "الوصف", "هامش الربح", "عامل المخاطرة", "عامل المحتوى المحلي"]
st.dataframe(display_df, use_container_width=True)
else:
st.write("لا توجد استراتيجيات متاحة حاليًا.")
def _render_strategy_application(self):
"""عرض واجهة تطبيق الاستراتيجيات"""
st.markdown("### تطبيق استراتيجية التسعير")
if 'current_project' not in st.session_state:
st.warning("يرجى اختيار مشروع أولاً")
return
project = st.session_state.current_project
strategies = st.session_state.pricing_strategies["strategies"]
render_items_management()
selected_strategy = self.render_strategy_selection()
if selected_strategy:
if st.button("تطبيق الاستراتيجية المختارة"):
if project and "items" in project:
strategy = next(s for s in strategies if s["id"] == selected_strategy)
st.subheader(f"نتائج تطبيق {strategy['name']}")
for item in project["items"]:
result = self.apply_strategy(selected_strategy, item)
if result:
st.write(f"نتائج تطبيق الاستراتيجية على البند: {item.get('code', 'غير محدد')}")
st.write(result)
else:
st.error("لا توجد بيانات للبنود في المشروع الحالي.")
def _render_pricing_settings(self):
"""عرض إعدادات التسعير"""
st.markdown("### إعدادات التسعير")
with st.form("pricing_settings"):
st.number_input("الحد الأدنى لهامش الربح", 0.0, 1.0, 0.15)
st.number_input("الحد الأقصى لهامش الربح", 0.0, 1.0, 0.30)
st.number_input("نسبة المحتوى المحلي المستهدفة", 0.0, 1.0, 0.40)
if st.form_submit_button("حفظ الإعدادات"):
st.success("تم حفظ الإعدادات بنجاح")
def _calculate_base_costs(self, project_data):
"""حساب التكاليف الأساسية"""
if not project_data:
return {}
materials_cost = sum(item.get("materials_cost", 0) for item in project_data.get("items", []))
equipment_cost = sum(item.get("equipment_cost", 0) for item in project_data.get("items", []))
labor_cost = sum(item.get("labor_cost", 0) for item in project_data.get("items", []))
subcontractors_cost = sum(item.get("subcontractors_cost", 0) for item in project_data.get("items", []))
return {
"materials": materials_cost,
"equipment": equipment_cost,
"labor": labor_cost,
"subcontractors": subcontractors_cost,
"total": materials_cost + equipment_cost + labor_cost + subcontractors_cost
}
def _calculate_final_price(self, base_costs, strategy_factors):
"""حساب السعر النهائي"""
total_base_cost = base_costs["total"]
profit = total_base_cost * strategy_factors["profit_margin"]
risk_cost = total_base_cost * strategy_factors["risk_factor"]
local_content_adjustment = total_base_cost * (strategy_factors["local_content_factor"] - 1)
return {
"base_cost": total_base_cost,
"profit": profit,
"risk_cost": risk_cost,
"local_content_adjustment": local_content_adjustment,
"total": total_base_cost + profit + risk_cost + local_content_adjustment
}
def render_items_management():
st.header("نظام إدارة البنود")
tab1, tab2, tab3 = st.tabs(["إضافة بنود يدوياً", "استيراد من Excel", "البنود الجاهزة"])
with tab1:
with st.form("manual_item_entry"):
item_code = st.text_input("رمز البند")
item_desc = st.text_area("وصف البند")
unit = st.selectbox("الوحدة", ["متر مربع", "متر مكعب", "متر طولي", "عدد", "طن", "كجم"])
quantity = st.number_input("الكمية", min_value=0.0)
item_type = st.selectbox("نوع البند", ["المواد", "العمالة", "المعدات", "المقاولين من الباطن"])
col1, col2 = st.columns(2)
with col1:
material_cost = st.number_input("تكلفة المواد", min_value=0.0)
labor_cost = st.number_input("تكلفة العمالة", min_value=0.0)
with col2:
equipment_cost = st.number_input("تكلفة المعدات", min_value=0.0)
overhead_cost = st.number_input("التكاليف غير المباشرة", min_value=0.0)
if st.form_submit_button("إضافة البند"):
if item_code and item_desc:
if 'items' not in st.session_state:
st.session_state.items = []
item_data = {
'code': item_code,
'description': item_desc,
'unit': unit,
'quantity': quantity,
'item_type': item_type,
'materials_cost': material_cost,
'labor_cost': labor_cost,
'equipment_cost': equipment_cost,
'subcontractors_cost': overhead_cost,
'total_cost': material_cost + labor_cost + equipment_cost + overhead_cost
}
if item_type == "المواد":
item_data['unit_price'] = material_cost / quantity if quantity > 0 else 0
elif item_type == "العمالة":
item_data['daily_rate'] = labor_cost / quantity if quantity > 0 else 0
elif item_type == "المعدات":
item_data['daily_rate'] = equipment_cost / quantity if quantity > 0 else 0
elif item_type == "المقاولين من الباطن":
item_data['quoted_price'] = overhead_cost
st.session_state.items.append(item_data)
st.success("تم إضافة البند بنجاح")
with tab2:
uploaded_file = st.file_uploader("اختر ملف Excel", type=['xlsx', 'xls'])
if uploaded_file:
df = pd.read_excel(uploaded_file)
st.dataframe(df)
if st.button("استيراد البنود"):
# معالجة وتخزين البنود من Excel
st.success("تم استيراد البنود بنجاح")
with tab3:
# عرض البنود المخزنة مسبقاً
if 'items' in st.session_state:
df = pd.DataFrame(st.session_state.items)
st.dataframe(df)