File size: 10,592 Bytes
82676b8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
"""

خدمة التسعير غير المتزن

"""

import pandas as pd
import numpy as np
from datetime import datetime
import os
import config


class UnbalancedPricing:
    """خدمة التسعير غير المتزن للبنود"""
    
    def __init__(self):
        """تهيئة خدمة التسعير غير المتزن"""
        self.strategies = {
            'front_loading': self.apply_front_loading,
            'back_loading': self.apply_back_loading,
            'confirmed_items': self.apply_confirmed_items_loading,
            'variable_items': self.apply_variable_items_discount
        }
    
    def apply_strategy(self, items_df, strategy, params=None):
        """تطبيق استراتيجية تسعير غير متزن على البنود"""
        # نسخة من البيانات المدخلة للعمل عليها
        df = items_df.copy()
        
        # إضافة عمود إستراتيجية التسعير إذا لم يكن موجوداً
        if 'إستراتيجية التسعير' not in df.columns:
            df['إستراتيجية التسعير'] = 'متوازن'
        
        # تطبيق الإستراتيجية المطلوبة
        if strategy in self.strategies:
            df = self.strategies[strategy](df, params)
        else:
            # إذا كانت الإستراتيجية غير معروفة، أعد البيانات بدون تغيير
            pass
        
        # حساب الإجمالي بعد التعديل
        df['الإجمالي'] = df['الكمية'] * df['سعر الوحدة']
        
        return df
    
    def apply_front_loading(self, items_df, params=None):
        """تطبيق استراتيجية التحميل الأمامي (Front Loading)"""
        df = items_df.copy()
        
        # استخراج المعلمات الافتراضية إذا لم يتم تحديدها
        if params is None:
            params = {
                'early_increase': 1.3,    # زيادة 30% للبنود المبكرة
                'late_decrease': 0.7,     # تخفيض 30% للبنود المتأخرة
                'early_percentage': 0.33,  # نسبة البنود المبكرة 33%
                'late_percentage': 0.33    # نسبة البنود المتأخرة 33%
            }
        
        # تحديد البنود المبكرة والمتأخرة والمتوسطة
        items_count = len(df)
        early_count = int(items_count * params['early_percentage'])
        late_count = int(items_count * params['late_percentage'])
        
        early_items = df.iloc[:early_count].index
        middle_items = df.iloc[early_count:items_count-late_count].index
        late_items = df.iloc[items_count-late_count:].index
        
        # تطبيق الزيادة والنقصان
        for idx in early_items:
            df.at[idx, 'سعر الوحدة'] = df.at[idx, 'سعر الوحدة'] * params['early_increase']
            df.at[idx, 'إستراتيجية التسعير'] = 'زيادة'
        
        for idx in middle_items:
            df.at[idx, 'إستراتيجية التسعير'] = 'متوازن'
        
        for idx in late_items:
            df.at[idx, 'سعر الوحدة'] = df.at[idx, 'سعر الوحدة'] * params['late_decrease']
            df.at[idx, 'إستراتيجية التسعير'] = 'نقص'
        
        return df
    
    def apply_back_loading(self, items_df, params=None):
        """تطبيق استراتيجية التحميل الخلفي (Back Loading)"""
        df = items_df.copy()
        
        # استخراج المعلمات الافتراضية إذا لم يتم تحديدها
        if params is None:
            params = {
                'early_decrease': 0.7,    # تخفيض 30% للبنود المبكرة
                'late_increase': 1.3,     # زيادة 30% للبنود المتأخرة
                'early_percentage': 0.33,  # نسبة البنود المبكرة 33%
                'late_percentage': 0.33    # نسبة البنود المتأخرة 33%
            }
        
        # تحديد البنود المبكرة والمتأخرة والمتوسطة
        items_count = len(df)
        early_count = int(items_count * params['early_percentage'])
        late_count = int(items_count * params['late_percentage'])
        
        early_items = df.iloc[:early_count].index
        middle_items = df.iloc[early_count:items_count-late_count].index
        late_items = df.iloc[items_count-late_count:].index
        
        # تطبيق الزيادة والنقصان
        for idx in early_items:
            df.at[idx, 'سعر الوحدة'] = df.at[idx, 'سعر الوحدة'] * params['early_decrease']
            df.at[idx, 'إستراتيجية التسعير'] = 'نقص'
        
        for idx in middle_items:
            df.at[idx, 'إستراتيجية التسعير'] = 'متوازن'
        
        for idx in late_items:
            df.at[idx, 'سعر الوحدة'] = df.at[idx, 'سعر الوحدة'] * params['late_increase']
            df.at[idx, 'إستراتيجية التسعير'] = 'زيادة'
        
        return df
    
    def apply_confirmed_items_loading(self, items_df, params=None):
        """تطبيق استراتيجية تحميل البنود المؤكدة"""
        df = items_df.copy()
        
        # استخراج المعلمات الافتراضية إذا لم يتم تحديدها
        if params is None:
            params = {
                'confirmed_increase': 1.25,   # زيادة 25% للبنود المؤكدة
                'others_decrease': 0.85,      # تخفيض 15% للبنود الأخرى
                'confirmed_items_indices': []  # قائمة مؤشرات البنود المؤكدة
            }
        
        # إذا لم يتم تحديد البنود المؤكدة، استخدم قواعد اختيار افتراضية
        if not params['confirmed_items_indices']:
            # البنود التي تحتوي على كلمات مثل "أساسات" أو "هيكل" عادة ما تكون مؤكدة
            confirmed_items = []
            for idx, row in df.iterrows():
                description = row['وصف البند'].lower()
                if any(term in description for term in ['أساس', 'خرسان', 'هيكل', 'إنشائي']):
                    confirmed_items.append(idx)
        else:
            confirmed_items = params['confirmed_items_indices']
        
        # تحديد البنود غير المؤكدة
        all_indices = set(range(len(df)))
        confirmed_indices = set(confirmed_items)
        variable_indices = list(all_indices - confirmed_indices)
        
        # تطبيق الزيادة والنقصان
        for idx in confirmed_items:
            df.at[idx, 'سعر الوحدة'] = df.at[idx, 'سعر الوحدة'] * params['confirmed_increase']
            df.at[idx, 'إستراتيجية التسعير'] = 'زيادة'
        
        for idx in variable_indices:
            df.at[idx, 'سعر الوحدة'] = df.at[idx, 'سعر الوحدة'] * params['others_decrease']
            df.at[idx, 'إستراتيجية التسعير'] = 'نقص'
        
        return df
    
    def apply_variable_items_discount(self, items_df, params=None):
        """تطبيق استراتيجية تخفيض البنود المحتمل زيادتها"""
        df = items_df.copy()
        
        # استخراج المعلمات الافتراضية إذا لم يتم تحديدها
        if params is None:
            params = {
                'variable_decrease': 0.7,    # تخفيض 30% للبنود المحتمل زيادتها
                'others_increase': 1.15,     # زيادة 15% للبنود الأخرى
                'variable_items_indices': []  # قائمة مؤشرات البنود المحتمل زيادتها
            }
        
        # إذا لم يتم تحديد البنود المحتمل زيادتها، استخدم قواعد اختيار افتراضية
        if not params['variable_items_indices']:
            # البنود التي تحتوي على كلمات مثل "حفر" أو "ردم" عادة ما تكون محتمل زيادتها
            variable_items = []
            for idx, row in df.iterrows():
                description = row['وصف البند'].lower()
                if any(term in description for term in ['حفر', 'ردم', 'تمديد', 'صرف', 'مياه']):
                    variable_items.append(idx)
        else:
            variable_items = params['variable_items_indices']
        
        # تحديد البنود الأخرى
        all_indices = set(range(len(df)))
        variable_indices = set(variable_items)
        other_indices = list(all_indices - variable_indices)
        
        # تطبيق الزيادة والنقصان
        for idx in variable_items:
            df.at[idx, 'سعر الوحدة'] = df.at[idx, 'سعر الوحدة'] * params['variable_decrease']
            df.at[idx, 'إستراتيجية التسعير'] = 'نقص'
        
        for idx in other_indices:
            df.at[idx, 'سعر الوحدة'] = df.at[idx, 'سعر الوحدة'] * params['others_increase']
            df.at[idx, 'إستراتيجية التسعير'] = 'زيادة'
        
        return df
    
    def calibrate_prices(self, original_df, unbalanced_df):
        """معايرة الأسعار للحفاظ على إجمالي التسعير الأصلي"""
        # حساب الإجماليات
        original_total = original_df['الإجمالي'].sum()
        unbalanced_total = unbalanced_df['الإجمالي'].sum()
        
        # نسخة من البيانات المدخلة للعمل عليها
        df = unbalanced_df.copy()
        
        # حساب معامل التعديل
        adjustment_factor = original_total / unbalanced_total if unbalanced_total > 0 else 1.0
        
        # تعديل الأسعار
        df['سعر الوحدة'] = df['سعر الوحدة'] * adjustment_factor
        
        # حساب الإجمالي بعد التعديل
        df['الإجمالي'] = df['الكمية'] * df['سعر الوحدة']
        
        return df