|
""" |
|
وحدة إدارة المشاريع - نظام تحليل المناقصات |
|
""" |
|
|
|
import streamlit as st |
|
import pandas as pd |
|
import numpy as np |
|
from datetime import datetime, timedelta |
|
import os |
|
import time |
|
import io |
|
import sys |
|
from pathlib import Path |
|
|
|
|
|
sys.path.append(str(Path(__file__).parent.parent)) |
|
|
|
|
|
from styling.enhanced_ui import UIEnhancer |
|
|
|
class ProjectsApp: |
|
"""وحدة إدارة المشاريع""" |
|
|
|
def __init__(self): |
|
"""تهيئة وحدة إدارة المشاريع""" |
|
self.ui = UIEnhancer(page_title="إدارة المشاريع - نظام تحليل المناقصات", page_icon="📋") |
|
self.ui.apply_theme_colors() |
|
|
|
|
|
if 'projects' not in st.session_state: |
|
st.session_state.projects = self._generate_sample_projects() |
|
|
|
def run(self): |
|
"""تشغيل وحدة إدارة المشاريع""" |
|
|
|
menu_items = [ |
|
{"name": "لوحة المعلومات", "icon": "house"}, |
|
{"name": "المناقصات والعقود", "icon": "file-text"}, |
|
{"name": "تحليل المستندات", "icon": "file-earmark-text"}, |
|
{"name": "نظام التسعير", "icon": "calculator"}, |
|
{"name": "حاسبة تكاليف البناء", "icon": "building"}, |
|
{"name": "الموارد والتكاليف", "icon": "people"}, |
|
{"name": "تحليل المخاطر", "icon": "exclamation-triangle"}, |
|
{"name": "إدارة المشاريع", "icon": "kanban"}, |
|
{"name": "الخرائط والمواقع", "icon": "geo-alt"}, |
|
{"name": "الجدول الزمني", "icon": "calendar3"}, |
|
{"name": "الإشعارات", "icon": "bell"}, |
|
{"name": "مقارنة المستندات", "icon": "files"}, |
|
{"name": "الترجمة", "icon": "translate"}, |
|
{"name": "المساعد الذكي", "icon": "robot"}, |
|
{"name": "التقارير", "icon": "bar-chart"}, |
|
{"name": "الإعدادات", "icon": "gear"} |
|
] |
|
|
|
|
|
selected = self.ui.create_sidebar(menu_items) |
|
|
|
|
|
self.ui.create_header("إدارة المشاريع", "إدارة ومتابعة المشاريع والمناقصات") |
|
|
|
|
|
tabs = st.tabs([ |
|
"قائمة المشاريع", |
|
"إضافة مشروع جديد", |
|
"تفاصيل المشروع", |
|
"متابعة المشاريع" |
|
]) |
|
|
|
with tabs[0]: |
|
self._render_projects_list_tab() |
|
|
|
with tabs[1]: |
|
self._render_add_project_tab() |
|
|
|
with tabs[2]: |
|
self._render_project_details_tab() |
|
|
|
with tabs[3]: |
|
self._render_projects_tracking_tab() |
|
|
|
def _render_projects_list_tab(self): |
|
"""عرض تبويب قائمة المشاريع""" |
|
|
|
st.markdown("### قائمة المشاريع") |
|
|
|
|
|
col1, col2, col3 = st.columns(3) |
|
|
|
with col1: |
|
search_term = st.text_input("البحث في المشاريع", key="project_search") |
|
|
|
with col2: |
|
status_filter = st.multiselect( |
|
"حالة المشروع", |
|
["جديد", "قيد التسعير", "تم التقديم", "تمت الترسية", "قيد التنفيذ", "منتهي", "ملغي"], |
|
default=["جديد", "قيد التسعير", "تم التقديم"], |
|
key="project_status_filter" |
|
) |
|
|
|
with col3: |
|
client_filter = st.multiselect( |
|
"الجهة المالكة", |
|
list(set([p['client'] for p in st.session_state.projects])), |
|
key="project_client_filter" |
|
) |
|
|
|
|
|
filtered_projects = st.session_state.projects |
|
|
|
if search_term: |
|
filtered_projects = [p for p in filtered_projects if search_term.lower() in p['name'].lower() or search_term in p['number']] |
|
|
|
if status_filter: |
|
filtered_projects = [p for p in filtered_projects if p['status'] in status_filter] |
|
|
|
if client_filter: |
|
filtered_projects = [p for p in filtered_projects if p['client'] in client_filter] |
|
|
|
|
|
if filtered_projects: |
|
projects_df = pd.DataFrame(filtered_projects) |
|
|
|
|
|
display_columns = [ |
|
'name', 'number', 'client', 'location', 'status', |
|
'submission_date', 'tender_type', 'created_at' |
|
] |
|
|
|
|
|
column_names = { |
|
'name': 'اسم المشروع', |
|
'number': 'رقم المناقصة', |
|
'client': 'الجهة المالكة', |
|
'location': 'الموقع', |
|
'status': 'الحالة', |
|
'submission_date': 'تاريخ التقديم', |
|
'tender_type': 'نوع المناقصة', |
|
'created_at': 'تاريخ الإنشاء' |
|
} |
|
|
|
display_df = projects_df[display_columns].rename(columns=column_names) |
|
|
|
|
|
date_columns = ['تاريخ التقديم', 'تاريخ الإنشاء'] |
|
for col in date_columns: |
|
if col in display_df.columns: |
|
display_df[col] = pd.to_datetime(display_df[col]).dt.strftime('%Y-%m-%d') |
|
|
|
|
|
st.dataframe(display_df, use_container_width=True, hide_index=True) |
|
|
|
|
|
if st.button("تصدير المشاريع إلى Excel"): |
|
|
|
st.success("تم تصدير المشاريع بنجاح!") |
|
else: |
|
st.info("لا توجد مشاريع تطابق معايير البحث.") |
|
|
|
def _render_add_project_tab(self): |
|
"""عرض تبويب إضافة مشروع جديد""" |
|
|
|
st.markdown("### إضافة مشروع جديد") |
|
|
|
|
|
with st.form("new_project_form"): |
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
project_name = st.text_input("اسم المشروع", key="new_project_name") |
|
client = st.text_input("الجهة المالكة", key="new_project_client") |
|
location = st.text_input("الموقع", key="new_project_location") |
|
tender_type = st.selectbox( |
|
"نوع المناقصة", |
|
["عامة", "خاصة", "أمر مباشر"], |
|
key="new_project_tender_type" |
|
) |
|
|
|
with col2: |
|
tender_number = st.text_input("رقم المناقصة", key="new_project_number") |
|
submission_date = st.date_input("تاريخ التقديم", key="new_project_submission_date") |
|
pricing_method = st.selectbox( |
|
"طريقة التسعير", |
|
["قياسي", "غير متزن", "تنافسي", "موجه بالربحية"], |
|
key="new_project_pricing_method" |
|
) |
|
status = st.selectbox( |
|
"حالة المشروع", |
|
["جديد", "قيد التسعير", "تم التقديم", "تمت الترسية", "قيد التنفيذ", "منتهي", "ملغي"], |
|
index=0, |
|
key="new_project_status" |
|
) |
|
|
|
description = st.text_area("وصف المشروع", key="new_project_description") |
|
|
|
submitted = st.form_submit_button("إضافة المشروع") |
|
|
|
if submitted: |
|
|
|
if not project_name or not tender_number or not client: |
|
st.error("يرجى تعبئة جميع الحقول الإلزامية (اسم المشروع، رقم المناقصة، الجهة المالكة).") |
|
else: |
|
|
|
new_project = { |
|
'id': len(st.session_state.projects) + 1, |
|
'name': project_name, |
|
'number': tender_number, |
|
'client': client, |
|
'location': location, |
|
'description': description, |
|
'status': status, |
|
'tender_type': tender_type, |
|
'pricing_method': pricing_method, |
|
'submission_date': submission_date, |
|
'created_at': datetime.now(), |
|
'created_by_id': 1 |
|
} |
|
|
|
|
|
st.session_state.projects.append(new_project) |
|
|
|
|
|
st.success(f"تم إضافة المشروع [{project_name}] بنجاح!") |
|
|
|
|
|
st.session_state.current_project = new_project |
|
|
|
def _render_project_details_tab(self): |
|
"""عرض تبويب تفاصيل المشروع""" |
|
|
|
st.markdown("### تفاصيل المشروع") |
|
|
|
|
|
if 'current_project' not in st.session_state or st.session_state.current_project is None: |
|
|
|
project_names = [p['name'] for p in st.session_state.projects] |
|
selected_project_name = st.selectbox("اختر المشروع", project_names) |
|
|
|
if selected_project_name: |
|
selected_project = next((p for p in st.session_state.projects if p['name'] == selected_project_name), None) |
|
if selected_project: |
|
st.session_state.current_project = selected_project |
|
else: |
|
st.warning("لم يتم العثور على المشروع المحدد.") |
|
return |
|
else: |
|
st.info("يرجى اختيار مشروع لعرض تفاصيله.") |
|
return |
|
|
|
|
|
project = st.session_state.current_project |
|
|
|
|
|
col1, col2, col3 = st.columns(3) |
|
|
|
with col1: |
|
st.markdown(f"**اسم المشروع**: {project['name']}") |
|
st.markdown(f"**رقم المناقصة**: {project['number']}") |
|
st.markdown(f"**الجهة المالكة**: {project['client']}") |
|
|
|
with col2: |
|
st.markdown(f"**الموقع**: {project['location']}") |
|
st.markdown(f"**نوع المناقصة**: {project['tender_type']}") |
|
st.markdown(f"**حالة المشروع**: {project['status']}") |
|
|
|
with col3: |
|
st.markdown(f"**طريقة التسعير**: {project['pricing_method']}") |
|
st.markdown(f"**تاريخ التقديم**: {project['submission_date'].strftime('%Y-%m-%d') if isinstance(project['submission_date'], datetime) else project['submission_date']}") |
|
st.markdown(f"**تاريخ الإنشاء**: {project['created_at'].strftime('%Y-%m-%d') if isinstance(project['created_at'], datetime) else project['created_at']}") |
|
|
|
|
|
st.markdown("#### وصف المشروع") |
|
st.text_area("", value=project.get('description', ''), disabled=True, height=100) |
|
|
|
|
|
st.markdown("#### مستندات المشروع") |
|
|
|
if 'documents' in project and project['documents']: |
|
docs_df = pd.DataFrame(project['documents']) |
|
st.dataframe(docs_df, use_container_width=True, hide_index=True) |
|
else: |
|
st.info("لا توجد مستندات مرتبطة بهذا المشروع حاليًا.") |
|
|
|
|
|
if st.button("إضافة مستندات"): |
|
st.session_state.upload_documents = True |
|
|
|
|
|
if 'upload_documents' in st.session_state and st.session_state.upload_documents: |
|
st.markdown("#### تحميل مستندات جديدة") |
|
|
|
uploaded_file = st.file_uploader("اختر ملفًا", type=['pdf', 'docx', 'xlsx', 'png', 'jpg', 'dwg']) |
|
doc_type = st.selectbox("نوع المستند", ["كراسة شروط", "عقد", "مخططات", "جدول كميات", "مواصفات فنية", "تعديلات وملاحق"]) |
|
|
|
if uploaded_file and st.button("تحميل المستند"): |
|
|
|
with st.spinner("جاري تحميل المستند..."): |
|
time.sleep(2) |
|
|
|
|
|
new_document = { |
|
'filename': uploaded_file.name, |
|
'type': doc_type, |
|
'upload_date': datetime.now().strftime('%Y-%m-%d'), |
|
'size': f"{uploaded_file.size / 1024:.1f} KB" |
|
} |
|
|
|
|
|
if 'documents' not in project: |
|
project['documents'] = [] |
|
|
|
project['documents'].append(new_document) |
|
|
|
st.success(f"تم تحميل المستند [{uploaded_file.name}] بنجاح!") |
|
st.session_state.upload_documents = False |
|
st.experimental_rerun() |
|
|
|
|
|
st.markdown("#### بنود وكميات المشروع") |
|
|
|
if 'items' in project and project['items']: |
|
items_df = pd.DataFrame(project['items']) |
|
st.dataframe(items_df, use_container_width=True, hide_index=True) |
|
|
|
|
|
if st.button("تحويل البنود إلى وحدة التسعير"): |
|
if 'manual_items' not in st.session_state: |
|
st.session_state.manual_items = pd.DataFrame() |
|
|
|
st.session_state.manual_items = items_df.copy() |
|
st.success("تم تحويل البنود إلى وحدة التسعير بنجاح!") |
|
else: |
|
st.info("لا توجد بنود وكميات لهذا المشروع حاليًا.") |
|
|
|
|
|
if st.button("استيراد البنود من تحليل المستندات"): |
|
st.warning("ميزة استيراد البنود من تحليل المستندات قيد التطوير.") |
|
|
|
|
|
col1, col2, col3 = st.columns(3) |
|
|
|
with col1: |
|
if st.button("تعديل المشروع"): |
|
st.session_state.edit_project = True |
|
st.experimental_rerun() |
|
|
|
with col2: |
|
if st.button("تصدير بيانات المشروع"): |
|
st.success("تم تصدير بيانات المشروع بنجاح!") |
|
|
|
with col3: |
|
if st.button("إرسال للاعتماد"): |
|
st.success("تم إرسال المشروع للاعتماد بنجاح!") |
|
|
|
|
|
if 'edit_project' in st.session_state and st.session_state.edit_project: |
|
st.markdown("#### تعديل المشروع") |
|
|
|
with st.form("edit_project_form"): |
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
project_name = st.text_input("اسم المشروع", value=project['name']) |
|
client = st.text_input("الجهة المالكة", value=project['client']) |
|
location = st.text_input("الموقع", value=project['location']) |
|
tender_type = st.selectbox( |
|
"نوع المناقصة", |
|
["عامة", "خاصة", "أمر مباشر"], |
|
index=["عامة", "خاصة", "أمر مباشر"].index(project['tender_type']) |
|
) |
|
|
|
with col2: |
|
tender_number = st.text_input("رقم المناقصة", value=project['number']) |
|
submission_date = st.date_input( |
|
"تاريخ التقديم", |
|
value=datetime.strptime(project['submission_date'], "%Y-%m-%d") if isinstance(project['submission_date'], str) else project['submission_date'] |
|
) |
|
pricing_method = st.selectbox( |
|
"طريقة التسعير", |
|
["قياسي", "غير متزن", "تنافسي", "موجه بالربحية"], |
|
index=["قياسي", "غير متزن", "تنافسي", "موجه بالربحية"].index(project['pricing_method']) |
|
) |
|
status = st.selectbox( |
|
"حالة المشروع", |
|
["جديد", "قيد التسعير", "تم التقديم", "تمت الترسية", "قيد التنفيذ", "منتهي", "ملغي"], |
|
index=["جديد", "قيد التسعير", "تم التقديم", "تمت الترسية", "قيد التنفيذ", "منتهي", "ملغي"].index(project['status']) |
|
) |
|
|
|
description = st.text_area("وصف المشروع", value=project.get('description', '')) |
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
submit = st.form_submit_button("حفظ التعديلات") |
|
|
|
with col2: |
|
cancel = st.form_submit_button("إلغاء") |
|
|
|
if submit: |
|
|
|
project['name'] = project_name |
|
project['number'] = tender_number |
|
project['client'] = client |
|
project['location'] = location |
|
project['description'] = description |
|
project['status'] = status |
|
project['tender_type'] = tender_type |
|
project['pricing_method'] = pricing_method |
|
project['submission_date'] = submission_date |
|
|
|
st.success("تم تحديث بيانات المشروع بنجاح!") |
|
st.session_state.edit_project = False |
|
st.experimental_rerun() |
|
|
|
elif cancel: |
|
st.session_state.edit_project = False |
|
st.experimental_rerun() |
|
|
|
def _render_projects_tracking_tab(self): |
|
"""عرض تبويب متابعة المشاريع""" |
|
|
|
st.markdown("### متابعة المشاريع") |
|
|
|
|
|
col1, col2, col3, col4 = st.columns(4) |
|
|
|
projects = st.session_state.projects |
|
|
|
with col1: |
|
total_projects = len(projects) |
|
self.ui.create_metric_card("إجمالي المشاريع", str(total_projects), None, self.ui.COLORS['primary']) |
|
|
|
with col2: |
|
active_projects = len([p for p in projects if p['status'] in ["قيد التسعير", "تم التقديم", "تمت الترسية", "قيد التنفيذ"]]) |
|
self.ui.create_metric_card("المشاريع النشطة", str(active_projects), None, self.ui.COLORS['success']) |
|
|
|
with col3: |
|
pending_submission = len([p for p in projects if p['status'] in ["جديد", "قيد التسعير"]]) |
|
self.ui.create_metric_card("مشاريع قيد التسعير", str(pending_submission), None, self.ui.COLORS['warning']) |
|
|
|
with col4: |
|
completed_projects = len([p for p in projects if p['status'] in ["منتهي"]]) |
|
self.ui.create_metric_card("المشاريع المنتهية", str(completed_projects), None, self.ui.COLORS['info']) |
|
|
|
|
|
st.markdown("#### توزيع المشاريع حسب الحالة") |
|
|
|
status_counts = {} |
|
for p in projects: |
|
status = p['status'] |
|
status_counts[status] = status_counts.get(status, 0) + 1 |
|
|
|
status_df = pd.DataFrame({ |
|
'الحالة': list(status_counts.keys()), |
|
'عدد المشاريع': list(status_counts.values()) |
|
}) |
|
|
|
st.bar_chart(status_df.set_index('الحالة')) |
|
|
|
|
|
st.markdown("#### المشاريع قيد المتابعة") |
|
|
|
|
|
active_projects_list = [p for p in projects if p['status'] in ["قيد التسعير", "تم التقديم", "تمت الترسية", "قيد التنفيذ"]] |
|
|
|
if active_projects_list: |
|
|
|
for p in active_projects_list: |
|
if isinstance(p['submission_date'], str): |
|
p['submission_date'] = datetime.strptime(p['submission_date'], "%Y-%m-%d") |
|
|
|
|
|
active_projects_list.sort(key=lambda x: x['submission_date']) |
|
|
|
|
|
active_df = pd.DataFrame(active_projects_list) |
|
|
|
|
|
display_columns = [ |
|
'name', 'number', 'client', 'status', |
|
'submission_date', 'tender_type' |
|
] |
|
|
|
|
|
column_names = { |
|
'name': 'اسم المشروع', |
|
'number': 'رقم المناقصة', |
|
'client': 'الجهة المالكة', |
|
'status': 'الحالة', |
|
'submission_date': 'تاريخ التقديم', |
|
'tender_type': 'نوع المناقصة' |
|
} |
|
|
|
|
|
display_df = active_df[display_columns].rename(columns=column_names) |
|
display_df['تاريخ التقديم'] = pd.to_datetime(display_df['تاريخ التقديم']).dt.strftime('%Y-%m-%d') |
|
|
|
|
|
st.dataframe(display_df, use_container_width=True, hide_index=True) |
|
else: |
|
st.info("لا توجد مشاريع نشطة حاليًا.") |
|
|
|
|
|
st.markdown("#### المواعيد المقبلة") |
|
|
|
upcoming_events = [] |
|
today = datetime.now().date() |
|
|
|
for p in projects: |
|
submission_date = p['submission_date'] |
|
if isinstance(submission_date, str): |
|
submission_date = datetime.strptime(submission_date, "%Y-%m-%d").date() |
|
elif isinstance(submission_date, datetime): |
|
submission_date = submission_date.date() |
|
|
|
|
|
if today <= submission_date <= today + timedelta(days=14) and p['status'] in ["قيد التسعير"]: |
|
days_left = (submission_date - today).days |
|
upcoming_events.append({ |
|
'المشروع': p['name'], |
|
'الحدث': 'موعد تقديم المناقصة', |
|
'التاريخ': submission_date.strftime('%Y-%m-%d'), |
|
'الأيام المتبقية': days_left |
|
}) |
|
|
|
if upcoming_events: |
|
events_df = pd.DataFrame(upcoming_events) |
|
st.dataframe(events_df, use_container_width=True, hide_index=True) |
|
else: |
|
st.info("لا توجد مواعيد قريبة.") |
|
|
|
def _generate_sample_projects(self): |
|
"""توليد بيانات افتراضية للمشاريع""" |
|
|
|
projects = [ |
|
{ |
|
'id': 1, |
|
'name': "إنشاء مبنى مستشفى الولادة والأطفال بمنطقة الشرقية", |
|
'number': "SHPD-2025-001", |
|
'client': "وزارة الصحة", |
|
'location': "الدمام، المنطقة الشرقية", |
|
'description': "يشمل المشروع إنشاء وتجهيز مبنى مستشفى الولادة والأطفال بسعة 300 سرير، ويتكون المبنى من 4 طوابق بمساحة إجمالية 15,000 متر مربع.", |
|
'status': "قيد التسعير", |
|
'tender_type': "عامة", |
|
'pricing_method': "قياسي", |
|
'submission_date': (datetime.now() + timedelta(days=5)), |
|
'created_at': datetime.now() - timedelta(days=10), |
|
'created_by_id': 1, |
|
'documents': [ |
|
{ |
|
'filename': "كراسة الشروط والمواصفات.pdf", |
|
'type': "كراسة شروط", |
|
'upload_date': (datetime.now() - timedelta(days=9)).strftime('%Y-%m-%d'), |
|
'size': "5.2 MB" |
|
}, |
|
{ |
|
'filename': "المخططات الهندسية.dwg", |
|
'type': "مخططات", |
|
'upload_date': (datetime.now() - timedelta(days=8)).strftime('%Y-%m-%d'), |
|
'size': "25.7 MB" |
|
}, |
|
{ |
|
'filename': "جدول الكميات.xlsx", |
|
'type': "جدول كميات", |
|
'upload_date': (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d'), |
|
'size': "1.8 MB" |
|
} |
|
], |
|
'items': [ |
|
{ |
|
'رقم البند': "A1", |
|
'وصف البند': "أعمال الحفر والردم", |
|
'الوحدة': "م3", |
|
'الكمية': 12500 |
|
}, |
|
{ |
|
'رقم البند': "A2", |
|
'وصف البند': "أعمال الخرسانة المسلحة للأساسات", |
|
'الوحدة': "م3", |
|
'الكمية': 3500 |
|
}, |
|
{ |
|
'رقم البند': "A3", |
|
'وصف البند': "أعمال حديد التسليح", |
|
'الوحدة': "طن", |
|
'الكمية': 450 |
|
} |
|
] |
|
}, |
|
{ |
|
'id': 2, |
|
'name': "صيانة وتطوير طريق الملك عبدالله", |
|
'number': "MOT-2025-042", |
|
'client': "وزارة النقل", |
|
'location': "الرياض، المنطقة الوسطى", |
|
'description': "صيانة وتطوير طريق الملك عبدالله بطول 25 كم، ويشمل المشروع إعادة الرصف وتحسين الإنارة وتركيب اللوحات الإرشادية.", |
|
'status': "تم التقديم", |
|
'tender_type': "عامة", |
|
'pricing_method': "غير متزن", |
|
'submission_date': (datetime.now() - timedelta(days=15)), |
|
'created_at': datetime.now() - timedelta(days=45), |
|
'created_by_id': 1 |
|
}, |
|
{ |
|
'id': 3, |
|
'name': "إنشاء محطة معالجة مياه الصرف الصحي", |
|
'number': "SWPC-2025-007", |
|
'client': "شركة المياه الوطنية", |
|
'location': "جدة، المنطقة الغربية", |
|
'description': "إنشاء محطة معالجة مياه الصرف الصحي بطاقة استيعابية 50,000 م3/يوم، مع جميع الأعمال المدنية والكهروميكانيكية.", |
|
'status': "تمت الترسية", |
|
'tender_type': "عامة", |
|
'pricing_method': "قياسي", |
|
'submission_date': (datetime.now() - timedelta(days=90)), |
|
'created_at': datetime.now() - timedelta(days=120), |
|
'created_by_id': 1 |
|
}, |
|
{ |
|
'id': 4, |
|
'name': "إنشاء منتزه الملك سلمان", |
|
'number': "RAM-2025-015", |
|
'client': "أمانة منطقة الرياض", |
|
'location': "الرياض، المنطقة الوسطى", |
|
'description': "إنشاء منتزه الملك سلمان على مساحة 500,000 متر مربع، ويشمل المشروع أعمال التشجير والتنسيق والمسطحات المائية والمباني الخدمية.", |
|
'status': "قيد التنفيذ", |
|
'tender_type': "عامة", |
|
'pricing_method': "قياسي", |
|
'submission_date': (datetime.now() - timedelta(days=180)), |
|
'created_at': datetime.now() - timedelta(days=210), |
|
'created_by_id': 1 |
|
}, |
|
{ |
|
'id': 5, |
|
'name': "إنشاء مبنى مختبرات كلية العلوم", |
|
'number': "KSU-2025-032", |
|
'client': "جامعة الملك سعود", |
|
'location': "الرياض، المنطقة الوسطى", |
|
'description': "إنشاء مبنى المختبرات الجديد لكلية العلوم بمساحة 8,000 متر مربع، ويتكون من 3 طوابق ويشمل تجهيز المعامل والمختبرات العلمية.", |
|
'status': "جديد", |
|
'tender_type': "خاصة", |
|
'pricing_method': "تنافسي", |
|
'submission_date': (datetime.now() + timedelta(days=10)), |
|
'created_at': datetime.now() - timedelta(days=5), |
|
'created_by_id': 1 |
|
}, |
|
{ |
|
'id': 6, |
|
'name': "توريد وتركيب أنظمة الطاقة الشمسية", |
|
'number': "SEC-2025-098", |
|
'client': "الشركة السعودية للكهرباء", |
|
'location': "تبوك، المنطقة الشمالية", |
|
'description': "توريد وتركيب أنظمة الطاقة الشمسية بقدرة 5 ميجاوات، مع جميع الأعمال المدنية والكهربائية.", |
|
'status': "جديد", |
|
'tender_type': "عامة", |
|
'pricing_method': "قياسي", |
|
'submission_date': (datetime.now() + timedelta(days=20)), |
|
'created_at': datetime.now() - timedelta(days=2), |
|
'created_by_id': 1 |
|
} |
|
] |
|
|
|
return projects |
|
|
|
|
|
if __name__ == "__main__": |
|
projects_app = ProjectsApp() |
|
projects_app.run() |
|
|