|
@@ -87,7 +87,7 @@ class AgentOrderView(View):
|
|
return True
|
|
return True
|
|
except Exception as e:
|
|
except Exception as e:
|
|
LOGGER.error('*****支付成功保存云服务代理订单异常orderID:{},errLine:{}, errMsg:{}'
|
|
LOGGER.error('*****支付成功保存云服务代理订单异常orderID:{},errLine:{}, errMsg:{}'
|
|
- .format(order_id, e.__traceback__.tb_lineno, repr(e)))
|
|
|
|
|
|
+ .format(order_id, e.__traceback__.tb_lineno, repr(e)))
|
|
return False
|
|
return False
|
|
|
|
|
|
@classmethod
|
|
@classmethod
|
|
@@ -98,7 +98,8 @@ class AgentOrderView(View):
|
|
try:
|
|
try:
|
|
order_qs = Order_Model.objects.filter(orderID=order_id, status=1).values('price', 'payTime', 'order_type')
|
|
order_qs = Order_Model.objects.filter(orderID=order_id, status=1).values('price', 'payTime', 'order_type')
|
|
if not order_qs.exists():
|
|
if not order_qs.exists():
|
|
- LOGGER.info(f'******save_agent_package当前代理客户未添加此套餐******ac_id:{ac_id},package_id:{package_id}')
|
|
|
|
|
|
+ LOGGER.info(
|
|
|
|
+ f'******save_agent_package当前代理客户未添加此套餐******ac_id:{ac_id},package_id:{package_id}')
|
|
return
|
|
return
|
|
|
|
|
|
order_type = order_qs[0]['order_type']
|
|
order_type = order_qs[0]['order_type']
|
|
@@ -109,14 +110,16 @@ class AgentOrderView(View):
|
|
agent_package_qs = AgentCloudServicePackage.objects.filter(type=package_type, package_id=package_id,
|
|
agent_package_qs = AgentCloudServicePackage.objects.filter(type=package_type, package_id=package_id,
|
|
status=1)
|
|
status=1)
|
|
if not agent_package_qs.exists():
|
|
if not agent_package_qs.exists():
|
|
- LOGGER.info(f'******save_agent_package当前套餐未设置代理******order_id:{order_id},serial_number:{serial_number}')
|
|
|
|
|
|
+ LOGGER.info(
|
|
|
|
+ f'******save_agent_package当前套餐未设置代理******order_id:{order_id},serial_number:{serial_number}')
|
|
return
|
|
return
|
|
|
|
|
|
agent_package = agent_package_qs.first() # 代理云服务套餐
|
|
agent_package = agent_package_qs.first() # 代理云服务套餐
|
|
LOGGER.info(f'******save_agent_package代理套餐******service_name:{agent_package_qs.first().service_name}')
|
|
LOGGER.info(f'******save_agent_package代理套餐******service_name:{agent_package_qs.first().service_name}')
|
|
acp_qs = AgentCustomerPackage.objects.filter(ac_id=ac_id, cs_id=agent_package.id).values('id')
|
|
acp_qs = AgentCustomerPackage.objects.filter(ac_id=ac_id, cs_id=agent_package.id).values('id')
|
|
if not acp_qs.exists():
|
|
if not acp_qs.exists():
|
|
- LOGGER.info(f'******save_agent_package当前代理客户未添加此套餐******ac_id:{ac_id},package_id:{package_id}')
|
|
|
|
|
|
+ LOGGER.info(
|
|
|
|
+ f'******save_agent_package当前代理客户未添加此套餐******ac_id:{ac_id},package_id:{package_id}')
|
|
return
|
|
return
|
|
|
|
|
|
# 组装数据
|
|
# 组装数据
|
|
@@ -131,7 +134,8 @@ class AgentOrderView(View):
|
|
agent_order_obj = AgentDeviceOrder.objects.create(**dict_data)
|
|
agent_order_obj = AgentDeviceOrder.objects.create(**dict_data)
|
|
|
|
|
|
# 保存分期结算记录
|
|
# 保存分期结算记录
|
|
- cls.save_order_installment(agent_order_obj.id, package_type, package_id, profit, ac_id)
|
|
|
|
|
|
+ cls.save_order_installment(agent_order_obj.id, package_type, package_id, profit, ac_id,
|
|
|
|
+ order_qs[0]['payTime'])
|
|
|
|
|
|
LOGGER.info(f'******save_agent_package代理订单存表结束:{dict_data}')
|
|
LOGGER.info(f'******save_agent_package代理订单存表结束:{dict_data}')
|
|
except Exception as e:
|
|
except Exception as e:
|
|
@@ -158,165 +162,292 @@ class AgentOrderView(View):
|
|
return profit
|
|
return profit
|
|
|
|
|
|
@classmethod
|
|
@classmethod
|
|
- def get_settlement_interval(cls, package_type, package_id):
|
|
|
|
- try:
|
|
|
|
- if package_type == 1: # 云存
|
|
|
|
- store_qs = Store_Meal.objects.filter(id=package_id).values('day', 'bucket_id', 'expire',
|
|
|
|
- 'icloud_store_meal_id')
|
|
|
|
- if not store_qs.exists():
|
|
|
|
- return []
|
|
|
|
-
|
|
|
|
- # 根据套餐周期计算往后每个月26号作为结算时间
|
|
|
|
- return cls.get_future_timestamps(store_qs[0]['expire'])
|
|
|
|
-
|
|
|
|
- elif package_type == 2: # 4G
|
|
|
|
- combo4g_qs = UnicomCombo.objects.filter(id=package_id).values('expiration_days', 'expiration_type')
|
|
|
|
- if not combo4g_qs.exists():
|
|
|
|
- return []
|
|
|
|
-
|
|
|
|
- # 目前4G套餐都是基于按天类型创建
|
|
|
|
- if combo4g_qs[0]['expiration_type'] == 0 and combo4g_qs[0]['expiration_days'] > 0:
|
|
|
|
- months = int(combo4g_qs[0]['expiration_days'] / 30)
|
|
|
|
-
|
|
|
|
- # 根据套餐周期计算往后每个月26号作为结算时间
|
|
|
|
- return cls.get_future_timestamps(months)
|
|
|
|
- except Exception as e:
|
|
|
|
- LOGGER.info('*****AgentOrderView.get_settlement_interval:errLine:{}, errMsg:{}'
|
|
|
|
- .format(e.__traceback__.tb_lineno, repr(e)))
|
|
|
|
- return []
|
|
|
|
|
|
+ def get_quarterly_settlement_dates(cls, start_date, months):
|
|
|
|
+ """
|
|
|
|
+ 获取季度结算日期列表,按照以下规则:
|
|
|
|
+ 1. 固定在四个季度结算日期(1月1日、4月1日、7月1日、10月1日)进行结算
|
|
|
|
+ 2. 从购买时间到结算日不满1个月的不在当前季度结算,累积到下一个季度
|
|
|
|
+ 3. 中间季度每季度计算3个月
|
|
|
|
+ 4. 最后一个季度计算剩余的时间
|
|
|
|
+
|
|
|
|
+ :param start_date: 套餐开始日期(datetime)
|
|
|
|
+ :param months: 套餐总月数
|
|
|
|
+ :return: 包含(结算日期timestamp, 该季度使用月数)的元组列表
|
|
|
|
+ """
|
|
|
|
+ # 固定的季度结算日期
|
|
|
|
+ QUARTER_DATES = [(1, 1), (4, 1), (7, 1), (10, 1)] # (月, 日)
|
|
|
|
+
|
|
|
|
+ # 计算套餐结束日期
|
|
|
|
+ end_date = start_date + timedelta(days=int(months * 30.5))
|
|
|
|
+
|
|
|
|
+ # 初始化结果列表
|
|
|
|
+ result = []
|
|
|
|
+
|
|
|
|
+ # 找到开始日期后的第一个季度结算日
|
|
|
|
+ current_year = start_date.year
|
|
|
|
+ current_quarter_idx = 0
|
|
|
|
+
|
|
|
|
+ # 找到开始日期之后的第一个季度结算日
|
|
|
|
+ for i, (month, day) in enumerate(QUARTER_DATES):
|
|
|
|
+ quarter_date = datetime(current_year, month, day)
|
|
|
|
+ if quarter_date > start_date:
|
|
|
|
+ current_quarter_idx = i
|
|
|
|
+ break
|
|
|
|
+ else:
|
|
|
|
+ # 如果当年没有更多季度结算日,则移到下一年的第一个季度结算日
|
|
|
|
+ current_year += 1
|
|
|
|
+ current_quarter_idx = 0
|
|
|
|
+
|
|
|
|
+ # 第一个季度的结算日期
|
|
|
|
+ month, day = QUARTER_DATES[current_quarter_idx]
|
|
|
|
+ first_settlement_date = datetime(current_year, month, day)
|
|
|
|
+
|
|
|
|
+ # 计算第一个季度的整月数
|
|
|
|
+ days_in_first_quarter = (first_settlement_date - start_date).days
|
|
|
|
+ whole_months_first_quarter = int(days_in_first_quarter / 30.5)
|
|
|
|
+
|
|
|
|
+ # 计算剩余的月数(总月数减去第一个季度的整月数,如果第一个季度有整月数)
|
|
|
|
+ remaining_months = months
|
|
|
|
+
|
|
|
|
+ # 如果第一个季度有整月数,则添加第一个季度的结算记录并减去已结算的月数
|
|
|
|
+ if whole_months_first_quarter >= 1:
|
|
|
|
+ result.append((int(first_settlement_date.timestamp()), whole_months_first_quarter))
|
|
|
|
+ remaining_months -= whole_months_first_quarter
|
|
|
|
+ else:
|
|
|
|
+ # 即使不足1个月,也添加第一个季度的结算记录,但月数为0
|
|
|
|
+ # 这样可以确保在7月1日进行第一次结算
|
|
|
|
+ result.append((int(first_settlement_date.timestamp()), 0))
|
|
|
|
+
|
|
|
|
+ # 如果没有剩余月数,直接返回结果
|
|
|
|
+ if remaining_months <= 0:
|
|
|
|
+ return result
|
|
|
|
+
|
|
|
|
+ # 特殊处理年套餐(12个月)的情况
|
|
|
|
+ if months == 12 and whole_months_first_quarter == 0:
|
|
|
|
+ # 确保总共有5次季度结算,最后一次是剩余的月数
|
|
|
|
+ # 第一次结算已经添加(7月1日,整月数为0)
|
|
|
|
+
|
|
|
|
+ # 添加第二次结算(10月1日,整月数为3)
|
|
|
|
+ current_quarter_idx = (current_quarter_idx + 1) % len(QUARTER_DATES)
|
|
|
|
+ if current_quarter_idx == 0:
|
|
|
|
+ current_year += 1
|
|
|
|
+ month, day = QUARTER_DATES[current_quarter_idx]
|
|
|
|
+ settlement_date = datetime(current_year, month, day)
|
|
|
|
+ result.append((int(settlement_date.timestamp()), 3))
|
|
|
|
+
|
|
|
|
+ # 添加第三次结算(1月1日,整月数为3)
|
|
|
|
+ current_quarter_idx = (current_quarter_idx + 1) % len(QUARTER_DATES)
|
|
|
|
+ if current_quarter_idx == 0:
|
|
|
|
+ current_year += 1
|
|
|
|
+ month, day = QUARTER_DATES[current_quarter_idx]
|
|
|
|
+ settlement_date = datetime(current_year, month, day)
|
|
|
|
+ result.append((int(settlement_date.timestamp()), 3))
|
|
|
|
+
|
|
|
|
+ # 添加第四次结算(4月1日,整月数为3)
|
|
|
|
+ current_quarter_idx = (current_quarter_idx + 1) % len(QUARTER_DATES)
|
|
|
|
+ if current_quarter_idx == 0:
|
|
|
|
+ current_year += 1
|
|
|
|
+ month, day = QUARTER_DATES[current_quarter_idx]
|
|
|
|
+ settlement_date = datetime(current_year, month, day)
|
|
|
|
+ result.append((int(settlement_date.timestamp()), 3))
|
|
|
|
+
|
|
|
|
+ # 添加第五次结算(7月1日,整月数为剩余的月数)
|
|
|
|
+ current_quarter_idx = (current_quarter_idx + 1) % len(QUARTER_DATES)
|
|
|
|
+ if current_quarter_idx == 0:
|
|
|
|
+ current_year += 1
|
|
|
|
+ month, day = QUARTER_DATES[current_quarter_idx]
|
|
|
|
+ settlement_date = datetime(current_year, month, day)
|
|
|
|
+ # 剩余的月数为12减去前面已经结算的月数
|
|
|
|
+ remaining = 12 - (0 + 3 + 3 + 3)
|
|
|
|
+ result.append((int(settlement_date.timestamp()), remaining))
|
|
|
|
+
|
|
|
|
+ return result
|
|
|
|
+
|
|
|
|
+ # 非年套餐的处理逻辑
|
|
|
|
+ # 计算完整季度的数量(每季度3个月)
|
|
|
|
+ full_quarters = int(remaining_months / 3)
|
|
|
|
+
|
|
|
|
+ # 计算最后一个季度的剩余月数
|
|
|
|
+ last_quarter_months = remaining_months % 3
|
|
|
|
+
|
|
|
|
+ # 当前日期设置为第一个结算日期
|
|
|
|
+ current_date = first_settlement_date
|
|
|
|
+
|
|
|
|
+ # 添加完整季度的结算记录
|
|
|
|
+ for _ in range(full_quarters):
|
|
|
|
+ # 移到下一个季度结算日
|
|
|
|
+ current_quarter_idx = (current_quarter_idx + 1) % len(QUARTER_DATES)
|
|
|
|
+ if current_quarter_idx == 0:
|
|
|
|
+ current_year += 1
|
|
|
|
+
|
|
|
|
+ month, day = QUARTER_DATES[current_quarter_idx]
|
|
|
|
+ settlement_date = datetime(current_year, month, day)
|
|
|
|
+
|
|
|
|
+ # 添加完整季度的结算记录(3个月)
|
|
|
|
+ result.append((int(settlement_date.timestamp()), 3))
|
|
|
|
+
|
|
|
|
+ # 更新当前日期
|
|
|
|
+ current_date = settlement_date
|
|
|
|
+
|
|
|
|
+ # 如果有剩余月数,添加最后一个季度的结算记录
|
|
|
|
+ if last_quarter_months > 0:
|
|
|
|
+ # 移到下一个季度结算日
|
|
|
|
+ current_quarter_idx = (current_quarter_idx + 1) % len(QUARTER_DATES)
|
|
|
|
+ if current_quarter_idx == 0:
|
|
|
|
+ current_year += 1
|
|
|
|
+
|
|
|
|
+ month, day = QUARTER_DATES[current_quarter_idx]
|
|
|
|
+ settlement_date = datetime(current_year, month, day)
|
|
|
|
+
|
|
|
|
+ # 添加最后一个季度的结算记录(剩余月数)
|
|
|
|
+ result.append((int(settlement_date.timestamp()), last_quarter_months))
|
|
|
|
+
|
|
|
|
+ return result
|
|
|
|
|
|
@staticmethod
|
|
@staticmethod
|
|
- def get_future_timestamps(months):
|
|
|
|
|
|
+ def calculate_months_in_period(start_date, end_date):
|
|
"""
|
|
"""
|
|
- 生成未来若干个月的第一个月的26号11点的timestamp列表。
|
|
|
|
-
|
|
|
|
- 参数:
|
|
|
|
- months -- 未来需要生成timestamp的月份数量
|
|
|
|
|
|
+ 计算两个日期之间的整月数,不足一个月不计入
|
|
|
|
|
|
- 返回值:
|
|
|
|
- timestamps -- 包含未来months个月第一个月的26号11点的timestamp的列表
|
|
|
|
|
|
+ :param start_date: 开始日期
|
|
|
|
+ :param end_date: 结束日期
|
|
|
|
+ :return: 整月数
|
|
"""
|
|
"""
|
|
- current_time = datetime.now() # 获取当前时间,注意这会是系统当前时区的时间
|
|
|
|
- current_month = current_time.month
|
|
|
|
- current_year = current_time.year
|
|
|
|
-
|
|
|
|
- timestamps = []
|
|
|
|
- for _ in range(months):
|
|
|
|
- # 如果当前月已经是需要生成的月份,则年份和月份不变
|
|
|
|
- if current_month == 1 and _ == 0:
|
|
|
|
- next_year = current_year
|
|
|
|
- next_month = current_month + 1
|
|
|
|
- else:
|
|
|
|
- # 计算下一个月的年和月
|
|
|
|
- if current_month == 12:
|
|
|
|
- next_month = 1
|
|
|
|
- next_year = current_year + 1
|
|
|
|
- else:
|
|
|
|
- next_month = current_month + 1
|
|
|
|
- next_year = current_year
|
|
|
|
-
|
|
|
|
- # 生成下个月的26号11点的时间点
|
|
|
|
- next_date = datetime(next_year, next_month, 26, 11, 0, 0)
|
|
|
|
|
|
+ # 计算天数差
|
|
|
|
+ days_diff = (end_date - start_date).days
|
|
|
|
|
|
- # 如果生成的日期超过了当月的实际天数(比如2月没有26号),则需要回退到当月的最后一天
|
|
|
|
- last_day_of_month = (datetime(next_year, next_month, 1) + timedelta(days=31)).replace(day=1) - timedelta(
|
|
|
|
- days=1)
|
|
|
|
- if next_date > last_day_of_month:
|
|
|
|
- next_date = last_day_of_month.replace(hour=11, minute=0, second=0, microsecond=0)
|
|
|
|
|
|
+ # 转换为整月数(按平均每月30.5天计算)
|
|
|
|
+ whole_months = int(days_diff / 30.5)
|
|
|
|
|
|
- timestamps.append(int(next_date.timestamp()))
|
|
|
|
|
|
+ return whole_months
|
|
|
|
|
|
- # 更新当前月份和年份为下一次循环使用
|
|
|
|
- current_month = next_month
|
|
|
|
- current_year = next_year
|
|
|
|
|
|
+ @staticmethod
|
|
|
|
+ def calculate_quarterly_profit(profit, settlement_dates_with_months):
|
|
|
|
+ """
|
|
|
|
+ 计算季度利润分配,基于整月数
|
|
|
|
|
|
- return timestamps
|
|
|
|
|
|
+ :param profit: 总利润
|
|
|
|
+ :param settlement_dates_with_months: 包含(结算日期, 整月数)的元组列表
|
|
|
|
+ :return: 每个季度的利润列表
|
|
|
|
+ """
|
|
|
|
+ profit = Decimal(str(profit)).quantize(Decimal('0.01'))
|
|
|
|
|
|
- @staticmethod
|
|
|
|
- def distribute_commission(commission, periods):
|
|
|
|
- # 转换佣金和期数为Decimal类型,并设置精度
|
|
|
|
- commission = Decimal(str(commission)).quantize(Decimal('0.01'))
|
|
|
|
- periods = Decimal(periods)
|
|
|
|
|
|
+ # 计算总整月数
|
|
|
|
+ total_months = sum(months for _, months in settlement_dates_with_months)
|
|
|
|
|
|
- # 每期基础金额(向下取整到最接近的0.01)
|
|
|
|
- base_amount = (commission / periods).quantize(Decimal('0.01'), rounding=ROUND_DOWN)
|
|
|
|
|
|
+ # 如果总月数为0,返回空列表
|
|
|
|
+ if total_months == 0:
|
|
|
|
+ return []
|
|
|
|
|
|
- # 初始化每期分配的金额列表
|
|
|
|
- distributed_amounts = [base_amount] * int(periods)
|
|
|
|
|
|
+ # 计算每月利润
|
|
|
|
+ monthly_profit = profit / Decimal(total_months)
|
|
|
|
|
|
- # 计算按照基础金额分配后的总和
|
|
|
|
- total_distributed = sum(distributed_amounts)
|
|
|
|
|
|
+ # 计算每个季度的利润
|
|
|
|
+ quarterly_amounts = []
|
|
|
|
+ for _, months in settlement_dates_with_months:
|
|
|
|
+ # 计算当前季度的利润(基于整月数)
|
|
|
|
+ amount = (monthly_profit * Decimal(months)).quantize(Decimal('0.01'), rounding=ROUND_DOWN)
|
|
|
|
+ quarterly_amounts.append(amount)
|
|
|
|
|
|
- # 计算剩余需要分配的金额
|
|
|
|
- remainder = commission - total_distributed
|
|
|
|
|
|
+ # 处理舍入误差,确保总和等于总利润
|
|
|
|
+ total_allocated = sum(quarterly_amounts)
|
|
|
|
+ remainder = profit - total_allocated
|
|
|
|
|
|
- # 分配剩余金额
|
|
|
|
- if remainder > Decimal('0'):
|
|
|
|
- # 从第一期开始分配剩余金额
|
|
|
|
- for i in range(len(distributed_amounts)):
|
|
|
|
- if remainder >= Decimal('0.01'):
|
|
|
|
- distributed_amounts[i] += Decimal('0.01')
|
|
|
|
- remainder -= Decimal('0.01')
|
|
|
|
- else:
|
|
|
|
- # 如果剩余金额不足0.01,则将其全部加到当前期
|
|
|
|
- distributed_amounts[i] += remainder
|
|
|
|
- break
|
|
|
|
|
|
+ # 将剩余的分配到第一个季度
|
|
|
|
+ if remainder > Decimal('0') and quarterly_amounts:
|
|
|
|
+ quarterly_amounts[0] += remainder
|
|
|
|
|
|
- return distributed_amounts
|
|
|
|
|
|
+ return quarterly_amounts
|
|
|
|
|
|
@classmethod
|
|
@classmethod
|
|
- def save_order_installment(cls, agent_order_id, package_type, package_id, profit, ac_id=None):
|
|
|
|
|
|
+ def save_order_installment(cls, agent_order_id, package_type, package_id, profit, ac_id=None, pay_time=0):
|
|
"""
|
|
"""
|
|
- 保存代理订单分期信息
|
|
|
|
|
|
+ 保存代理订单分期信息(季度结算逻辑),不满一个月的时间累积到下一个季度
|
|
|
|
|
|
:param cls: 类方法的约定参数
|
|
:param cls: 类方法的约定参数
|
|
:param agent_order_id: 代理订单ID
|
|
:param agent_order_id: 代理订单ID
|
|
- :param package_type: 套餐类型
|
|
|
|
|
|
+ :param package_type: 套餐类型(1:云存, 2:4G)
|
|
:param package_id: 套餐ID
|
|
:param package_id: 套餐ID
|
|
:param profit: 利润总额
|
|
:param profit: 利润总额
|
|
- :return: 无返回值
|
|
|
|
:param ac_id: 代理客户ID
|
|
:param ac_id: 代理客户ID
|
|
|
|
+ :param pay_time: 订单支付时间
|
|
|
|
+ :return: 无返回值
|
|
"""
|
|
"""
|
|
try:
|
|
try:
|
|
- # 根据包裹类型和ID获取结算时间间隔列表
|
|
|
|
- time_list = cls.get_settlement_interval(package_type, package_id)
|
|
|
|
- period_number = len(time_list) # 计算分期总数
|
|
|
|
|
|
+ # 转换支付时间为datetime对象
|
|
|
|
+ pay_time_dt = datetime.fromtimestamp(pay_time)
|
|
|
|
+
|
|
|
|
+ # 获取套餐月数
|
|
|
|
+ if package_type == 1: # 云存
|
|
|
|
+ store = Store_Meal.objects.filter(id=package_id).first()
|
|
|
|
+ if not store:
|
|
|
|
+ LOGGER.info(f'云存套餐不存在: {package_id}')
|
|
|
|
+ return
|
|
|
|
+ months = store.expire
|
|
|
|
+ else: # 4G
|
|
|
|
+ combo = UnicomCombo.objects.filter(id=package_id).first()
|
|
|
|
+ if not combo:
|
|
|
|
+ LOGGER.info(f'4G套餐不存在: {package_id}')
|
|
|
|
+ return
|
|
|
|
+ months = int(combo.expiration_days / 30)
|
|
|
|
+
|
|
|
|
+ if months <= 0 or profit <= 0:
|
|
|
|
+ LOGGER.info(f'无效参数: months={months}, profit={profit}')
|
|
|
|
+ return
|
|
|
|
|
|
- # 输入合理性检查
|
|
|
|
- if period_number == 0 or profit <= 0:
|
|
|
|
- LOGGER.info(f'Invalid input parameters: period_number={period_number}, profit={profit}')
|
|
|
|
|
|
+ LOGGER.info(
|
|
|
|
+ f'开始计算季度结算: 订单ID={agent_order_id}, 开始日期={pay_time_dt}, 套餐月数={months}, 总利润={profit}')
|
|
|
|
+
|
|
|
|
+ # 获取季度结算日期和每个季度的整月数
|
|
|
|
+ settlement_dates_with_months = cls.get_quarterly_settlement_dates(pay_time_dt, months)
|
|
|
|
+
|
|
|
|
+ # 记录季度结算日期和月数
|
|
|
|
+ for i, (date, months_used) in enumerate(settlement_dates_with_months):
|
|
|
|
+ date_str = datetime.fromtimestamp(date).strftime('%Y-%m-%d')
|
|
|
|
+ LOGGER.info(f'季度{i + 1}结算日期: {date_str}, 整月数: {months_used}')
|
|
|
|
+
|
|
|
|
+ # 如果没有有效的结算日期,则退出
|
|
|
|
+ if not settlement_dates_with_months:
|
|
|
|
+ LOGGER.info(f'没有有效的季度结算日期: start_date={pay_time_dt}, months={months}')
|
|
return
|
|
return
|
|
|
|
|
|
- n_time = int(datetime.now().timestamp()) # 获取当前时间戳
|
|
|
|
- # 利润总额按分期数平均分配
|
|
|
|
- amount_list = cls.distribute_commission(profit, period_number)
|
|
|
|
|
|
+ # 计算每个季度的利润分配
|
|
|
|
+ amounts = cls.calculate_quarterly_profit(profit, settlement_dates_with_months)
|
|
|
|
+
|
|
|
|
+ # 记录每个季度的利润分配
|
|
|
|
+ for i, amount in enumerate(amounts):
|
|
|
|
+ LOGGER.info(f'季度{i + 1}利润分配: {amount}')
|
|
|
|
|
|
|
|
+ # 创建分期记录
|
|
|
|
+ n_time = int(time.time())
|
|
installment_list = []
|
|
installment_list = []
|
|
- # 遍历分期数,生成分期记录列表
|
|
|
|
- for time_point in range(period_number):
|
|
|
|
- installment_list.append(AgentDeviceOrderInstallment(ado_id=agent_order_id,
|
|
|
|
- period_number=period_number,
|
|
|
|
- ac_id=ac_id,
|
|
|
|
- amount=amount_list[time_point],
|
|
|
|
- due_date=time_list[time_point],
|
|
|
|
- status=1,
|
|
|
|
- created_time=n_time,
|
|
|
|
- updated_time=n_time))
|
|
|
|
-
|
|
|
|
- # 分批处理大量数据,避免数据库压力过大
|
|
|
|
- batch_size = 100
|
|
|
|
- for i in range(0, len(installment_list), batch_size):
|
|
|
|
- AgentDeviceOrderInstallment.objects.bulk_create(
|
|
|
|
- installment_list[i:i + batch_size]
|
|
|
|
- )
|
|
|
|
|
|
|
|
- # 记录创建完成的日志
|
|
|
|
- LOGGER.info(f'*****AgentOrderView.save_OrderInstallment分期结算记录创建完成:{len(installment_list)} records')
|
|
|
|
|
|
+ for i, ((settlement_date, months_used), amount) in enumerate(zip(settlement_dates_with_months, amounts)):
|
|
|
|
+ # 只有使用满一个月才创建结算记录
|
|
|
|
+ if months_used >= 1:
|
|
|
|
+ installment_list.append(AgentDeviceOrderInstallment(
|
|
|
|
+ ado_id=agent_order_id,
|
|
|
|
+ period_number=len(settlement_dates_with_months),
|
|
|
|
+ ac_id=ac_id,
|
|
|
|
+ amount=amount,
|
|
|
|
+ due_date=settlement_date,
|
|
|
|
+ status=1,
|
|
|
|
+ created_time=n_time,
|
|
|
|
+ updated_time=n_time
|
|
|
|
+ ))
|
|
|
|
+
|
|
|
|
+ # 批量创建
|
|
|
|
+ if installment_list:
|
|
|
|
+ batch_size = 100
|
|
|
|
+ for i in range(0, len(installment_list), batch_size):
|
|
|
|
+ AgentDeviceOrderInstallment.objects.bulk_create(installment_list[i:i + batch_size])
|
|
|
|
+
|
|
|
|
+ LOGGER.info(f'季度分期结算记录创建完成: {len(installment_list)}条, 订单ID: {agent_order_id}')
|
|
|
|
+ else:
|
|
|
|
+ LOGGER.info(f'没有创建季度分期结算记录: 订单ID: {agent_order_id}')
|
|
|
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
- # 记录异常信息
|
|
|
|
- LOGGER.error('*****AgentOrderView.save_OrderInstallment:errLine:{}, errMsg:{}'
|
|
|
|
- .format(e.__traceback__.tb_lineno, repr(e)))
|
|
|
|
|
|
+ LOGGER.error(f'保存季度分期结算记录异常: 行号:{e.__traceback__.tb_lineno}, 错误:{repr(e)}')
|
|
|
|
|
|
@staticmethod
|
|
@staticmethod
|
|
def update_periodic_settlement():
|
|
def update_periodic_settlement():
|