EGYADMIN commited on
Commit
b364a1a
·
verified ·
1 Parent(s): b17d178

Create web/pages/procurement.py

Browse files
Files changed (1) hide show
  1. web/pages/procurement.py +536 -0
web/pages/procurement.py ADDED
@@ -0,0 +1,536 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ import plotly.express as px
5
+ import plotly.graph_objects as go
6
+ from datetime import datetime, timedelta
7
+
8
+ def show_procurement():
9
+ """
10
+ عرض صفحة إدارة المشتريات والعقود
11
+ """
12
+ st.subheader("إدارة المشتريات والعقود")
13
+
14
+ # الخيارات الفرعية
15
+ tabs = st.tabs(["العقود النشطة", "أوامر الشراء", "المناقصات الداخلية", "تقييم الموردين"])
16
+
17
+ # تبويب العقود النشطة
18
+ with tabs[0]:
19
+ show_active_contracts()
20
+
21
+ # تبويب أوامر الشراء
22
+ with tabs[1]:
23
+ show_purchase_orders()
24
+
25
+ # تبويب المناقصات الداخلية
26
+ with tabs[2]:
27
+ show_internal_tenders()
28
+
29
+ # تبويب تقييم الموردين
30
+ with tabs[3]:
31
+ show_vendor_evaluation()
32
+
33
+ def show_active_contracts():
34
+ """
35
+ عرض بيانات العقود النشطة
36
+ """
37
+ st.markdown("## العقود النشطة")
38
+
39
+ # إنشاء بيانات توضيحية للعقود
40
+ current_date = datetime.now().date()
41
+
42
+ contracts_data = {
43
+ "رقم العقد": ["C-2025-1001", "C-2025-1042", "C-2024-0987", "C-2024-0912", "C-2025-1123",
44
+ "C-2024-0875", "C-2025-1088", "C-2025-1156", "C-2024-0932", "C-2025-1201"],
45
+ "المورد": ["شركة الصناعات السعودية", "مؤسسة الخليج للمقاولات", "شركة الرياض للإنشاءات",
46
+ "الشركة العربية للمعدات", "مصنع المنتجات الإسمنتية", "شركة تقنيات البناء",
47
+ "مؤسسة المدار للتوريدات", "شركة البنية التحتية المتكاملة", "مصنع الصلب السعودي",
48
+ "شركة الأنابيب الوطنية"],
49
+ "نوع العقد": ["توريد مواد", "مقاولات", "خدمات هندسية", "تأجير معدات", "توريد مواد",
50
+ "خدمات فنية", "توريد مواد", "مقاولات", "توريد مواد", "توريد مواد"],
51
+ "تاريخ البدء": [
52
+ current_date - timedelta(days=120),
53
+ current_date - timedelta(days=90),
54
+ current_date - timedelta(days=210),
55
+ current_date - timedelta(days=180),
56
+ current_date - timedelta(days=60),
57
+ current_date - timedelta(days=240),
58
+ current_date - timedelta(days=45),
59
+ current_date - timedelta(days=30),
60
+ current_date - timedelta(days=150),
61
+ current_date - timedelta(days=15)
62
+ ],
63
+ "تاريخ الانتهاء": [
64
+ current_date + timedelta(days=245),
65
+ current_date + timedelta(days=270),
66
+ current_date + timedelta(days=155),
67
+ current_date + timedelta(days=185),
68
+ current_date + timedelta(days=305),
69
+ current_date + timedelta(days=125),
70
+ current_date + timedelta(days=320),
71
+ current_date + timedelta(days=335),
72
+ current_date + timedelta(days=215),
73
+ current_date + timedelta(days=350)
74
+ ],
75
+ "القيمة (مليون ريال)": [12.5, 28.7, 8.3, 6.2, 9.1, 5.4, 7.8, 15.6, 11.2, 10.9],
76
+ "نسبة الإنجاز (%)": [45, 30, 75, 65, 20, 80, 15, 10, 60, 5]
77
+ }
78
+
79
+ # إنشاء DataFrame
80
+ contracts_df = pd.DataFrame(contracts_data)
81
+
82
+ # إضافة المدة المتبقية
83
+ contracts_df["المدة المتبقية (يوم)"] = (contracts_df["تاريخ الانتهاء"] - current_date).dt.days
84
+
85
+ # تصنيف الحالة
86
+ conditions = [
87
+ (contracts_df["المدة المتبقية (يوم)"] < 30),
88
+ (contracts_df["المدة المتبقية (يوم)"] < 90),
89
+ (contracts_df["المدة المتبقية (يوم)"] >= 90)
90
+ ]
91
+ values = ["على وشك الانتهاء", "متوسطة", "طويلة الأجل"]
92
+ colors = ["#D32F2F", "#FFC107", "#4CAF50"]
93
+
94
+ contracts_df["حالة العقد"] = np.select(conditions, values)
95
+
96
+ # عرض فلاتر البحث
97
+ col1, col2, col3 = st.columns(3)
98
+
99
+ with col1:
100
+ contract_type_filter = st.selectbox(
101
+ "نوع العقد",
102
+ ["الكل"] + sorted(contracts_df["نوع العقد"].unique().tolist())
103
+ )
104
+
105
+ with col2:
106
+ status_filter = st.selectbox(
107
+ "حالة العقد",
108
+ ["الكل"] + sorted(contracts_df["حالة العقد"].unique().tolist())
109
+ )
110
+
111
+ with col3:
112
+ min_value = st.number_input("الحد الأدنى للقيمة (مليون ريال)", 0.0, 50.0, 0.0)
113
+
114
+ # تطبيق الفلاتر
115
+ filtered_df = contracts_df.copy()
116
+
117
+ if contract_type_filter != "الكل":
118
+ filtered_df = filtered_df[filtered_df["نوع العقد"] == contract_type_filter]
119
+
120
+ if status_filter != "الكل":
121
+ filtered_df = filtered_df[filtered_df["حالة العقد"] == status_filter]
122
+
123
+ if min_value > 0:
124
+ filtered_df = filtered_df[filtered_df["القيمة (مليون ريال)"] >= min_value]
125
+
126
+ # عرض العقود المصفاة
127
+ st.dataframe(filtered_df, use_container_width=True)
128
+
129
+ # تحليلات العقود
130
+ st.markdown("### تحليلات العقود")
131
+
132
+ col1, col2 = st.columns(2)
133
+
134
+ with col1:
135
+ # توزيع العقود حسب النوع
136
+ type_distribution = contracts_df.groupby("نوع العقد")["القيمة (مليون ريال)"].sum().reset_index()
137
+
138
+ fig1 = px.pie(
139
+ type_distribution,
140
+ values="القيمة (مليون ريال)",
141
+ names="نوع العقد",
142
+ title="توزيع قيمة العقود حسب النوع",
143
+ color_discrete_sequence=px.colors.qualitative.Bold
144
+ )
145
+
146
+ fig1.update_traces(textposition="inside", textinfo="percent+label")
147
+
148
+ st.plotly_chart(fig1, use_container_width=True)
149
+
150
+ with col2:
151
+ # توزيع العقود حسب الحالة
152
+ status_distribution = contracts_df.groupby("حالة العقد").agg({
153
+ "رقم العقد": "count",
154
+ "القيمة (مليون ريال)": "sum"
155
+ }).reset_index()
156
+
157
+ status_distribution.columns = ["الحالة", "عدد العقود", "إجمالي القيمة (مليون ريال)"]
158
+
159
+ # ترتيب الحالات
160
+ status_order = {"على وشك الانتهاء": 1, "متوسطة": 2, "طويلة الأجل": 3}
161
+ status_distribution["الترتيب"] = status_distribution["الحالة"].map(status_order)
162
+ status_distribution = status_distribution.sort_values("الترتيب")
163
+
164
+ # اختيار الألوان حسب الحالة
165
+ status_colors = {"على وشك الانتهاء": "#D32F2F", "متوسطة": "#FFC107", "طويلة الأجل": "#4CAF50"}
166
+
167
+ fig2 = px.bar(
168
+ status_distribution,
169
+ x="الحالة",
170
+ y="إجمالي القيمة (مليون ريال)",
171
+ color="الحالة",
172
+ text="عدد العقود",
173
+ title="توزيع العقود حسب المدة المتبقية",
174
+ color_discrete_map=status_colors
175
+ )
176
+
177
+ fig2.update_traces(texttemplate="%{text} عقد", textposition="outside")
178
+
179
+ st.plotly_chart(fig2, use_container_width=True)
180
+
181
+ # العقود القريبة من الانتهاء
182
+ st.markdown("### العقود على وشك الانتهاء")
183
+
184
+ expiring_contracts = contracts_df[contracts_df["المدة المتبقية (يوم)"] < 30].sort_values("المدة المتبقية (يوم)")
185
+
186
+ if not expiring_contracts.empty:
187
+ for _, contract in expiring_contracts.iterrows():
188
+ st.markdown(f"""
189
+ **{contract['رقم العقد']} - {contract['المورد']}**
190
+ **نوع العقد:** {contract['نوع العقد']}
191
+ **المدة المتبقية:** {contract['المدة المتبقية (يوم)']} يوم
192
+ **نسبة الإنجاز:** {contract['نسبة الإنجاز (%)']}%
193
+ **القيمة:** {contract['القيمة (مليون ريال)']} مليون ريال
194
+ """)
195
+
196
+ # شريط التقدم
197
+ st.progress(contract['نسبة الإنجاز (%)'] / 100)
198
+ st.markdown("---")
199
+ else:
200
+ st.info("لا توجد عقود على وشك الانتهاء خلال الشهر القادم")
201
+
202
+ def show_purchase_orders():
203
+ """
204
+ عرض أوامر الشراء
205
+ """
206
+ st.markdown("## أوامر الشراء")
207
+
208
+ # إنشاء بيانات توضيحية لأوامر الشراء
209
+ current_date = datetime.now().date()
210
+
211
+ po_data = {
212
+ "رقم أمر الشراء": [f"PO-{2025}-{i:04d}" for i in range(1001, 1011)],
213
+ "المورد": [
214
+ "شركة الصناعات السعودية", "مؤسسة الخليج للمقاولات", "شركة الرياض للإنشاءات",
215
+ "الشركة العربية للمعدات", "مصنع المنتجات الإسمنتية", "شركة تقنيات البناء",
216
+ "مؤسسة المدار للتوريدات", "شركة البنية التحتية المتكاملة", "مصنع الصلب السعودي",
217
+ "شركة الأنابيب الوطنية"
218
+ ],
219
+ "المشروع": [
220
+ "مشروع توسعة شبكة الطرق", "بناء المدارس", "تطوير البنية التحتية",
221
+ "تحديث شبكة المياه", "بناء المستشفى التخصصي", "إنشاء مركز البيانات",
222
+ "توسعة المطار", "تطوير الحدائق ال��امة", "بناء المجمع السكني",
223
+ "تطوير شبكة الصرف الصحي"
224
+ ],
225
+ "تاريخ الطلب": [
226
+ current_date - timedelta(days=np.random.randint(5, 60)) for _ in range(10)
227
+ ],
228
+ "تاريخ التسليم المتوقع": [
229
+ current_date + timedelta(days=np.random.randint(5, 45)) for _ in range(10)
230
+ ],
231
+ "القيمة (ريال)": [
232
+ np.random.randint(50000, 5000000) for _ in range(10)
233
+ ],
234
+ "الحالة": np.random.choice(
235
+ ["جديد", "قيد المعالجة", "تم الشحن", "تم الاستلام", "مغلق"],
236
+ size=10,
237
+ p=[0.2, 0.3, 0.2, 0.2, 0.1]
238
+ )
239
+ }
240
+
241
+ # إنشاء DataFrame
242
+ po_df = pd.DataFrame(po_data)
243
+
244
+ # عرض فلاتر البحث
245
+ col1, col2 = st.columns(2)
246
+
247
+ with col1:
248
+ status_filter = st.selectbox(
249
+ "حالة أمر الشراء",
250
+ ["الكل"] + sorted(po_df["الحالة"].unique().tolist())
251
+ )
252
+
253
+ with col2:
254
+ vendor_filter = st.selectbox(
255
+ "المورد",
256
+ ["الكل"] + sorted(po_df["المورد"].unique().tolist())
257
+ )
258
+
259
+ # تطبيق الفلاتر
260
+ filtered_po = po_df.copy()
261
+
262
+ if status_filter != "الكل":
263
+ filtered_po = filtered_po[filtered_po["الحالة"] == status_filter]
264
+
265
+ if vendor_filter != "الكل":
266
+ filtered_po = filtered_po[filtered_po["المورد"] == vendor_filter]
267
+
268
+ # عرض أوامر الشراء المصفاة
269
+ st.dataframe(filtered_po, use_container_width=True)
270
+
271
+ # تحليلات أوامر الشراء
272
+ st.markdown("### تحليلات أوامر الشراء")
273
+
274
+ col1, col2 = st.columns(2)
275
+
276
+ with col1:
277
+ # توزيع أوامر الشراء حسب الحالة
278
+ status_counts = po_df.groupby("الحالة").size().reset_index(name="العدد")
279
+
280
+ fig1 = px.pie(
281
+ status_counts,
282
+ values="العدد",
283
+ names="الحالة",
284
+ title="توزيع أوامر الشراء حسب الحالة",
285
+ color_discrete_sequence=px.colors.qualitative.Bold
286
+ )
287
+
288
+ fig1.update_traces(textposition="inside", textinfo="percent+label")
289
+
290
+ st.plotly_chart(fig1, use_container_width=True)
291
+
292
+ with col2:
293
+ # قيمة أوامر الشراء حسب المورد
294
+ vendor_values = po_df.groupby("المورد")["القيمة (ريال)"].sum().reset_index()
295
+ vendor_values = vendor_values.sort_values("القيمة (ريال)", ascending=False).head(5)
296
+
297
+ fig2 = px.bar(
298
+ vendor_values,
299
+ x="المورد",
300
+ y="القيمة (ريال)",
301
+ title="أعلى 5 موردين حسب قيمة أوامر الشراء",
302
+ color="القيمة (ريال)",
303
+ color_continuous_scale="Viridis"
304
+ )
305
+
306
+ fig2.update_yaxes(title_text="القيمة (ريال)")
307
+
308
+ st.plotly_chart(fig2, use_container_width=True)
309
+
310
+ # إضافة أمر شراء جديد
311
+ st.markdown("### إضافة أمر شراء جديد")
312
+
313
+ with st.expander("إضافة أمر شراء جديد"):
314
+ col1, col2 = st.columns(2)
315
+
316
+ with col1:
317
+ new_vendor = st.selectbox("المورد", sorted(po_df["المورد"].unique().tolist()))
318
+ new_project = st.selectbox("المشروع", sorted(po_df["المشروع"].unique().tolist()))
319
+ new_value = st.number_input("القيمة (ريال)", min_value=1000, max_value=10000000, value=100000)
320
+
321
+ with col2:
322
+ new_delivery_date = st.date_input("تاريخ التسليم المتوقع", value=current_date + timedelta(days=30))
323
+ new_description = st.text_area("وصف الطلب", height=100)
324
+
325
+ if st.button("إضافة أمر الشراء"):
326
+ st.success(f"تم إضافة أمر الشراء بنجاح للمورد {new_vendor} بقيمة {new_value:,} ريال")
327
+
328
+ def show_internal_tenders():
329
+ """
330
+ عرض المناقصات الداخلية
331
+ """
332
+ st.markdown("## المناقصات الداخلية")
333
+
334
+ # إنشاء بيانات توضيحية للمناقصات الداخلية
335
+ current_date = datetime.now().date()
336
+
337
+ tenders_data = {
338
+ "رقم المناقصة": [f"IT-{2025}-{i:04d}" for i in range(1001, 1009)],
339
+ "العنوان": [
340
+ "توريد معدات بناء ثقيلة",
341
+ "شراء مواد إنشائية",
342
+ "خدمات نقل وشحن",
343
+ "توريد أنظمة تكييف",
344
+ "خدمات تركيب كهربائية",
345
+ "توريد محولات كهربائية",
346
+ "خدمات أمن وسلامة",
347
+ "توريد أنظمة مراقبة"
348
+ ],
349
+ "المشروع": [
350
+ "مشروع توسعة شبكة الطرق", "بناء المدارس", "تطوير البنية التحتية",
351
+ "تحديث شبكة المياه", "بناء المستشفى التخصصي", "إنشاء مركز البيانات",
352
+ "توسعة المطار", "تطوير الحدائق العامة"
353
+ ],
354
+ "تاريخ النشر": [current_date - timedelta(days=np.random.randint(5, 30)) for _ in range(8)],
355
+ "الموعد النهائي": [current_date + timedelta(days=np.random.randint(10, 45)) for _ in range(8)],
356
+ "القيمة التقديرية (ريال)": [
357
+ np.random.randint(200000, 10000000) for _ in range(8)
358
+ ],
359
+ "عدد العروض المستلمة": [np.random.randint(0, 10) for _ in range(8)],
360
+ "الحالة": np.random.choice(
361
+ ["مفتوحة", "مغلقة", "قيد التقييم", "تم الترسية", "ملغاة"],
362
+ size=8,
363
+ p=[0.4, 0.1, 0.2, 0.2, 0.1]
364
+ )
365
+ }
366
+
367
+ # إنشاء DataFrame
368
+ tenders_df = pd.DataFrame(tenders_data)
369
+
370
+ # عرض فلاتر البحث
371
+ col1, col2 = st.columns(2)
372
+
373
+ with col1:
374
+ status_filter = st.selectbox(
375
+ "حالة المناقصة",
376
+ ["الكل"] + sorted(tenders_df["الحالة"].unique().tolist())
377
+ )
378
+
379
+ with col2:
380
+ project_filter = st.selectbox(
381
+ "المشروع",
382
+ ["الكل"] + sorted(tenders_df["المشروع"].unique().tolist())
383
+ )
384
+
385
+ # تطبيق الفلاتر
386
+ filtered_tenders = tenders_df.copy()
387
+
388
+ if status_filter != "الكل":
389
+ filtered_tenders = filtered_tenders[filtered_tenders["الحالة"] == status_filter]
390
+
391
+ if project_filter != "الكل":
392
+ filtered_tenders = filtered_tenders[filtered_tenders["المشروع"] == project_filter]
393
+
394
+ # عرض المناقصات المصفاة
395
+ st.dataframe(filtered_tenders, use_container_width=True)
396
+
397
+ # تحليلات المناقصات
398
+ st.markdown("### تحليلات المناقصات الداخلية")
399
+
400
+ col1, col2 = st.columns(2)
401
+
402
+ with col1:
403
+ # توزيع المناقصات حسب الحالة
404
+ status_counts = tenders_df.groupby("الحالة").size().reset_index(name="العدد")
405
+
406
+ fig1 = px.pie(
407
+ status_counts,
408
+ values="العدد",
409
+ names="الحالة",
410
+ title="توزيع المناقصات حسب الحالة",
411
+ color_discrete_sequence=px.colors.qualitative.Bold
412
+ )
413
+
414
+ fig1.update_traces(textposition="inside", textinfo="percent+label")
415
+
416
+ st.plotly_chart(fig1, use_container_width=True)
417
+
418
+ with col2:
419
+ # متوسط عدد العروض حسب نوع المناقصة
420
+ tenders_df["نوع المناقصة"] = tenders_df["العنوان"].apply(
421
+ lambda x: "توريد" if "توريد" in x else "خدمات" if "خدمات" in x else "أخرى"
422
+ )
423
+
424
+ avg_offers = tenders_df.groupby("نوع المناقصة")["عدد العروض المستلمة"].mean().reset_index()
425
+ avg_offers["عدد العروض المستلمة"] = avg_offers["عدد العروض المستلمة"].round(1)
426
+
427
+ fig2 = px.bar(
428
+ avg_offers,
429
+ x="نوع المناقصة",
430
+ y="عدد العروض المستلمة",
431
+ title="متوسط عدد العروض حسب نوع المناقصة",
432
+ color="نوع المناقصة",
433
+ text="عدد العروض المستلمة"
434
+ )
435
+
436
+ fig2.update_traces(texttemplate="%{text}", textposition="outside")
437
+
438
+ st.plotly_chart(fig2, use_container_width=True)
439
+
440
+ # المناقصات القريبة من الإغلاق
441
+ st.markdown("### المناقصات القريبة من الموعد النهائي")
442
+
443
+ closing_soon = tenders_df[
444
+ (tenders_df["الموعد النهائي"] > current_date) &
445
+ (tenders_df["الموعد النهائي"] <= current_date + timedelta(days=7)) &
446
+ (tenders_df["الحالة"] == "مفتوحة")
447
+ ].sort_values("الموعد النهائي")
448
+
449
+ if not closing_soon.empty:
450
+ for _, tender in closing_soon.iterrows():
451
+ days_left = (tender["الموعد النهائي"] - current_date).days
452
+
453
+ st.markdown(f"""
454
+ **{tender['رقم المناقصة']} - {tender['العنوان']}**
455
+ **المشروع:** {tender['المشروع']}
456
+ **الموعد النهائي:** {tender['الموعد النهائي'].strftime('%Y/%m/%d')} ({days_left} أيام متبقية)
457
+ **القيمة التقديرية:** {tender['القيمة التقديرية (ريال)']:,} ريال
458
+ **العروض المستلمة حتى الآن:** {tender['عدد العروض المستلمة']}
459
+ """)
460
+ st.markdown("---")
461
+ else:
462
+ st.info("لا توجد مناقصات على وشك الإغلاق خلال الأسبوع القادم")
463
+
464
+ def show_vendor_evaluation():
465
+ """
466
+ عرض تقييم الموردين
467
+ """
468
+ st.markdown("## تقييم الموردين")
469
+
470
+ # إنشاء بيانات توضيحية لتقييم الموردين
471
+ vendors_eval_data = {
472
+ "المورد": [
473
+ "شركة الصناعات السعودية", "مؤسسة الخليج للمقاولات", "شركة الرياض للإنشاءات",
474
+ "الشركة العربية للمعدات", "مصنع المنتجات الإسمنتية", "شركة تقنيات البناء",
475
+ "مؤسسة المدار للتوريدات", "شركة البنية التحتية المتكاملة", "مصنع الصلب السعودي",
476
+ "شركة الأنابيب الوطنية"
477
+ ],
478
+ "الفئة": [
479
+ "مواد بناء", "مقاولات", "خدمات هندسية", "معدات", "مواد خام",
480
+ "تقنيات", "مواد متنوعة", "بنية تحتية", "صناعات معدنية", "أنابيب"
481
+ ],
482
+ "جودة المنتجات (5)": [4.5, 3.8, 4.2, 3.2, 4.7, 3.5, 3.9, 4.3, 4.6, 4.1],
483
+ "الالتزام بالمواعيد (5)": [4.2, 3.5, 4.0, 2.8, 4.5, 3.7, 3.6, 4.4, 4.3, 3.9],
484
+ "التنافسية السعرية (5)": [3.8, 4.2, 3.5, 4.6, 3.7, 4.1, 4.4, 3.8, 3.6, 4.0],
485
+ "الاستجابة والتواصل (5)": [4.3, 3.9, 4.5, 3.5, 4.2, 3.6, 3.8, 4.1, 4.4, 4.0],
486
+ "نسبة المحتوى المحلي (%)": [85, 92, 78, 65, 100, 70, 88, 75, 95, 82],
487
+ "عدد المشاريع المنفذة": [12, 8, 10, 5, 7, 6, 4, 9, 11, 8]
488
+ }
489
+
490
+ # إنشاء DataFrame
491
+ vendors_eval_df = pd.DataFrame(vendors_eval_data)
492
+
493
+ # حساب التقييم العام
494
+ eval_weights = {
495
+ "جودة المنتجات (5)": 0.35,
496
+ "الالتزام بالمواعيد (5)": 0.25,
497
+ "التنافسية السعرية (5)": 0.2,
498
+ "الاستجابة والتواصل (5)": 0.2
499
+ }
500
+
501
+ # حساب التقييم المرجح
502
+ for col, weight in eval_weights.items():
503
+ vendors_eval_df[f"{col} (مرجح)"] = vendors_eval_df[col] * weight
504
+
505
+ vendors_eval_df["التقييم العام"] = vendors_eval_df[[f"{col} (مرجح)" for col in eval_weights.keys()]].sum(axis=1)
506
+
507
+ # تصنيف الموردين
508
+ conditions = [
509
+ (vendors_eval_df["التقييم العام"] >= 4.5),
510
+ (vendors_eval_df["التقييم العام"] >= 4.0),
511
+ (vendors_eval_df["التقييم العام"] >= 3.5),
512
+ (vendors_eval_df["التقييم العام"] >= 3.0),
513
+ (vendors_eval_df["التقييم العام"] < 3.0)
514
+ ]
515
+ values = ["ممتاز", "جيد جداً", "جيد", "مقبول", "ضعيف"]
516
+ vendors_eval_df["التصنيف"] = np.select(conditions, values)
517
+
518
+ # عرض مقارنة الموردين
519
+ st.markdown("### مقارنة تقييمات الموردين")
520
+
521
+ selected_vendors = st.multiselect(
522
+ "اختر الموردين للمقارنة",
523
+ vendors_eval_df["المورد"].tolist(),
524
+ default=vendors_eval_df["المورد"].tolist()[:5]
525
+ )
526
+
527
+ if selected_vendors:
528
+ # تصفية البيانات
529
+ selected_df = vendors_eval_df[vendors_eval_df["المورد"].isin(selected_vendors)]
530
+
531
+ # تصفية البيانات
532
+ if selected_vendors:
533
+ selected_df = vendors_eval_df[vendors_eval_df["المورد"].isin(selected_vendors)]
534
+ st.dataframe(selected_df)
535
+ else:
536
+ st.write("يرجى اختيار مورد لعرض البيانات.")