|
"""
|
|
خدمة التسعير غير المتزن
|
|
"""
|
|
|
|
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,
|
|
'late_decrease': 0.7,
|
|
'early_percentage': 0.33,
|
|
'late_percentage': 0.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,
|
|
'late_increase': 1.3,
|
|
'early_percentage': 0.33,
|
|
'late_percentage': 0.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,
|
|
'others_decrease': 0.85,
|
|
'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,
|
|
'others_increase': 1.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 |