EGYADMIN commited on
Commit
d653c9b
·
verified ·
1 Parent(s): f5db5d9

Update modules/pricing/pricing_app.py

Browse files
Files changed (1) hide show
  1. modules/pricing/pricing_app.py +917 -299
modules/pricing/pricing_app.py CHANGED
@@ -102,337 +102,955 @@ class PricingApp:
102
  """تشغيل التطبيق"""
103
  st.title("وحدة التسعير المتكاملة")
104
 
105
- # زر إنشاء تسعير جديد
106
- if st.button("➕ إنشاء تسعير جديد", type="primary"):
107
- self._create_new_pricing()
108
 
109
- # عرض قائمة المشاريع
110
- self._render_projects_list()
111
-
112
- # إذا تم اختيار مشروع، عرض تفاصيله
113
- if st.session_state.current_project_id is not None:
114
- self._render_project_details()
115
-
116
- # عرض التبويبات
117
- self._render_tabs()
118
-
119
- def _load_sample_projects(self):
120
- """تحميل بيانات المشاريع النموذجية"""
121
- return [
122
- {
123
- 'id': 1,
124
- 'name': 'مشروع تطوير الطرق الداخلية',
125
- 'client': 'وزارة النقل',
126
- 'estimated_value': 5000000.0,
127
- 'deadline': '2024-06-30',
128
- 'pricing_type': 'قياسي',
129
- 'boq': [
130
- {
131
- 'id': 'A-001',
132
- 'code': 'A-001',
133
- 'description': 'أعمال الحفر والردم',
134
- 'unit': 'م3',
135
- 'quantity': 1500.0,
136
- 'unit_price': 45.0,
137
- 'total_price': 67500.0
138
- },
139
- {
140
- 'id': 'A-002',
141
- 'code': 'A-002',
142
- 'description': 'توريد وتركيب بردورات خرسانية',
143
- 'unit': 'م.ط',
144
- 'quantity': 2500.0,
145
- 'unit_price': 85.0,
146
- 'total_price': 212500.0
147
- },
148
- {
149
- 'id': 'A-003',
150
- 'code': 'A-003',
151
- 'description': 'أعمال الأسفلت',
152
- 'unit': 'م2',
153
- 'quantity': 10000.0,
154
- 'unit_price': 120.0,
155
- 'total_price': 1200000.0
156
- }
157
- ]
158
- },
159
- {
160
- 'id': 2,
161
- 'name': 'مشروع إنشاء مبنى إداري',
162
- 'client': 'شركة التطوير العقاري',
163
- 'estimated_value': 12000000.0,
164
- 'deadline': '2024-08-15',
165
- 'pricing_type': 'قياسي',
166
- 'boq': [
167
- {
168
- 'id': 'B-001',
169
- 'code': 'B-001',
170
- 'description': 'أعمال الخرسانة المسلحة للأساسات',
171
- 'unit': 'م3',
172
- 'quantity': 750.0,
173
- 'unit_price': 1200.0,
174
- 'total_price': 900000.0
175
- },
176
- {
177
- 'id': 'B-002',
178
- 'code': 'B-002',
179
- 'description': 'أعمال البناء بالطوب',
180
- 'unit': 'م2',
181
- 'quantity': 3500.0,
182
- 'unit_price': 180.0,
183
- 'total_price': 630000.0
184
- },
185
- {
186
- 'id': 'B-003',
187
- 'code': 'B-003',
188
- 'description': 'أعمال التشطيبات',
189
- 'unit': 'م2',
190
- 'quantity': 5000.0,
191
- 'unit_price': 850.0,
192
- 'total_price': 4250000.0
193
- }
194
- ]
195
- }
196
- ]
197
 
198
- def _create_new_pricing(self):
199
- """إنشاء تسعير جديد"""
200
- # إنشاء مشروع جديد بقيم افتراضية
201
- new_project = {
202
- 'id': len(st.session_state.projects) + 1,
203
- 'name': f'مشروع جديد {len(st.session_state.projects) + 1}',
204
- 'client': 'عميل جديد',
205
- 'estimated_value': 0.0,
206
- 'deadline': datetime.now().strftime('%Y-%m-%d'),
207
- 'pricing_type': 'قياسي',
208
- 'boq': []
209
- }
210
 
211
- # إضافة المشروع الجديد إلى قائمة المشاريع
212
- st.session_state.projects.append(new_project)
 
 
213
 
214
- # تعيين المشروع الجديد كمشروع حالي
215
- st.session_state.current_project_id = new_project['id']
 
 
 
 
 
216
 
217
- # إعادة تحميل الصفحة
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  st.rerun()
219
 
220
- def _render_projects_list(self):
221
- """عرض قائمة المشاريع"""
222
- st.header("قائمة المشاريع")
223
-
224
- # إنشاء DataFrame من قائمة المشاريع
225
- projects_data = []
226
- for i, project in enumerate(st.session_state.projects):
227
- projects_data.append({
228
- 'الرقم': i,
229
- 'رقم المشروع': project['id'],
230
- 'اسم المشروع': project['name'],
231
- 'العميل': project['client'],
232
- 'القيمة التقديرية': f"{project['estimated_value']:,.2f} ريال",
233
- 'الموعد النهائي': project['deadline'],
234
- 'نوع التسعير': project['pricing_type']
235
- })
236
-
237
- df = pd.DataFrame(projects_data)
238
-
239
- # عرض الجدول
240
- st.dataframe(df, use_container_width=True)
241
 
242
  # اختيار المشروع
243
- col1, col2 = st.columns([3, 1])
244
- with col1:
245
- project_options = [p['name'] for p in st.session_state.projects]
246
- selected_project = st.selectbox("اختر المشروع", project_options, index=0 if project_options else None, key="project_selector")
247
-
248
- if selected_project:
249
- selected_project_id = next((p['id'] for p in st.session_state.projects if p['name'] == selected_project), None)
250
- st.session_state.current_project_id = selected_project_id
 
251
 
 
 
 
 
252
  with col2:
253
- if st.button("تعديل المشروع"):
254
- # هنا يمكن إضافة منطق تعديل المشروع
255
- pass
256
-
257
- def _render_project_details(self):
258
- """عرض تفاصيل المشروع الحالي"""
259
- # الحصول على المشروع الحالي
260
- current_project = next((p for p in st.session_state.projects if p['id'] == st.session_state.current_project_id), None)
261
-
262
- if current_project:
263
- st.header(f"تسعير: {current_project['name']}")
264
-
265
- # عرض تفاصيل المشروع
266
- col1, col2, col3, col4 = st.columns(4)
267
- with col1:
268
- st.info(f"العميل: {current_project['client']}")
269
- with col2:
270
- st.info(f"القيمة التقديرية: {current_project['estimated_value']:,.2f} ريال")
271
- with col3:
272
- st.info(f"الموعد النهائي: {current_project['deadline']}")
273
- with col4:
274
- st.info(f"نوع التسعير: {current_project['pricing_type']}")
275
-
276
- def _render_tabs(self):
277
- """عرض التبويبات"""
278
- # إنشاء التبويبات
279
- tabs = ["جدول الكميات", "تحليل سعر البند", "تحليل التكلفة", "تحليل الربحية", "استراتيجيات التسعير"]
280
-
281
- # عرض أزرار التبويبات
282
- cols = st.columns(len(tabs))
283
- for i, tab in enumerate(tabs):
284
- with cols[i]:
285
- if st.button(tab, key=f"tab_{i}"):
286
- st.session_state.current_tab = tab.lower()
287
  st.rerun()
288
 
