import streamlit as st import pandas as pd from pricing_system.modules.stages.project_entry import render_project_entry from pricing_system.modules.pricing_strategies import balanced_pricing from pricing_system.modules.indirect_support import overheads from pricing_system.modules.analysis.smart_price_analysis import SmartPriceAnalysis from pricing_system.modules.analysis.market_analysis import MarketAnalysis import openpyxl from pricing_system.modules.risk_analysis.risk_analyzer import RiskAnalyzer from pricing_system.modules.reference_guides.pricing_guidelines import PricingGuidelines import os from datetime import datetime import pdfkit class ReferenceGuides: def render(self): st.title("المراجع والأدلة") st.markdown("## دليل تحليل أسعار بنود الإنشاءات") st.markdown("**المرجع الأول:** [رابط للمرجع الأول](link_to_reference_1)") st.markdown("**المرجع الثاني:** [رابط للمرجع الثاني](link_to_reference_2)") class IntegratedApp: def __init__(self): from config_manager import ConfigManager config_manager = ConfigManager() config_manager.set_page_config_if_needed( page_title="نظام التسعير المتكامل", page_icon="💰", layout="wide", initial_sidebar_state="expanded" ) if 'pricing_stage' not in st.session_state: st.session_state.pricing_stage = 1 if 'current_project' not in st.session_state: st.session_state.current_project = { 'name': '', 'code': '', 'boq_items': [], 'indirect_costs': { 'overhead': 0.15, 'profit': 0.10, 'risk': 0.05 } } elif 'boq_items' not in st.session_state.current_project: st.session_state.current_project['boq_items'] = [] self.smart_analysis = SmartPriceAnalysis() self.market_analysis = MarketAnalysis() self.risk_analyzer = RiskAnalyzer() self.reference_guides = ReferenceGuides() def run(self): st.markdown(""" """, unsafe_allow_html=True) st.markdown('

نظام التسعير المتكامل

', unsafe_allow_html=True) st.sidebar.markdown('', unsafe_allow_html=True) self._render_sidebar_stages() if st.session_state.pricing_stage == 1: self._render_project_entry() elif st.session_state.pricing_stage == 2: self._render_boq_items() elif st.session_state.pricing_stage == 3: self._render_price_analysis() elif st.session_state.pricing_stage == 4: self._render_risk_analysis() elif st.session_state.pricing_stage == 5: self._render_pricing_strategies() elif st.session_state.pricing_stage == 6: self._render_local_content() elif st.session_state.pricing_stage == 7: self._render_final_boq() elif st.session_state.pricing_stage == 8: self._render_reference_guides() self._render_navigation() def _render_sidebar_stages(self): st.sidebar.markdown("### مراحل التسعير") stages = [ "بيانات المشروع", "جدول الكميات", "تحليل الأسعار", "تحليل المخاطر", "استراتيجيات التسعير", "المحتوى المحلي", "الجدول النهائي", "المراجع والأدلة" ] for i, stage in enumerate(stages, 1): if st.session_state.pricing_stage > i: status = "✓" elif st.session_state.pricing_stage == i: status = "🔄" else: status = "" st.sidebar.markdown(f"{i}. {stage} {status}") def _render_project_entry(self): st.title("بيانات المشروع") if 'current_project' not in st.session_state: st.session_state.current_project = {} st.session_state.show_entry_form = True if st.session_state.get('show_entry_form', True): st.subheader("إدخال بيانات المشروع") with st.form("project_entry_form"): col1, col2 = st.columns(2) with col1: name = st.text_input("اسم المشروع") code = st.text_input("رقم المشروع") location = st.text_input("الموقع") with col2: start_date = st.date_input("تاريخ البدء") duration = st.number_input("مدة المشروع (يوم)", min_value=1, value=180) budget = st.number_input("الميزانية (ريال)", min_value=0.0, step=1000.0) description = st.text_area("وصف المشروع") if st.form_submit_button("حفظ البيانات"): st.session_state.current_project.update({ 'name': name, 'code': code, 'location': location, 'start_date': start_date, 'duration': duration, 'budget': budget, 'description': description }) st.session_state.show_entry_form = False st.success("تم حفظ بيانات المشروع بنجاح!") st.rerun() else: st.subheader("بيانات المشروع المحفوظة") col1, col2 = st.columns(2) with col1: st.markdown(f"**اسم المشروع:** {st.session_state.current_project.get('name', '')}") st.markdown(f"**رقم المشروع:** {st.session_state.current_project.get('code', '')}") st.markdown(f"**الموقع:** {st.session_state.current_project.get('location', '')}") with col2: st.markdown(f"**تاريخ البدء:** {st.session_state.current_project.get('start_date', '')}") st.markdown(f"**مدة المشروع:** {st.session_state.current_project.get('duration', '')} يوم") st.markdown(f"**الميزانية:** {st.session_state.current_project.get('budget', '')} ريال") st.markdown(f"**الوصف:** {st.session_state.current_project.get('description', '')}") if st.button("تعديل البيانات"): st.session_state.show_entry_form = True st.rerun() def _render_boq_items(self): st.title("جدول الكميات") tabs = st.tabs(["إدخال البنود", "استيراد/تصدير جدول الكميات", "تحليل البنود"]) with tabs[0]: st.subheader("إضافة بند جديد") st.markdown("### إضافة بند جديد") new_item_type = st.selectbox("نوع البند", ["عمالة", "معدات", "مواد"]) col1, col2, col3 = st.columns(3) with col1: item_name = st.text_input("اسم البند") with col2: item_quantity = st.number_input("الكمية", min_value=0.0, step=0.1) with col3: item_price = st.number_input("السعر", min_value=0.0, step=0.1) if st.button("إضافة البند"): new_item = { "type": new_item_type, "name": item_name, "quantity": item_quantity, "price": item_price, "total": item_quantity * item_price } if new_item_type == "عمالة": if 'labor' not in st.session_state.current_project: st.session_state.current_project['labor'] = [] st.session_state.current_project['labor'].append(new_item) elif new_item_type == "معدات": if 'equipment' not in st.session_state.current_project: st.session_state.current_project['equipment'] = [] st.session_state.current_project['equipment'].append(new_item) else: if 'materials' not in st.session_state.current_project: st.session_state.current_project['materials'] = [] st.session_state.current_project['materials'].append(new_item) st.success(f"تم إضافة {item_name} بنجاح") st.rerun() with st.form("boq_item_form"): col1, col2 = st.columns(2) with col1: item_code = st.text_input("كود البند") item_desc = st.text_area("وصف البند") quantity = st.number_input("الكمية", min_value=0.0) with col2: unit = st.selectbox("الوحدة", ["متر مربع", "متر مكعب", "متر طولي", "عدد", "طن", "كجم"]) unit_price = st.number_input("سعر الوحدة", min_value=0.0) if st.form_submit_button("إضافة البند"): if not item_code or not item_desc or quantity <= 0 or unit_price <= 0: st.error("يرجى إدخال جميع البيانات المطلوبة") else: new_item = { 'code': item_code, 'description': item_desc, 'unit': unit, 'quantity': quantity, 'unit_price': unit_price, 'total_price': quantity * unit_price } st.session_state.current_project['boq_items'].append(new_item) st.success("تم إضافة البند بنجاح") st.rerun() with tabs[1]: st.subheader("استيراد/تصدير جدول الكميات") uploaded_file = st.file_uploader("رفع ملف جدول كميات", type=['xlsx', 'xls'], key="boq_upload") if uploaded_file: try: df = pd.read_excel(uploaded_file) st.write("معاينة البيانات:") st.dataframe(df) if st.button("تأكيد استيراد البيانات", key="confirm_import"): for _, row in df.iterrows(): new_item = { 'code': str(row.get('كود البند', '')), 'description': str(row.get('وصف البند', '')), 'unit': str(row.get('الوحدة', '')), 'quantity': float(row.get('الكمية', 0)), 'unit_price': float(row.get('سعر الوحدة', 0)), 'total_price': float(row.get('السعر الإجمالي', 0)) } st.session_state.current_project['boq_items'].append(new_item) st.success("تم استيراد البيانات بنجاح") st.rerun() except Exception as e: st.error(f"حدث خطأ أثناء استيراد الملف: {str(e)}") st.divider() if st.session_state.current_project.get('boq_items'): if st.button("تصدير جدول الكميات الحالي", key="export_current_boq"): try: df = pd.DataFrame(st.session_state.current_project['boq_items']) # Rename columns to Arabic df = df.rename(columns={ 'code': 'كود البند', 'description': 'وصف البند', 'unit': 'الوحدة', 'quantity': 'الكمية', 'unit_price': 'سعر الوحدة', 'total_price': 'السعر الإجمالي' }) timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") excel_file = f"data/exports/boq_{timestamp}.xlsx" os.makedirs("data/exports", exist_ok=True) df.to_excel(excel_file, index=False) with open(excel_file, 'rb') as f: st.download_button( label="تحميل الملف", data=f, file_name=f"boq_{timestamp}.xlsx", mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", key="download_boq" ) except Exception as e: st.error(f"حدث خطأ أثناء تصدير الملف: {str(e)}") with tabs[2]: st.subheader("تحليل البنود") if st.session_state.current_project.get('boq_items'): df = pd.DataFrame(st.session_state.current_project['boq_items']) categories = ["أعمال ترابية", "أعمال خرسانية", "أعمال حديد", "أعمال بناء", "أعمال تشطيبات"] selected_category = st.selectbox("اختر فئة البند", categories) if 'category' in df.columns: category_items = df[df['category'] == selected_category] if not category_items.empty: st.write("### البنود المتاحة في هذه الفئة:") for _, item in category_items.iterrows(): st.write(f"- {item['description']}") else: st.info("لا توجد بنود في هذه الفئة") total_cost = df['total_price'].sum() st.metric("إجمالي التكاليف", f"{total_cost:,.2f} ريال") st.subheader("توزيع التكاليف حسب الوحدات") unit_costs = df.groupby('unit')['total_price'].sum() st.bar_chart(unit_costs) st.subheader("البنود الأعلى تكلفة") top_items = df.nlargest(5, 'total_price')[['code', 'description', 'total_price']] st.dataframe(top_items) st.subheader("تحليل تفصيلي للبند") selected_item = st.selectbox("اختر بند للتحليل", df['code'].tolist()) if selected_item: item = df[df['code'] == selected_item].iloc[0] col1, col2 = st.columns(2) with col1: st.write("**الوصف:**", item['description']) st.write("**الكمية:**", item['quantity']) with col2: st.write("**سعر الوحدة:**", f"{item['unit_price']:,.2f} ريال") st.write("**الإجمالي:**", f"{item['total_price']:,.2f} ريال") else: st.warning("لا توجد بنود للتحليل. الرجاء إضافة بنود أولاً.") if st.session_state.current_project['boq_items']: st.markdown("### البنود المضافة") for idx, item in enumerate(st.session_state.current_project['boq_items']): st.markdown(f"### البند {idx+1}: {item['description'][:50]}...") col1, col2, col3 = st.columns([2,2,1]) with col1: st.text_input("كود البند", value=item['code'], key=f"code_{idx}") st.text_area("وصف البند", value=item['description'], key=f"desc_{idx}") if st.checkbox(f"عرض تحليل مكونات البند {idx+1}", key=f"show_analysis_{idx}"): with st.expander("تحليل مكونات البند"): # المواد st.subheader("المواد") materials_container = st.container() with materials_container: if 'materials' not in st.session_state: st.session_state.materials = [] materials = st.session_state.materials for i in range(len(materials)): cols = st.columns([3, 2, 2, 1]) with cols[0]: materials[i]['name'] = st.selectbox(f"المادة {i+1}", ["اسمنت", "رمل", "حصى", "حديد"], key=f"mat_{idx}_{i}", index = 0 if materials[i]['name'] == "" else ["اسمنت", "رمل", "حصى", "حديد"].index(materials[i]['name'])) with cols[1]: unit_col1, unit_col2 = st.columns(2) with unit_col1: materials[i]['unit'] = st.selectbox( "وحدة القياس", ["متر مربع", "متر مكعب", "متر طولي", "رول", "بوكس", "كجم", "طن", "عدد", "لتر"], key=f"mat_unit_{idx}_{i}" ) with unit_col2: try: current_qty = float(materials[i]['quantity']) except (ValueError, TypeError): current_qty = 0.0 materials[i]['quantity'] = st.number_input( "الكمية", min_value=0.0, value=current_qty, key=f"mat_qty_{idx}_{i}" ) with cols[2]: try: current_price = float(materials[i]['price']) except (ValueError, TypeError): current_price = 0.0 materials[i]['price'] = st.number_input("السعر", min_value=0.0, value=current_price, key=f"mat_price_{idx}_{i}") with cols[3]: materials[i]['total'] = materials[i]['quantity'] * materials[i]['price'] st.text(f"{materials[i]['total']:.2f}") if st.button("🗑️ حذف", key=f"delete_mat_{idx}_{i}"): if len(materials) > i: materials.pop(i) st.rerun() if st.button("➕ إضافة مادة جديدة", key=f"add_mat_{idx}"): materials.append({ "name": "", "quantity": 0, "price": 0, "total": 0 }) st.rerun() # العمالة st.subheader("العمالة") with st.container(): labor_container = st.container() with labor_container: if 'labor' not in st.session_state: st.session_state.labor = [] labor = st.session_state.labor for i in range(len(labor)): cols = st.columns([3, 2, 2, 1]) with cols[0]: labor[i]['name'] = st.selectbox(f"العامل {i+1}", ["نجار", "حداد", "عامل", "فني"], key=f"labor_{idx}_{i}") with cols[1]: labor[i]['quantity'] = st.number_input("العدد", min_value=0, value=labor[i].get('quantity', 0), key=f"labor_qty_{idx}_{i}") with cols[2]: current_price = float(labor[i].get('price', 0.0)) labor[i]['price'] = st.number_input("الأجر اليومي", min_value=0.0, value=current_price, key=f"labor_price_{idx}_{i}") with cols[3]: labor[i]['total'] = labor[i]['quantity'] * labor[i]['price'] st.text(f"{labor[i]['total']:.2f}") if st.button("🗑️ حذف", key=f"delete_labor_{idx}_{i}"): if len(labor) > i: labor.pop(i) st.rerun() if st.button("➕ إضافة عامل جديد", key=f"add_labor_{idx}"): labor.append({ "name": "", "quantity": 0, "price": 0, "total": 0 }) st.rerun() # المعدات st.subheader("المعدات") equipment_container = st.container() with equipment_container: if 'equipment' not in st.session_state: st.session_state.equipment = [] equipment = st.session_state.equipment for i in range(len(equipment)): cols = st.columns([3, 2, 2, 1]) with cols[0]: equipment[i]['name'] = st.selectbox(f"المعدة {i+1}", ["خلاطة", "هزاز", "ونش", "مضخة"], key=f"equip_{idx}_{i}") with cols[1]: equipment[i]['quantity'] = st.number_input("العدد", min_value=0, value=int(equipment[i].get('quantity', 0)), key=f"equip_qty_{idx}_{i}") with cols[2]: current_price = float(equipment[i].get('price', 0.0)) equipment[i]['price'] = st.number_input("السعر اليومي", min_value=0.0, value=current_price, key=f"equip_price_{idx}_{i}") with cols[3]: equipment[i]['total'] = equipment[i]['quantity'] * equipment[i]['price'] st.text(f"{equipment[i]['total']:.2f}") if st.button("🗑️ حذف", key=f"delete_equip_{idx}_{i}"): if len(equipment) > i: equipment.pop(i) st.rerun() if st.button("➕ إضافة معدة جديدة", key=f"add_equip_{idx}"): equipment.append({ "name": "", "quantity": 0, "price": 0, "total": 0 }) st.rerun() col1, col2 = st.columns(2) with col1: if st.button("➕ إضافة بند جديد", key=f"add_item_{idx}"): if 'materials' not in st.session_state: st.session_state.materials = [] st.session_state.materials.append({ "name": "", "quantity": 0, "price": 0, "total": 0 }) st.rerun() with col2: if st.button("❌ حذف البند", key=f"delete_item_{idx}"): if len(st.session_state.materials) > 0: st.session_state.materials.pop() st.rerun() total_materials = sum(m["total"] for m in materials) total_labor = sum(l["total"] for l in labor) total_equipment = sum(e["total"] for e in equipment) total_cost = total_materials + total_labor + total_equipment st.markdown("---") st.subheader("ملخص التكاليف والحاسبة") col1, col2, col3, col4 = st.columns(4) with col1: st.metric("تكلفة المواد", f"{total_materials:.2f}") with col2: st.metric("تكلفة العمالة", f"{total_labor:.2f}") with col3: st.metric("تكلفة المعدات", f"{total_equipment:.2f}") with col4: st.metric("التكلفة الإجمالية", f"{total_cost:.2f}") st.markdown("### الحاسبة") calc_col1, calc_col2, calc_col3 = st.columns([2,1,2]) with calc_col1: num1 = st.number_input("الرقم الأول", value=0.0, format="%.2f") num2 = st.number_input("الرقم الثاني", value=0.0, format="%.2f") with calc_col2: operation = st.selectbox("العملية", ['+', '-', '×', '÷']) with calc_col3: if operation == '+': result = num1 + num2 elif operation == '-': result = num1 - num2 elif operation == '×': result = num1 * num2 elif operation == '÷': result = num1 / num2 if num2 != 0 else 0 st.metric("النتيجة", f"{result:.2f}") unit_cost = total_cost / quantity if quantity > 0 else 0 st.success(f"تكلفة الوحدة: {unit_cost:.2f}") if st.button("تطبيق السعر", key=f"apply_price_{idx}"): item['unit_price'] = unit_cost item['total_price'] = unit_cost * quantity st.success("تم تحديث سعر البند") st.rerun() with col2: units_list = ["م3", "م2", "متر طولي", "عدد", "متر مربع", "طن", "كجم"] try: default_index = units_list.index(item['unit']) except ValueError: default_index = 0 unit = st.selectbox("الوحدة", units_list, key=f"unit_{idx}", index=default_index) quantity = st.number_input("الكمية", value=float(item['quantity']), key=f"quantity_{idx}") with col3: unit_price = st.number_input("سعر الوحدة", value=float(item['unit_price']), key=f"price_{idx}") if st.button("تحديث البند", key=f"update_{idx}"): st.session_state.current_project['boq_items'][idx].update({ 'code': st.session_state[f"code_{idx}"], 'description': st.session_state[f"desc_{idx}"], 'unit': st.session_state[f"unit_{idx}"], 'quantity': st.session_state[f"quantity_{idx}"], 'unit_price': st.session_state[f"price_{idx}"], 'total_price': st.session_state[f"quantity_{idx}"] * st.session_state[f"price_{idx}"] }) st.success("تم تحديث البند بنجاح") st.rerun() if st.button("حذف البند", key=f"delete_{idx}"): st.session_state.current_project['boq_items'].pop(idx) st.success("تم حذف البند بنجاح") st.rerun() df = pd.DataFrame(st.session_state.current_project['boq_items']) column_names = { 'code': 'كود البند', 'description': 'وصف البند', 'unit': 'الوحدة', 'quantity': 'الكمية', 'unit_price': 'سعر الوحدة', 'total_price': 'السعر الإجمالي' } df = df.rename(columns=column_names) st.markdown("### ملخص البنود") st.dataframe(df, use_container_width=True) def _render_price_analysis(self): st.title("تحليل الأسعار") tabs = st.tabs(["تحليل البنود", "تحليل التكاليف", "تحليل السوق", "التحليل الذكي"]) with tabs[0]: if 'current_project' in st.session_state and 'boq_items' in st.session_state.current_project: df = pd.DataFrame(st.session_state.current_project['boq_items']) if not df.empty: # تغيير أسماء الأعمدة إلى العربية df = df.rename(columns={ 'code': 'كود البند', 'description': 'وصف البند', 'unit': 'الوحدة', 'quantity': 'الكمية', 'unit_price': 'سعر الوحدة', 'total_price': 'السعر الإجمالي' }) st.dataframe(df) selected_item = st.selectbox("اختر بند للتحليل", df['كود البند'].tolist()) if selected_item: item = df[df['كود البند'] == selected_item].iloc[0] st.write("### تفاصيل البند") st.write(f"الوصف: {item['وصف البند']}") st.write(f"الكمية: {item['الكمية']}") st.write(f"سعر الوحدة: {item['سعر الوحدة']}") st.write(f"الإجمالي: {item['السعر الإجمالي']}") else: st.warning("لا توجد بنود مضافة بعد") else: st.warning("الرجاء إضافة بنود للمشروع أولاً") with tabs[1]: self._render_cost_analysis() with tabs[2]: self.market_analysis.render() with tabs[3]: self.smart_analysis.render() def _render_cost_analysis(self): if not st.session_state.current_project['boq_items']: st.warning("لا توجد بنود لتحليلها") return total_direct_cost = sum(item['total_price'] for item in st.session_state.current_project['boq_items']) indirect_costs = st.session_state.current_project['indirect_costs'] st.markdown("### ملخص التكاليف") col1, col2 = st.columns(2) with col1: st.metric("إجمالي التكاليف المباشرة", f"{total_direct_cost:,.2f} ريال") st.metric("المصاريف العامة", f"{total_direct_cost * indirect_costs['overhead']:,.2f} ريال") st.metric("هامش الربح", f"{total_direct_cost * indirect_costs['profit']:,.2f} ريال") with col2: st.metric("احتياطي المخاطر", f"{total_direct_cost * indirect_costs['risk']:,.2f} ريال") total_cost = total_direct_cost * (1 + sum(indirect_costs.values())) st.metric("إجمالي التكلفة", f"{total_cost:,.2f} ريال") def _render_risk_analysis(self): st.title("تحليل المخاطر") self.risk_analyzer.render() def _render_pricing_strategies(self): st.title("استراتيجيات التسعير") balanced_pricing.render_balanced_strategy() def _render_local_content(self): st.title("المحتوى المحلي") st.subheader("نسب المكونات المحلية") col1, col2 = st.columns(2) with col1: materials_percentage = st.number_input("نسبة المواد المحلية (%)", 0, 100, 40) equipment_percentage = st.number_input("نسبة المعدات المحلية (%)", 0, 100, 30) with col2: labor_percentage = st.number_input("نسبة العمالة المحلية (%)", 0, 100, 80) subcontractors_percentage = st.number_input("نسبة المقاولين المحليين (%)", 0, 100, 50) total_local_content = ( materials_percentage * 0.4 + equipment_percentage * 0.2 + labor_percentage * 0.3 + subcontractors_percentage * 0.1 ) st.markdown("### نتيجة تحليل المحتوى المحلي") st.metric("نسبة المحتوى المحلي الإجمالية", f"{total_local_content:.1f}%") if st.checkbox("عرض التحليل التفصيلي"): data = { 'المكون': ['المواد', 'المعدات', 'العمالة', 'المقاولين'], 'النسبة المحلية': [materials_percentage, equipment_percentage, labor_percentage, subcontractors_percentage] } df = pd.DataFrame(data) st.bar_chart(df.set_index('المكون')) def _render_final_boq(self): st.title("جدول الكميات النهائي") if not st.session_state.current_project['boq_items']: st.warning("لا توجد بنود في جدول الكميات") return # Create fresh DataFrame with numeric values df = pd.DataFrame(st.session_state.current_project['boq_items']) # Convert quantity and prices to float df['quantity'] = pd.to_numeric(df['quantity'], errors='coerce') df['unit_price'] = pd.to_numeric(df['unit_price'], errors='coerce') # Calculate total price df['total_price'] = df['quantity'] * df['unit_price'] # Calculate grand total total = df['total_price'].sum() # Format numbers for display df['quantity'] = df['quantity'].apply(lambda x: '{:.2f}'.format(x)) df['unit_price'] = df['unit_price'].apply(lambda x: '{:.2f}'.format(x)) df['total_price'] = df['total_price'].apply(lambda x: '{:.2f}'.format(x)) # Rename columns to Arabic # Get local content percentage if available local_content = 0 if hasattr(st.session_state, 'local_content'): materials_percentage = st.session_state.local_content.get('materials_local', 0.4) * 100 equipment_percentage = st.session_state.local_content.get('equipment_local', 0.3) * 100 labor_percentage = st.session_state.local_content.get('labor_local', 0.8) * 100 subcontractors_percentage = st.session_state.local_content.get('subcontractors_local', 0.5) * 100 local_content = ( materials_percentage * 0.4 + equipment_percentage * 0.2 + labor_percentage * 0.3 + subcontractors_percentage * 0.1 ) # Add local content column df['نسبة المحتوى المحلي'] = local_content df = df.rename(columns={ 'code': 'الكود', 'description': 'الوصف', 'unit': 'الوحدة', 'quantity': 'الكمية', 'unit_price': 'سعر الوحدة', 'total_price': 'السعر الإجمالي' }) # Add total row to display dataframe total_row = pd.DataFrame([{ 'الكود': 'الإجمالي', 'الوصف': '', 'الوحدة': '', 'الكمية': '', 'سعر الوحدة': '', 'السعر الإجمالي': f"{total:,.2f}" }]) # Combine original dataframe with total row df_with_total = pd.concat([df, total_row], ignore_index=True) st.dataframe( df_with_total, use_container_width=True, hide_index=True, column_config={ "الكود": st.column_config.TextColumn("الكود", width="small", help="كود البند"), "الوصف": st.column_config.TextColumn("الوصف", width="medium", help="وصف البند"), "الوحدة": st.column_config.TextColumn("الوحدة", width="small", help="وحدة القياس"), "الكمية": st.column_config.NumberColumn("الكمية", width="small", help="كمية البند", format="%.2f"), "سعر الوحدة": st.column_config.NumberColumn("سعر الوحدة", width="small", help="سعر الوحدة", format="%.2f"), "السعر الإجمالي": st.column_config.NumberColumn("السعر الإجمالي", width="small", help="السعر الإجمالي", format="%.2f"), "نسبة المحتوى المحلي": st.column_config.NumberColumn("نسبة المحتوى المحلي", width="small", help="نسبة المحتوى المحلي", format="%.1f%%") } ) st.metric("إجمالي جدول الكميات", f"{total:,.2f} ريال") # Show saved pricing history with export option if st.button("عرض التسعيرات المحفوظة", key="show_saved_pricing"): if 'saved_pricing' in st.session_state and st.session_state.saved_pricing: st.subheader("التسعيرات المحفوظة") # Create selection for saved pricing pricing_options = [f"{p['project_name']} - {p['timestamp']}" for p in st.session_state.saved_pricing] selected_pricing = st.selectbox("اختر التسعير", pricing_options, key="pricing_select") if selected_pricing: selected_idx = pricing_options.index(selected_pricing) pricing = st.session_state.saved_pricing[selected_idx] st.write(f"إجمالي السعر: {pricing['total_price']:,.2f} ريال") st.write(f"نسبة المحتوى المحلي: {pricing['local_content']:.1f}%") df = pd.DataFrame(pricing['items']) st.dataframe(df) # Export selected pricing to Excel if st.button("تصدير التسعير المحدد إلى Excel", key="export_selected_pricing"): try: export_path = "data/exports" os.makedirs(export_path, exist_ok=True) timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") excel_file = f"{export_path}/saved_pricing_{timestamp}.xlsx" # Create Excel writer with pd.ExcelWriter(excel_file, engine='openpyxl') as writer: df.to_excel(writer, index=False, sheet_name='التسعير المحفوظ') worksheet = writer.sheets['التسعير المحفوظ'] # Add summary information worksheet['A1'] = f"اسم المشروع: {pricing['project_name']}" worksheet['A2'] = f"التاريخ: {pricing['timestamp']}" worksheet['A3'] = f"إجمالي السعر: {pricing['total_price']:,.2f} ريال" worksheet['A4'] = f"نسبة المحتوى المحلي: {pricing['local_content']:.1f}%" # Provide download button with open(excel_file, 'rb') as f: excel_data = f.read() st.download_button( label="تحميل ملف Excel", data=excel_data, file_name=f"saved_pricing_{timestamp}.xlsx", mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ) st.success("تم تصدير التسعير المحدد بنجاح!") except Exception as e: st.error(f"حدث خطأ أثناء التصدير: {str(e)}") else: st.info("لا توجد تسعيرات محفوظة") col1, col2, col3, col4 = st.columns(4) # Add save button with col1: if st.button("💾 حفظ التسعير", key="save_pricing_btn"): try: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") pricing_data = { 'timestamp': timestamp, 'project_name': st.session_state.current_project.get('name', 'مشروع جديد'), 'total_price': total, 'items': df.to_dict('records'), 'local_content': local_content } # Save to session state database if 'saved_pricing' not in st.session_state: st.session_state.saved_pricing = [] # Check for duplicates before saving is_duplicate = False for saved_pricing in st.session_state.saved_pricing: if (saved_pricing['project_name'] == pricing_data['project_name'] and saved_pricing['total_price'] == pricing_data['total_price'] and saved_pricing['timestamp'] == pricing_data['timestamp']): is_duplicate = True break if not is_duplicate: st.session_state.saved_pricing.append(pricing_data) st.success("تم حفظ التسعير بنجاح!") else: st.warning("هذا التسعير موجود بالفعل!") except Exception as e: st.error(f"حدث خطأ أثناء الحفظ: {str(e)}") # Export button with col2: st.empty() # Placeholder for future functionality with col3: if st.button("تصدير إلى Excel"): try: export_path = "data/exports" os.makedirs(export_path, exist_ok=True) timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") excel_file = f"{export_path}/boq_{timestamp}.xlsx" # Add a total row total_row = pd.DataFrame([{ 'الكود': 'الإجمالي', 'الوصف': '', 'الوحدة': '', 'الكمية': '', 'سعر الوحدة': '', 'السعر الإجمالي': f"{total:,.2f}" }]) # Combine original dataframe with total row df_with_total = pd.concat([df, total_row], ignore_index=True) # Write to Excel with styling with pd.ExcelWriter(excel_file, engine='openpyxl') as writer: df_with_total.to_excel(writer, index=False, sheet_name='جدول الكميات') worksheet = writer.sheets['جدول الكميات'] # Style the total row for col in range(1, worksheet.max_column + 1): cell = worksheet.cell(row=len(df_with_total), column=col) cell.font = openpyxl.styles.Font(bold=True) with open(excel_file, 'rb') as f: excel_data = f.read() st.download_button( label="تحميل ملف Excel", data=excel_data, file_name=f"boq_{timestamp}.xlsx", mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ) st.success("تم تصدير الملف بنجاح!") except Exception as e: st.error(f"حدث خطأ أثناء التصدير: {str(e)}") with col2: if st.button("تصدير إلى PDF"): try: export_path = "data/exports" os.makedirs(export_path, exist_ok=True) timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") pdf_file = f"{export_path}/boq_{timestamp}.pdf" # Create HTML with Arabic support and styling html = f"""

جدول الكميات

{df.to_html(index=False)}

إجمالي جدول الكميات: {total:,.2f} ريال

""" # Configure PDF options options = { 'page-size': 'A4', 'margin-top': '1.0in', 'margin-right': '0.75in', 'margin-bottom': '1.0in', 'margin-left': '0.75in', 'encoding': 'UTF-8', 'enable-local-file-access': None } # Generate PDF pdfkit.from_string(html, pdf_file, options=options) # Provide download button with open(pdf_file, 'rb') as f: pdf_data = f.read() st.download_button( label="تحميل ملف PDF", data=pdf_data, file_name=f"boq_{timestamp}.pdf", mime="application/pdf" ) st.success("تم تصدير الملف بنجاح!") except Exception as e: st.error(f"حدث خطأ أثناء التصدير: {str(e)}") def _render_navigation(self): can_proceed = self._validate_current_stage() st.markdown("---") st.markdown(""" """, unsafe_allow_html=True) nav_col1, nav_col2, nav_col3 = st.columns([2, 4, 2]) with nav_col1: if st.session_state.pricing_stage > 1: st.button("⮕ السابق", key="prev_button", help="العودة للمرحلة السابقة", on_click=lambda: setattr(st.session_state, 'pricing_stage', st.session_state.pricing_stage - 1)) with nav_col2: st.markdown(f"

المرحلة {st.session_state.pricing_stage} من 8

", unsafe_allow_html=True) with nav_col3: if st.session_state.pricing_stage < 8: st.button("التالي ⬅️", key="next_button", help="الانتقال للمرحلة التالية", disabled=not can_proceed, on_click=lambda: setattr(st.session_state, 'pricing_stage', st.session_state.pricing_stage + 1)) progress = (st.session_state.pricing_stage - 1) / 7 st.progress(progress, text=f"اكتمال {int(progress * 100)}% من مراحل التسعير") progress = (st.session_state.pricing_stage - 1) / 7 st.progress(progress, text=f"اكتمال {int(progress * 100)}% من مراحل التسعير") def _validate_current_stage(self): if st.session_state.pricing_stage == 1: return True elif st.session_state.pricing_stage == 2: return len(st.session_state.current_project.get('boq_items', [])) > 0 elif st.session_state.pricing_stage == 3: return True elif st.session_state.pricing_stage == 4: return True return True def _render_reference_guides(self): self.reference_guides.render()