289
- # عرض محتوى التبويب الحالي
290
- if st.session_state.current_tab == "جدول الكميات":
291
- self._render_boq()
292
- elif st.session_state.current_tab == "تحليل سعر البند":
293
- self._render_item_price_analysis()
294
- elif st.session_state.current_tab == "تحليل التكلفة":
295
- self._render_cost_analysis()
296
- elif st.session_state.current_tab == "تحليل الربحية":
297
- self._render_profit_analysis()
298
- elif st.session_state.current_tab == "استراتيجيات التسعير":
299
- self._render_pricing_strategies()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
 
301
- def _render_boq(self):
302
- """عرض جدول الكميات"""
303
- st.header("جدول الكميات")
 
 
304
 
305
- # الحصول على المشروع الحالي
306
- current_project = next((p for p in st.session_state.projects if p['id'] == st.session_state.current_project_id), None)
307
 
308
- if not current_project:
309
- st.warning("الرجاء اختيار مشروع أولاً.")
310
- return
311
 
312
- # أزرار إضافة بند جديد وسحب من الموارد
313
- col1, col2 = st.columns(2)
314
  with col1:
315
- if st.button(" إضافة بند جديد", key="add_boq_item"):
316
- # إنشاء بند جديد بقيم افتراضية
317
- new_item = {
318
- 'id': f"ITEM-{len(current_project['boq']) + 1}",
319
- 'code': f"ITEM-{len(current_project['boq']) + 1}",
320
- 'description': 'بند جديد',
321
- 'unit': 'وحدة',
322
- 'quantity': 0.0,
323
- 'unit_price': 0.0,
324
- 'total_price': 0.0
325
- }
 
 
 
 
 
 
 
 
 
326
 
327
- # إضافة البند الجديد إلى جدول الكميات
328
- current_project['boq'].append(new_item)
329
  st.rerun()
330
 
331
- with col2:
332
- if st.button("📋 سحب من الموارد", key="import_from_resources"):
333
- # هنا يمكن إضافة منطق سحب البنود من الموارد
334
- pass
335
-
336
- # إنشاء DataFrame من جدول الكميات
337
- if current_project['boq']:
338
- boq_data = []
339
- for i, item in enumerate(current_project['boq']):
340
- boq_data.append({
341
- 'الرقم': i,
342
- 'رقم البند': item['code'],
343
- 'الوصف': item['description'],
344
- 'الوحدة': item['unit'],
345
- 'الكمية': item['quantity'],
346
- 'سعر الوحدة': item['unit_price'],
347
- 'السعر الإجمالي': item['total_price'],
348
- 'الإجراءات': f'<button class="action-button edit-button" onclick="alert(\'تعديل البند {item["code"]}\')">✏️</button> <button class="action-button delete-button" onclick="alert(\'حذف البند {item["code"]}\')">🗑️</button>'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
349
  })
350
 
351
- df = pd.DataFrame(boq_data)
352
 
353
  # إضافة صف المجموع
354
- total_price = sum(item['total_price'] for item in current_project['boq'])
355
- total_row = pd.DataFrame([{
356
- 'الرقم': '',
357
- 'رقم البند': '',
358
- 'الوصف': 'المجموع',
359
- 'الوحدة': '',
360
- 'الكمية': '',
361
- 'سعر الوحدة': '',
362
- 'السعر الإجمالي': total_price,
363
- 'الإجراءات': ''
364
- }])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
 
366
- # دمج الجدول مع صف المجموع
367
- df = pd.concat([df, total_row], ignore_index=True)
368
 
369
- # تحويل الجدول إلى جدول قابل للتعديل
370
- edited_df = st.data_editor(
371
- df,
372
- use_container_width=True,
373
- key="edit_boq_table",
 
 
 
 
 
 
 
 
 
 
374
  column_config={
375
- "الرقم": st.column_config.Column(
376
- "الرقم",
377
- width="small",
378
- ),
379
- "رقم البند": st.column_config.Column(
380
- "رقم البند",
381
- ),
382
- "الوصف": st.column_config.Column(
383
- "الوصف",
384
- ),
385
- "الوحدة": st.column_config.Column(
386
- "الوحدة",
387
- width="small",
388
- ),
389
- "الكمية": st.column_config.NumberColumn(
390
- "الكمية",
391
- min_value=0.0,
392
- format="%.2f",
393
- step=0.1,
394
- ),
395
- "سعر الوحدة": st.column_config.NumberColumn(
396
- "سعر الوحدة",
397
- min_value=0.0,
398
- format="%.2f ريال",
399
- step=0.1,
400
- ),
401
- "السعر الإجمالي": st.column_config.NumberColumn(
402
- "السعر الإجمالي",
403
- format="%.2f ريال",
404
- ),
405
- "الإجراءات": st.column_config.Column(
406
- "الإجراءات",
407
- width="small",
408
- ),
409
  },
410
  hide_index=True,
411
- disabled=["الرقم", "السعر الإجمالي", "الإجراءات"],
 
 
412
  )
413
 
414
- # تحديث البيانات في المشروع بناءً على التعديلات
415
- if edited_df is not None and not edited_df.equals(df):
416
- # تحديث بنود جدول الكميات
417
- for i in range(len(edited_df) - 1): # استثناء صف المجموع
418
- row = edited_df.iloc[i]
419
- item_code = row['رقم البند']
420
-
421
- # البحث عن البند في جدول الكميات
422
- for item in current_project['boq']:
423
- if item['code'] == item_code:
424
- # تحديث البند
425
- item['description'] = row['الوصف']
426
- item['unit'] = row['الوحدة']
427
- item['quantity'] = row['الكمية']
428
- item['unit_price'] = row['سعر الوحدة']
429
- item['total_price'] = row['الكمية'] * row['سعر الوحدة']
430
- break
431
 
432
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
433
  else:
434
- st.info("لا توجد بنود في جدول الكميات. قم بإضافة بنود جديدة.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
435
 
436
- def _render_item_price_analysis(self):
437
-
438
- (Content truncated due to size limit. Use line ranges to read in chunks)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  """تشغيل التطبيق"""
103
  st.title("وحدة التسعير المتكاملة")
104
 
105
+ # عرض الشريط العلوي
106
+ self._render_top_bar()
 
107
 
108
+ # عرض المحتوى حسب التبويب المحدد
109
+ if st.session_state.current_tab == "boq":
110
+ self._render_bill_of_quantities()
111
+ elif st.session_state.current_tab == "item_analysis":
112
+ self._render_item_price_analysis()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
+ def _render_top_bar(self):
115
+ """عرض الشريط العلوي"""
116
+ cols = st.columns([1, 1, 1, 1, 1])
 
 
 
 
 
 
 
 
 
117
 
118
+ with cols[0]:
119
+ if st.button("جدول الكميات", use_container_width=True):
120
+ st.session_state.current_tab = "boq"
121
+ st.rerun()
122
 
123
+ with cols[1]:
124
+ if st.button("تحليل الأسعار", use_container_width=True):
125
+ if st.session_state.current_project_id is not None:
126
+ st.session_state.current_tab = "item_analysis"
127
+ st.rerun()
128
+ else:
129
+ st.warning("الرجاء اختيار مشروع أولاً")
130
 
131
+ with cols[4]:
132
+ if st.button("إنشاء مشروع جديد", use_container_width=True):
133
+ self._create_new_project()
134
+
135
+ def _create_new_project(self):
136
+ """إنشاء مشروع جديد"""
137
+ project_id = f"proj_{len(st.session_state.projects) + 1}"
138
+ new_project = {
139
+ "id": project_id,
140
+ "name": f"مشروع رقم {len(st.session_state.projects) + 1}",
141
+ "client": "عميل قياسي",
142
+ "date": datetime.now().strftime("%Y-%m-%d"),
143
+ "budget": 1000000.00,
144
+ "items": []
145
+ }
146
+ st.session_state.projects[project_id] = new_project
147
+ st.session_state.current_project_id = project_id
148
+ st.session_state.current_tab = "boq"
149
  st.rerun()
150
 
151
+ def _render_bill_of_quantities(self):
152
+ """عرض جدول الكميات"""
153
+ st.header("جدول الكميات")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
  # اختيار المشروع
156
+ project_options = {proj["name"]: proj_id for proj_id, proj in st.session_state.projects.items()}
157
+ selected_project_name = st.selectbox(
158
+ "اختر المشروع",
159
+ options=list(project_options.keys()),
160
+ index=0 if st.session_state.current_project_id is None else list(project_options.keys()).index(st.session_state.projects[st.session_state.current_project_id]["name"])
161
+ )
162
+
163
+ st.session_state.current_project_id = project_options[selected_project_name]
164
+ current_project = st.session_state.projects[st.session_state.current_project_id]
165
 
166
+ # عرض معلومات المشروع
167
+ col1, col2, col3 = st.columns(3)
168
+ with col1:
169
+ st.write(f"**العميل:** {current_project['client']}")
170
  with col2:
171
+ st.write(f"**التاريخ:** {current_project['date']}")
172
+ with col3:
173
+ st.write(f"**الميزانية:** {current_project['budget']:,.2f} ريال")
174
+
175
+ # إضافة بند جديد
176
+ with st.expander("إضافة بند جديد"):
177
+ with st.form("add_item_form"):
178
+ col1, col2 = st.columns(2)
179
+ with col1:
180
+ new_item_name = st.text_input("اسم البند")
181
+ new_item_unit = st.text_input("الوحدة")
182
+ with col2:
183
+ new_item_quantity = st.number_input("الكمية", min_value=0.0, step=0.1)
184
+ new_item_price = st.number_input("سعر الوحدة (ريال)", min_value=0.0, step=0.1)
185
+
186
+ submitted = st.form_submit_button("إضافة البند")
187
+ if submitted and new_item_name and new_item_unit:
188
+ new_item = {
189
+ "id": f"item_{len(current_project['items']) + 1}",
190
+ "name": new_item_name,
191
+ "unit": new_item_unit,
192
+ "quantity": float(new_item_quantity),
193
+ "unit_price": float(new_item_price),
194
+ "total_price": float(new_item_quantity) * float(new_item_price),
195
+ "materials": [],
196
+ "labor": [],
197
+ "equipment": [],
198
+ "subcontractors": []
199
+ }
200
+ current_project["items"].append(new_item)
201
+ st.success("تمت إضافة البند بنجاح")
 
 
 
202
  st.rerun()
203
 
204
+ # عرض جدول الكميات
205
+ if current_project["items"]:
206
+ items_df = pd.DataFrame([
207
+ {
208
+ "م": i + 1,
209
+ "اسم البند": item["name"],
210
+ "الوحدة": item["unit"],
211
+ "الكمية": item["quantity"],
212
+ "سعر الوحدة (ريال)": item["unit_price"],
213
+ "السعر الإجمالي (ريال)": item["total_price"],
214
+ "تحليل": f'<a href="#" onclick="return false;" id="analyze_{i}">تحليل</a>'
215
+ }
216
+ for i, item in enumerate(current_project["items"])
217
+ ])
218
+
219
+ # إضافة صف المجموع
220
+ total_price = sum(item["total_price"] for item in current_project["items"])
221
+ total_row = pd.DataFrame([{
222
+ "م": "",
223
+ "اسم البند": "المجموع",
224
+ "الوحدة": "",
225
+ "الكمية": "",
226
+ "سعر الوحدة (ريال)": "",
227
+ "السعر الإجمالي (ريال)": total_price,
228
+ "تحليل": ""
229
+ }])
230
+
231
+ items_df = pd.concat([items_df, total_row], ignore_index=True)
232
+
233
+ st.write(items_df.to_html(escape=False, index=False), unsafe_allow_html=True)
234
+
235
+ # معالجة النقر على رابط التحليل
236
+ for i in range(len(current_project["items"])):
237
+ if st.button(f"تحليل البند {i+1}", key=f"analyze_btn_{i}", use_container_width=True):
238
+ st.session_state.current_item_index = i
239
+ st.session_state.current_tab = "item_analysis"
240
+ st.rerun()
241
+ else:
242
+ st.info("لا توجد بنود في جدول الكميات. قم بإضافة بنود جديدة.")
243
 
244
+ def _render_item_price_analysis(self):
245
+ """عرض تحليل سعر البند"""
246
+ if st.session_state.current_project_id is None or "current_item_index" not in st.session_state:
247
+ st.warning("الرجاء اختيار مشروع وبند أولاً")
248
+ return
249
 
250
+ current_project = st.session_state.projects[st.session_state.current_project_id]
251
+ current_item = current_project["items"][st.session_state.current_item_index]
252
 
253
+ st.header(f"تحليل سعر البند: {current_item['name']}")
 
 
254
 
255
+ # معلومات البند
256
+ col1, col2, col3, col4 = st.columns(4)
257
  with col1:
258
+ st.write(f"**الوحدة:** {current_item['unit']}")
259
+ with col2:
260
+ st.write(f"**الكمية:** {current_item['quantity']}")
261
+ with col3:
262
+ st.write(f"**سعر الوحدة:** {current_item['unit_price']} ريال")
263
+ with col4:
264
+ st.write(f"**السعر الإجمالي:** {current_item['total_price']} ريال")
265
+
266
+ # زر حفظ التغييرات
267
+ if st.session_state.item_analysis_edited:
268
+ if st.button("حفظ التغييرات", type="primary", use_container_width=True):
269
+ # تحديث السعر الإجمالي للبند
270
+ materials_total = sum(material.get("total_price", 0) for material in current_item["materials"])
271
+ labor_total = sum(labor.get("total_price", 0) for labor in current_item["labor"])
272
+ equipment_total = sum(equipment.get("total_price", 0) for equipment in current_item["equipment"])
273
+ subcontractors_total = sum(sub.get("total_price", 0) for sub in current_item["subcontractors"])
274
+
275
+ direct_cost = materials_total + labor_total + equipment_total + subcontractors_total
276
+ current_item["unit_price"] = direct_cost / current_item["quantity"] if current_item["quantity"] > 0 else 0
277
+ current_item["total_price"] = current_item["unit_price"] * current_item["quantity"]
278
 
279
+ st.session_state.item_analysis_edited = False
280
+ st.success("تم حفظ التغييرات بنجاح")
281
  st.rerun()
282
 
283
+ # تحليل المواد
284
+ st.subheader("تحليل المواد")
285
+
286
+ # إضافة مادة جديدة
287
+ with st.expander("إضافة مادة جديدة"):
288
+ with st.form("add_material_form"):
289
+ col1, col2 = st.columns(2)
290
+ with col1:
291
+ new_material_name = st.text_input("اسم المادة")
292
+ new_material_unit = st.text_input("الوحدة")
293
+ with col2:
294
+ new_material_quantity = st.number_input("الكمية", min_value=0.0, step=0.1)
295
+ new_material_price = st.number_input("سعر الوحدة (ريال)", min_value=0.0, step=0.1)
296
+
297
+ submitted = st.form_submit_button("إضافة المادة")
298
+ if submitted and new_material_name and new_material_unit:
299
+ new_material = {
300
+ "id": f"material_{len(current_item['materials']) + 1}",
301
+ "name": new_material_name,
302
+ "unit": new_material_unit,
303
+ "quantity": float(new_material_quantity),
304
+ "unit_price": float(new_material_price),
305
+ "total_price": float(new_material_quantity) * float(new_material_price)
306
+ }
307
+ current_item["materials"].append(new_material)
308
+ st.session_state.item_analysis_edited = True
309
+ st.success("تمت إضافة المادة بنجاح")
310
+ st.rerun()
311
+
312
+ # عرض جدول المواد
313
+ if current_item["materials"]:
314
+ # تحويل البيانات إلى DataFrame
315
+ materials_data = []
316
+ for i, material in enumerate(current_item["materials"]):
317
+ materials_data.append({
318
+ "م": i + 1,
319
+ "اسم المادة": material["name"],
320
+ "الوحدة": material["unit"],
321
+ "الكمية": material["quantity"],
322
+ "سعر الوحدة (ريال)": material["unit_price"],
323
+ "السعر الإجمالي (ريال)": material["total_price"],
324
+ "الإجراءات": f'<button class="action-button edit-button" id="edit_material_{i}">تعديل</button> <button class="action-button delete-button" id="delete_material_{i}">حذف</button>'
325
  })
326
 
327
+ materials_df = pd.DataFrame(materials_data)
328
 
329
  # إضافة صف المجموع
330
+ materials_total = sum(material["total_price"] for material in current_item["materials"])
331
+ materials_df = materials_df.append({
332
+ "م": "",
333
+ "اسم المادة": "المجموع",
334
+ "الوحدة": "",
335
+ "الكمية": "",
336
+ "سعر الوحدة (ريال)": "",
337
+ "السعر الإجمالي (ريال)": materials_total,
338
+ "الإجراءات": ""
339
+ }, ignore_index=True)
340
+
341
+ # عرض الجدول القابل للتعديل
342
+ edited_materials_df = st.data_editor(
343
+ materials_df,
344
+ column_config={
345
+ "م": st.column_config.NumberColumn("م", width="small"),
346
+ "اسم المادة": st.column_config.TextColumn("اسم المادة"),
347
+ "الوحدة": st.column_config.TextColumn("الوحدة", width="small"),
348
+ "الكمية": st.column_config.NumberColumn("الكمية", format="%.2f", width="small"),
349
+ "سعر الوحدة (ريال)": st.column_config.NumberColumn("سعر الوحدة (ريال)", format="%.2f"),
350
+ "السعر الإجمالي (ريال)": st.column_config.NumberColumn("السعر الإجمالي (ريال)", format="%.2f"),
351
+ "الإجراءات": st.column_config.TextColumn("الإجراءات", width="medium"),
352
+ },
353
+ hide_index=True,
354
+ key="materials_table",
355
+ on_change=self._update_total_price,
356
+ disabled=["م", "اسم المادة", "الوحدة", "السعر الإجمالي (ريال)", "الإجراءات"]
357
+ )
358
+
359
+ # تحديث البيانات بعد التعديل
360
+ for i, material in enumerate(current_item["materials"]):
361
+ if i < len(edited_materials_df) - 1: # تجاهل صف المجموع
362
+ material["quantity"] = edited_materials_df.iloc[i]["الكمية"]
363
+ material["unit_price"] = edited_materials_df.iloc[i]["سعر الوحدة (ريال)"]
364
+ material["total_price"] = material["quantity"] * material["unit_price"]
365
+
366
+ # معالجة أزرار التعديل والحذف
367
+ for i in range(len(current_item["materials"])):
368
+ col1, col2 = st.columns([1, 1])
369
+ with col1:
370
+ if st.button(f"تعديل المادة {i+1}", key=f"edit_material_btn_{i}"):
371
+ st.session_state[f"edit_material_{i}"] = True
372
+
373
+ with col2:
374
+ if st.button(f"حذف المادة {i+1}", key=f"delete_material_btn_{i}"):
375
+ st.session_state[f"delete_material_{i}"] = True
376
+
377
+ # نموذج التعديل
378
+ if st.session_state.get(f"edit_material_{i}", False):
379
+ with st.form(f"edit_material_form_{i}"):
380
+ material = current_item["materials"][i]
381
+ col1, col2 = st.columns(2)
382
+ with col1:
383
+ material_name = st.text_input("اسم المادة", value=material["name"])
384
+ material_unit = st.text_input("الوحدة", value=material["unit"])
385
+ with col2:
386
+ material_quantity = st.number_input("الكمية", min_value=0.0, step=0.1, value=material["quantity"])
387
+ material_price = st.number_input("سعر الوحدة (ريال)", min_value=0.0, step=0.1, value=material["unit_price"])
388
+
389
+ col1, col2 = st.columns(2)
390
+ with col1:
391
+ if st.form_submit_button("حفظ التعديلات"):
392
+ material["name"] = material_name
393
+ material["unit"] = material_unit
394
+ material["quantity"] = float(material_quantity)
395
+ material["unit_price"] = float(material_price)
396
+ material["total_price"] = material["quantity"] * material["unit_price"]
397
+ st.session_state.item_analysis_edited = True
398
+ st.session_state[f"edit_material_{i}"] = False
399
+ st.rerun()
400
+ with col2:
401
+ if st.form_submit_button("إلغاء"):
402
+ st.session_state[f"edit_material_{i}"] = False
403
+ st.rerun()
404
+
405
+ # تأكيد الحذف
406
+ if st.session_state.get(f"delete_material_{i}", False):
407
+ st.warning(f"هل أنت متأكد من حذف المادة: {current_item['materials'][i]['name']}؟")
408
+ col1, col2 = st.columns(2)
409
+ with col1:
410
+ if st.button("نعم، حذف", key=f"confirm_delete_material_{i}"):
411
+ current_item["materials"].pop(i)
412
+ st.session_state.item_analysis_edited = True
413
+ st.session_state[f"delete_material_{i}"] = False
414
+ st.rerun()
415
+ with col2:
416
+ if st.button("إلغاء", key=f"cancel_delete_material_{i}"):
417
+ st.session_state[f"delete_material_{i}"] = False
418
+ st.rerun()
419
+
420
+ # عرض المجموع الكلي للمواد
421
+ st.markdown(f"<div class='highlight-total'>إجمالي تكلفة المواد: <span class='total-value'>{materials_total:,.2f}</span> ريال</div>", unsafe_allow_html=True)
422
+ else:
423
+ st.info("لا توجد مواد مضافة لهذا البند")
424
+
425
+ # تحليل العمالة
426
+ st.subheader("تحليل العمالة")
427
+
428
+ # إضافة عمالة جديدة
429
+ with st.expander("إضافة عمالة جديدة"):
430
+ with st.form("add_labor_form"):
431
+ col1, col2 = st.columns(2)
432
+ with col1:
433
+ new_labor_name = st.text_input("نوع العمالة")
434
+ new_labor_unit = st.text_input("الوحدة", value="يوم")
435
+ with col2:
436
+ new_labor_quantity = st.number_input("عدد الأيام", min_value=0.0, step=0.5)
437
+ new_labor_price = st.number_input("الأجر اليومي (ريال)", min_value=0.0, step=10.0)
438
+
439
+ submitted = st.form_submit_button("إضافة العمالة")
440
+ if submitted and new_labor_name:
441
+ new_labor = {
442
+ "id": f"labor_{len(current_item['labor']) + 1}",
443
+ "name": new_labor_name,
444
+ "unit": new_labor_unit,
445
+ "quantity": float(new_labor_quantity),
446
+ "unit_price": float(new_labor_price),
447
+ "total_price": float(new_labor_quantity) * float(new_labor_price)
448
+ }
449
+ current_item["labor"].append(new_labor)
450
+ st.session_state.item_analysis_edited = True
451
+ st.success("تمت إضافة العمالة بنجاح")
452
+ st.rerun()
453
+
454
+ # عرض جدول العمالة
455
+ if current_item["labor"]:
456
+ # تحويل البيانات إلى DataFrame
457
+ labor_data = []
458
+ for i, labor in enumerate(current_item["labor"]):
459
+ labor_data.append({
460
+ "م": i + 1,
461
+ "نوع العمالة": labor["name"],
462
+ "الوحدة": labor["unit"],
463
+ "عدد الأيام": labor["quantity"],
464
+ "الأجر اليومي (ريال)": labor["unit_price"],
465
+ "الإجمالي (ريال)": labor["total_price"],
466
+ "الإجراءات": f'<button class="action-button edit-button" id="edit_labor_{i}">تعديل</button> <button class="action-button delete-button" id="delete_labor_{i}">حذف</button>'
467
+ })
468
 
469
+ labor_df = pd.DataFrame(labor_data)
 
470
 
471
+ # إضافة صف المجموع
472
+ labor_total = sum(labor["total_price"] for labor in current_item["labor"])
473
+ labor_df = labor_df.append({
474
+ "م": "",
475
+ "نوع العمالة": "المجموع",
476
+ "الوحدة": "",
477
+ "عدد الأيام": "",
478
+ "الأجر اليومي (ريال)": "",
479
+ "الإجمالي (ريال)": labor_total,
480
+ "الإجراءات": ""
481
+ }, ignore_index=True)
482
+
483
+ # عرض الجدول القابل للتعديل
484
+ edited_labor_df = st.data_editor(
485
+ labor_df,
486
  column_config={
487
+ "م": st.column_config.NumberColumn("م", width="small"),
488
+ "نوع العمالة": st.column_config.TextColumn("نوع العمالة"),
489
+ "الوحدة": st.column_config.TextColumn("الوحدة", width="small"),
490
+ "عدد الأيام": st.column_config.NumberColumn("عدد الأيام", format="%.1f", width="small"),
491
+ "الأجر اليومي (ريال)": st.column_config.NumberColumn("الأجر اليومي (ريال)", format="%.2f"),
492
+ "الإجمالي (ريال)": st.column_config.NumberColumn("الإجمالي (ريال)", format="%.2f"),
493
+ "الإجراءات": st.column_config.TextColumn("الإجراءات", width="medium"),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
494
  },
495
  hide_index=True,
496
+ key="labor_table",
497
+ on_change=self._update_total_price,
498
+ disabled=["م", "نوع العمالة", "الوحدة", "الإجمالي (ريال)", "الإجراءات"]
499
  )
500
 
501
+ # تحديث البيانات بعد التعديل
502
+ for i, labor in enumerate(current_item["labor"]):
503
+ if i < len(edited_labor_df) - 1: # تجاهل صف المجموع
504
+ labor["quantity"] = edited_labor_df.iloc[i]["عدد الأيام"]
505
+ labor["unit_price"] = edited_labor_df.iloc[i]["الأجر اليومي (ريال)"]
506
+ labor["total_price"] = labor["quantity"] * labor["unit_price"]
507
+
508
+ # معالجة أزرار التعديل والحذف
509
+ for i in range(len(current_item["labor"])):
510
+ col1, col2 = st.columns([1, 1])
511
+ with col1:
512
+ if st.button(f"تعديل العمالة {i+1}", key=f"edit_labor_btn_{i}"):
513
+ st.session_state[f"edit_labor_{i}"] = True
 
 
 
 
514
 
515
+ with col2:
516
+ if st.button(f"حذف العمالة {i+1}", key=f"delete_labor_btn_{i}"):
517
+ st.session_state[f"delete_labor_{i}"] = True
518
+
519
+ # نموذج التعديل
520
+ if st.session_state.get(f"edit_labor_{i}", False):
521
+ with st.form(f"edit_labor_form_{i}"):
522
+ labor = current_item["labor"][i]
523
+ col1, col2 = st.columns(2)
524
+ with col1:
525
+ labor_name = st.text_input("نوع العمالة", value=labor["name"])
526
+ labor_unit = st.text_input("الوحدة", value=labor["unit"])
527
+ with col2:
528
+ labor_quantity = st.number_input("عدد الأيام", min_value=0.0, step=0.5, value=labor["quantity"])
529
+ labor_price = st.number_input("الأجر اليومي (ريال)", min_value=0.0, step=10.0, value=labor["unit_price"])
530
+
531
+ col1, col2 = st.columns(2)
532
+ with col1:
533
+ if st.form_submit_button("حفظ التعديلات"):
534
+ labor["name"] = labor_name
535
+ labor["unit"] = labor_unit
536
+ labor["quantity"] = float(labor_quantity)
537
+ labor["unit_price"] = float(labor_price)
538
+ labor["total_price"] = labor["quantity"] * labor["unit_price"]
539
+ st.session_state.item_analysis_edited = True
540
+ st.session_state[f"edit_labor_{i}"] = False
541
+ st.rerun()
542
+ with col2:
543
+ if st.form_submit_button("إلغاء"):
544
+ st.session_state[f"edit_labor_{i}"] = False
545
+ st.rerun()
546
+
547
+ # تأكيد الحذف
548
+ if st.session_state.get(f"delete_labor_{i}", False):
549
+ st.warning(f"هل أنت متأكد من حذف العمالة: {current_item['labor'][i]['name']}؟")
550
+ col1, col2 = st.columns(2)
551
+ with col1:
552
+ if st.button("نعم، حذف", key=f"confirm_delete_labor_{i}"):
553
+ current_item["labor"].pop(i)
554
+ st.session_state.item_analysis_edited = True
555
+ st.session_state[f"delete_labor_{i}"] = False
556
+ st.rerun()
557
+ with col2:
558
+ if st.button("إلغاء", key=f"cancel_delete_labor_{i}"):
559
+ st.session_state[f"delete_labor_{i}"] = False
560
+ st.rerun()
561
+
562
+ # عرض المجموع الكلي للعمالة
563
+ st.markdown(f"<div class='highlight-total'>إجمالي تكلفة العمالة: <span class='total-value'>{labor_total:,.2f}</span> ريال</div>", unsafe_allow_html=True)
564
  else:
565
+ st.info("لا توجد عمالة مضافة لهذا البند")
566
+
567
+ # تحليل المعدات
568
+ st.subheader("تحليل المعدات")
569
+
570
+ # إضافة معدات جديدة
571
+ with st.expander("إضافة معدات جديدة"):
572
+ with st.form("add_equipment_form"):
573
+ col1, col2 = st.columns(2)
574
+ with col1:
575
+ new_equipment_name = st.text_input("نوع المعدات")
576
+ new_equipment_unit = st.text_input("الوحدة", value="يوم")
577
+ with col2:
578
+ new_equipment_quantity = st.number_input("عدد الأيام", min_value=0.0, step=0.5, key="new_equipment_quantity")
579
+ new_equipment_price = st.number_input("التكلفة اليومية (ريال)", min_value=0.0, step=10.0, key="new_equipment_price")
580
+
581
+ submitted = st.form_submit_button("إضافة المعدات")
582
+ if submitted and new_equipment_name:
583
+ new_equipment = {
584
+ "id": f"equipment_{len(current_item['equipment']) + 1}",
585
+ "name": new_equipment_name,
586
+ "unit": new_equipment_unit,
587
+ "quantity": float(new_equipment_quantity),
588
+ "unit_price": float(new_equipment_price),
589
+ "total_price": float(new_equipment_quantity) * float(new_equipment_price)
590
+ }
591
+ current_item["equipment"].append(new_equipment)
592
+ st.session_state.item_analysis_edited = True
593
+ st.success("تمت إضافة المعدات بنجاح")
594
+ st.rerun()
595
+
596
+ # عرض جدول المعدات
597
+ if current_item["equipment"]:
598
+ # تحويل البيانات إلى DataFrame
599
+ equipment_data = []
600
+ for i, equipment in enumerate(current_item["equipment"]):
601
+ equipment_data.append({
602
+ "م": i + 1,
603
+ "نوع المعدات": equipment["name"],
604
+ "الوحدة": equipment["unit"],
605
+ "عدد الأيام": equipment["quantity"],
606
+ "التكلفة اليومية (ريال)": equipment["unit_price"],
607
+ "الإجمالي (ريال)": equipment["total_price"],
608
+ "الإجراءات": f'<button class="action-button edit-button" id="edit_equipment_{i}">تعديل</button> <button class="action-button delete-button" id="delete_equipment_{i}">حذف</button>'
609
+ })
610
+
611
+ equipment_df = pd.DataFrame(equipment_data)
612
+
613
+ # إضافة صف المجموع
614
+ equipment_total = sum(equipment["total_price"] for equipment in current_item["equipment"])
615
+ equipment_df = equipment_df.append({
616
+ "م": "",
617
+ "نوع المعدات": "المجموع",
618
+ "الوحدة": "",
619
+ "عدد الأيام": "",
620
+ "التكلفة اليومية (ريال)": "",
621
+ "الإجمالي (ريال)": equipment_total,
622
+ "الإجراءات": ""
623
+ }, ignore_index=True)
624
+
625
+ # عرض الجدول القابل للتعديل
626
+ edited_equipment_df = st.data_editor(
627
+ equipment_df,
628
+ column_config={
629
+ "م": st.column_config.NumberColumn("م", width="small"),
630
+ "نوع المعدات": st.column_config.TextColumn("نوع المعدات"),
631
+ "الوحدة": st.column_config.TextColumn("الوحدة", width="small"),
632
+ "عدد الأيام": st.column_config.NumberColumn("عدد الأيام", format="%.1f", width="small"),
633
+ "التكلفة اليومية (ريال)": st.column_config.NumberColumn("التكلفة اليومية (ريال)", format="%.2f"),
634
+ "الإجمالي (ريال)": st.column_config.NumberColumn("الإجمالي (ريال)", format="%.2f"),
635
+ "الإجراءات": st.column_config.TextColumn("الإجراءات", width="medium"),
636
+ },
637
+ hide_index=True,
638
+ key="equipment_table",
639
+ on_change=self._update_total_price,
640
+ disabled=["م", "نوع المعدات", "الوحدة", "الإجمالي (ريال)", "الإجراءات"]
641
+ )
642
+
643
+ # تحديث البيانات بعد التعديل
644
+ for i, equipment in enumerate(current_item["equipment"]):
645
+ if i < len(edited_equipment_df) - 1: # تجاهل صف المجموع
646
+ equipment["quantity"] = edited_equipment_df.iloc[i]["عدد الأيام"]
647
+ equipment["unit_price"] = edited_equipment_df.iloc[i]["التكلفة اليومية (ريال)"]
648
+ equipment["total_price"] = equipment["quantity"] * equipment["unit_price"]
649
+
650
+ # معالجة أزرار التعديل والحذف
651
+ for i in range(len(current_item["equipment"])):
652
+ col1, col2 = st.columns([1, 1])
653
+ with col1:
654
+ if st.button(f"تعديل المعدات {i+1}", key=f"edit_equipment_btn_{i}"):
655
+ st.session_state[f"edit_equipment_{i}"] = True
656
+
657
+ with col2:
658
+ if st.button(f"حذف المعدات {i+1}", key=f"delete_equipment_btn_{i}"):
659
+ st.session_state[f"delete_equipment_{i}"] = True
660
+
661
+ # نموذج التعديل
662
+ if st.session_state.get(f"edit_equipment_{i}", False):
663
+ with st.form(f"edit_equipment_form_{i}"):
664
+ equipment = current_item["equipment"][i]
665
+ col1, col2 = st.columns(2)
666
+ with col1:
667
+ equipment_name = st.text_input("نوع المعدات", value=equipment["name"])
668
+ equipment_unit = st.text_input("الوحدة", value=equipment["unit"])
669
+ with col2:
670
+ equipment_quantity = st.number_input("عدد الأيام", min_value=0.0, step=0.5, value=equipment["quantity"])
671
+ equipment_price = st.number_input("التكلفة اليومية (ريال)", min_value=0.0, step=10.0, value=equipment["unit_price"])
672
+
673
+ col1, col2 = st.columns(2)
674
+ with col1:
675
+ if st.form_submit_button("حفظ التعديلات"):
676
+ equipment["name"] = equipment_name
677
+ equipment["unit"] = equipment_unit
678
+ equipment["quantity"] = float(equipment_quantity)
679
+ equipment["unit_price"] = float(equipment_price)
680
+ equipment["total_price"] = equipment["quantity"] * equipment["unit_price"]
681
+ st.session_state.item_analysis_edited = True
682
+ st.session_state[f"edit_equipment_{i}"] = False
683
+ st.rerun()
684
+ with col2:
685
+ if st.form_submit_button("إلغاء"):
686
+ st.session_state[f"edit_equipment_{i}"] = False
687
+ st.rerun()
688
+
689
+ # تأكيد الحذف
690
+ if st.session_state.get(f"delete_equipment_{i}", False):
691
+ st.warning(f"هل أنت متأكد من حذف المعدات: {current_item['equipment'][i]['name']}؟")
692
+ col1, col2 = st.columns(2)
693
+ with col1:
694
+ if st.button("نعم، حذف", key=f"confirm_delete_equipment_{i}"):
695
+ current_item["equipment"].pop(i)
696
+ st.session_state.item_analysis_edited = True
697
+ st.session_state[f"delete_equipment_{i}"] = False
698
+ st.rerun()
699
+ with col2:
700
+ if st.button("إلغاء", key=f"cancel_delete_equipment_{i}"):
701
+ st.session_state[f"delete_equipment_{i}"] = False
702
+ st.rerun()
703
+
704
+ # عرض المجموع الكلي للمعدات
705
+ st.markdown(f"<div class='highlight-total'>إجمالي تكلفة المعدات: <span class='total-value'>{equipment_total:,.2f}</span> ريال</div>", unsafe_allow_html=True)
706
+ else:
707
+ st.info("لا توجد معدات مضافة لهذا البند")
708
+
709
+ # تحليل المقاولين من الباطن
710
+ st.subheader("تحليل المقاولين من الباطن")
711
+
712
+ # إضافة مقاول جديد
713
+ with st.expander("إضافة مقاول من الباطن"):
714
+ with st.form("add_subcontractor_form"):
715
+ col1, col2 = st.columns(2)
716
+ with col1:
717
+ new_sub_name = st.text_input("اسم المقاول")
718
+ new_sub_work = st.text_input("نوع العمل")
719
+ with col2:
720
+ new_sub_price = st.number_input("التكلفة الإجمالية (ريال)", min_value=0.0, step=100.0)
721
+
722
+ submitted = st.form_submit_button("إضافة مقاول")
723
+ if submitted and new_sub_name and new_sub_work:
724
+ new_sub = {
725
+ "id": f"sub_{len(current_item['subcontractors']) + 1}",
726
+ "name": new_sub_name,
727
+ "work": new_sub_work,
728
+ "quantity": 1,
729
+ "unit_price": float(new_sub_price),
730
+ "total_price": float(new_sub_price)
731
+ }
732
+ current_item["subcontractors"].append(new_sub)
733
+ st.session_state.item_analysis_edited = True
734
+ st.success("تمت إضافة المقاول بنجاح")
735
+ st.rerun()
736
+
737
+ # عرض جدول المقاولين
738
+ if current_item["subcontractors"]:
739
+ # تحويل البيانات إلى DataFrame
740
+ subs_data = []
741
+ for i, sub in enumerate(current_item["subcontractors"]):
742
+ subs_data.append({
743
+ "م": i + 1,
744
+ "اسم المقاول": sub["name"],
745
+ "نوع العمل": sub["work"],
746
+ "التكلفة الإجمالية (ريال)": sub["total_price"],
747
+ "الإجراءات": f'<button class="action-button edit-button" id="edit_sub_{i}">تعديل</button> <button class="action-button delete-button" id="delete_sub_{i}">حذف</button>'
748
+ })
749
+
750
+ subs_df = pd.DataFrame(subs_data)
751
+
752
+ # إضافة صف المجموع
753
+ subs_total = sum(sub["total_price"] for sub in current_item["subcontractors"])
754
+ subs_df = subs_df.append({
755
+ "م": "",
756
+ "اسم المقاول": "المجموع",
757
+ "نوع العمل": "",
758
+ "التكلفة الإجمالية (ريال)": subs_total,
759
+ "الإجراءات": ""
760
+ }, ignore_index=True)
761
+
762
+ # عرض الجدول القابل للتعديل
763
+ edited_subs_df = st.data_editor(
764
+ subs_df,
765
+ column_config={
766
+ "م": st.column_config.NumberColumn("م", width="small"),
767
+ "اسم المقاول": st.column_config.TextColumn("اسم المقاول"),
768
+ "نوع العمل": st.column_config.TextColumn("نوع العمل"),
769
+ "التكلفة الإجمالية (ريال)": st.column_config.NumberColumn("التكلفة الإجمالية (ريال)", format="%.2f"),
770
+ "الإجراءات": st.column_config.TextColumn("الإجراءات", width="medium"),
771
+ },
772
+ hide_index=True,
773
+ key="subs_table",
774
+ on_change=self._update_total_price,
775
+ disabled=["م", "اسم المقاول", "نوع العمل", "الإجراءات"]
776
+ )
777
+
778
+ # تحديث البيانات بعد التعديل
779
+ for i, sub in enumerate(current_item["subcontractors"]):
780
+ if i < len(edited_subs_df) - 1: # تجاهل صف المجموع
781
+ sub["total_price"] = edited_subs_df.iloc[i]["التكلفة الإجمالية (ريال)"]
782
+ sub["unit_price"] = sub["total_price"] # للمقاولين، سعر الوحدة = السعر الإجمالي
783
+
784
+ # معالجة أزرار التعديل والحذف
785
+ for i in range(len(current_item["subcontractors"])):
786
+ col1, col2 = st.columns([1, 1])
787
+ with col1:
788
+ if st.button(f"تعديل المقاول {i+1}", key=f"edit_sub_btn_{i}"):
789
+ st.session_state[f"edit_sub_{i}"] = True
790
+
791
+ with col2:
792
+ if st.button(f"حذف المقاول {i+1}", key=f"delete_sub_btn_{i}"):
793
+ st.session_state[f"delete_sub_{i}"] = True
794
+
795
+ # نموذج التعديل
796
+ if st.session_state.get(f"edit_sub_{i}", False):
797
+ with st.form(f"edit_sub_form_{i}"):
798
+ sub = current_item["subcontractors"][i]
799
+ col1, col2 = st.columns(2)
800
+ with col1:
801
+ sub_name = st.text_input("اسم المقاول", value=sub["name"])
802
+ sub_work = st.text_input("نوع العمل", value=sub["work"])
803
+ with col2:
804
+ sub_price = st.number_input("التكلفة الإجمالية (ريال)", min_value=0.0, step=100.0, value=sub["total_price"])
805
+
806
+ col1, col2 = st.columns(2)
807
+ with col1:
808
+ if st.form_submit_button("حفظ التعديلات"):
809
+ sub["name"] = sub_name
810
+ sub["work"] = sub_work
811
+ sub["total_price"] = float(sub_price)
812
+ sub["unit_price"] = sub["total_price"]
813
+ st.session_state.item_analysis_edited = True
814
+ st.session_state[f"edit_sub_{i}"] = False
815
+ st.rerun()
816
+ with col2:
817
+ if st.form_submit_button("إلغاء"):
818
+ st.session_state[f"edit_sub_{i}"] = False
819
+ st.rerun()
820
+
821
+ # تأكيد الحذف
822
+ if st.session_state.get(f"delete_sub_{i}", False):
823
+ st.warning(f"هل أنت متأكد من حذف المقاول: {current_item['subcontractors'][i]['name']}؟")
824
+ col1, col2 = st.columns(2)
825
+ with col1:
826
+ if st.button("نعم، حذف", key=f"confirm_delete_sub_{i}"):
827
+ current_item["subcontractors"].pop(i)
828
+ st.session_state.item_analysis_edited = True
829
+ st.session_state[f"delete_sub_{i}"] = False
830
+ st.rerun()
831
+ with col2:
832
+ if st.button("إلغاء", key=f"cancel_delete_sub_{i}"):
833
+ st.session_state[f"delete_sub_{i}"] = False
834
+ st.rerun()
835
+
836
+ # عرض المجموع الكلي للمقاولين
837
+ st.markdown(f"<div class='highlight-total'>إجمالي تكلفة المقاولين من الباطن: <span class='total-value'>{subs_total:,.2f}</span> ريال</div>", unsafe_allow_html=True)
838
+ else:
839
+ st.info("لا يوجد مقاولون من الباطن مضافون لهذا البند")
840
+
841
+ # ملخص التكلفة
842
+ st.subheader("ملخص التكلفة")
843
+
844
+ # حساب التكاليف
845
+ materials_total = sum(material.get("total_price", 0) for material in current_item["materials"])
846
+ labor_total = sum(labor.get("total_price", 0) for labor in current_item["labor"])
847
+ equipment_total = sum(equipment.get("total_price", 0) for equipment in current_item["equipment"])
848
+ subcontractors_total = sum(sub.get("total_price", 0) for sub in current_item["subcontractors"])
849
+
850
+ direct_cost = materials_total + labor_total + equipment_total + subcontractors_total
851
+ overhead_profit = max(0, current_item["total_price"] - direct_cost) # تجنب القيم السالبة
852
+
853
+ # عرض ملخص التكلفة
854
+ st.markdown("<div class='total-summary'>", unsafe_allow_html=True)
855
+
856
+ col1, col2 = st.columns(2)
857
+ with col1:
858
+ st.markdown("<p class='total-label'>تكلفة المواد:</p>", unsafe_allow_html=True)
859
+ st.markdown("<p class='total-label'>تكلفة العمالة:</p>", unsafe_allow_html=True)
860
+ st.markdown("<p class='total-label'>تكلفة المعدات:</p>", unsafe_allow_html=True)
861
+ st.markdown("<p class='total-label'>تكلفة المقاولين من الباطن:</p>", unsafe_allow_html=True)
862
+ st.markdown("<p class='total-label'>إجمالي التكلفة المباشرة:</p>", unsafe_allow_html=True)
863
+ st.markdown("<p class='total-label'>المصاريف العمومية والربح:</p>", unsafe_allow_html=True)
864
+ st.markdown("<p class='total-label'>إجمالي سعر البند:</p>", unsafe_allow_html=True)
865
+
866
+ with col2:
867
+ st.markdown(f"<p>{materials_total:,.2f} ريال</p>", unsafe_allow_html=True)
868
+ st.markdown(f"<p>{labor_total:,.2f} ريال</p>", unsafe_allow_html=True)
869
+ st.markdown(f"<p>{equipment_total:,.2f} ريال</p>", unsafe_allow_html=True)
870
+ st.markdown(f"<p>{subcontractors_total:,.2f} ريال</p>", unsafe_allow_html=True)
871
+ st.markdown(f"<p>{direct_cost:,.2f} ريال</p>", unsafe_allow_html=True)
872
+ st.markdown(f"<p>{overhead_profit:,.2f} ريال</p>", unsafe_allow_html=True)
873
+ st.markdown(f"<p class='total-value'>{current_item['total_price']:,.2f} ريال</p>", unsafe_allow_html=True)
874
+
875
+ st.markdown("</div>", unsafe_allow_html=True)
876
+
877
+ # رسم بياني للتكاليف
878
+ if direct_cost > 0:
879
+ st.subheader("توزيع التكاليف")
880
+
881
+ # إعداد البيانات للرسم البياني
882
+ labels = ['المواد', 'العمالة', 'المعدات', 'المقاولين', 'الربح']
883
+ sizes = [materials_total, labor_total, equipment_total, subcontractors_total, overhead_profit]
884
+ colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#c2c2f0']
885
+
886
+ # رسم الرسم البياني
887
+ fig, ax = plt.subplots(figsize=(10, 6))
888
+ wedges, texts, autotexts = ax.pie(
889
+ sizes,
890
+ labels=[get_display(arabic_reshaper.reshape(label)) for label in labels],
891
+ autopct='%1.1f%%',
892
+ startangle=90,
893
+ colors=colors
894
+ )
895
+
896
+ # تنسيق النص
897
+ for text in texts:
898
+ text.set_fontsize(12)
899
+ for autotext in autotexts:
900
+ autotext.set_fontsize(10)
901
+ autotext.set_color('white')
902
+
903
+ ax.axis('equal')
904
+ plt.title(get_display(arabic_reshaper.reshape('توزيع تكاليف البند')), fontsize=16)
905
+
906
+ st.pyplot(fig)
907
 
908
+ def _load_sample_projects(self):
909
+ """تحميل مشاريع نموذجية"""
910
+ return {
911
+ "proj_1": {
912
+ "id": "proj_1",
913
+ "name": "مشروع إنشاء مبنى سكني",
914
+ "client": "شركة الإعمار",
915
+ "date": "2025-06-24",
916
+ "budget": 901000000.00,
917
+ "items": [
918
+ {
919
+ "id": "item_1",
920
+ "name": "أعمال الحفر",
921
+ "unit": "م3",
922
+ "quantity": 1500.0,
923
+ "unit_price": 35.0,
924
+ "total_price": 52500.0,
925
+ "materials": [
926
+ {
927
+ "id": "material_1",
928
+ "name": "رمل",
929
+ "unit": "م3",
930
+ "quantity": 50.0,
931
+ "unit_price": 120.0,
932
+ "total_price": 6000.0
933
+ }
934
+ ],
935
+ "labor": [
936
+ {
937
+ "id": "labor_1",
938
+ "name": "عامل حفر",
939
+ "unit": "يوم",
940
+ "quantity": 30.0,
941
+ "unit_price": 150.0,
942
+ "total_price": 4500.0
943
+ }
944
+ ],
945
+ "equipment": [
946
+ {
947
+ "id": "equipment_1",
948
+ "name": "حفارة",
949
+ "unit": "يوم",
950
+ "quantity": 15.0,
951
+ "unit_price": 1200.0,
952
+ "total_price": 18000.0
953
+ }
954
+ ],
955
+ "subcontractors": []
956
+ },
957
+ {
958
+ "id": "item_2",
959
+ "name": "أعمال الخرسانة",
960
+ "unit": "م3",
961
+ "quantity": 800.0,
962
+ "unit_price": 450.0,
963
+ "total_price": 360000.0,
964
+ "materials": [
965
+ {
966
+ "id": "material_1",
967
+ "name": "أسمنت",
968
+ "unit": "طن",
969
+ "quantity": 120.0,
970
+ "unit_price": 600.0,
971
+ "total_price": 72000.0
972
+ },
973
+ {
974
+ "id": "material_2",
975
+ "name": "رمل",
976
+ "unit": "م3",
977
+ "quantity": 400.0,
978
+ "unit_price": 120.0,
979
+ "total_price": 48000.0
980
+ },
981
+ {
982
+ "id": "material_3",
983
+ "name": "حصى",
984
+ "unit": "م3",
985
+ "quantity": 600.0,
986
+ "unit_price": 150.0,
987
+ "total_price": 90000.0
988
+ }
989
+ ],
990
+ "labor": [
991
+ {
992
+ "id": "labor_1",
993
+ "name": "عامل خرسانة",
994
+ "unit": "يوم",
995
+ "quantity": 200.0,
996
+ "unit_price": 200.0,
997
+ "total_price": 40000.0
998
+ },
999
+ {
1000
+ "id": "labor_2",
1001
+ "name": "فني خرسانة",
1002
+ "unit": "يوم",
1003
+ "quantity": 50.0,
1004
+ "unit_price": 350.0,
1005
+ "total_price": 17500.0
1006
+ }
1007
+ ],
1008
+ "equipment": [
1009
+ {
1010
+ "id": "equipment_1",
1011
+ "name": "خلاطة خرسانة",
1012
+ "unit": "يوم",
1013
+ "quantity": 40.0,
1014
+ "unit_price": 800.0,
1015
+ "total_price": 32000.0
1016
+ },
1017
+ {
1018
+ "id": "equipment_2",
1019
+ "name": "مضخة خرسانة",
1020
+ "unit": "يوم",
1021
+ "quantity": 20.0,
1022
+ "unit_price": 1500.0,
1023
+ "total_price": 30000.0
1024
+ }
1025
+ ],
1026
+ "subcontractors": []
1027
+ },
1028
+ {
1029
+ "id": "item_3",
1030
+ "name": "أعمال البناء",
1031
+ "unit": "م2",
1032
+ "quantity": 2000.0,
1033
+ "unit_price": 220.0,
1034
+ "total_price": 440000.0,
1035
+ "materials": [],
1036
+ "labor": [],
1037
+ "equipment": [],
1038
+ "subcontractors": [
1039
+ {
1040
+ "id": "sub_1",
1041
+ "name": "مقاول بناء",
1042
+ "work": "بناء جدران",
1043
+ "quantity": 1,
1044
+ "unit_price": 250000.0,
1045
+ "total_price": 250000.0
1046
+ }
1047
+ ]
1048
+ }
1049
+ ]
1050
+ }
1051
+ }
1052
+
1053
+ # تشغيل التطبيق عند تنفيذ الملف مباشرة
1054
+ if __name__ == "__main__":
1055
+ app = PricingApp()
1056
+ app.run()