|
@@ -18,6 +18,7 @@ from AgentModel.models import AgentDevice, AgentCloudServicePackage, AgentCustom
|
|
|
AgentDeviceOrderInstallment, AgentAccount
|
|
|
from Ansjer.config import LOGGER
|
|
|
from Model.models import Order_Model, Store_Meal, UnicomCombo
|
|
|
+from Object.RedisObject import RedisObject
|
|
|
from Object.ResponseObject import ResponseObject
|
|
|
from Object.TokenObject import TokenObject
|
|
|
from Service.CommonService import CommonService
|
|
@@ -50,6 +51,9 @@ class AgentOrderView(View):
|
|
|
|
|
|
def validation(self, request_dict, request, operation):
|
|
|
response = ResponseObject()
|
|
|
+ if operation == 'settlementOrder': # 季度结算
|
|
|
+ self.update_periodic_settlement()
|
|
|
+ return response.json(0)
|
|
|
tko = TokenObject(
|
|
|
request.META.get('HTTP_AUTHORIZATION'),
|
|
|
returntpye='pc')
|
|
@@ -61,6 +65,8 @@ class AgentOrderView(View):
|
|
|
|
|
|
self.check_agent_service_package(order_id, uid, int(package_id))
|
|
|
return response.json(0)
|
|
|
+ else:
|
|
|
+ return response.json(414)
|
|
|
|
|
|
@classmethod
|
|
|
def check_agent_service_package(cls, order_id, uid, package_id):
|
|
@@ -449,53 +455,166 @@ class AgentOrderView(View):
|
|
|
except Exception as e:
|
|
|
LOGGER.error(f'保存季度分期结算记录异常: 行号:{e.__traceback__.tb_lineno}, 错误:{repr(e)}')
|
|
|
|
|
|
- @staticmethod
|
|
|
- def update_periodic_settlement():
|
|
|
+ @classmethod
|
|
|
+ def update_periodic_settlement(cls):
|
|
|
"""
|
|
|
- 更新周期结算信息
|
|
|
+ 更新周期结算信息 - 优化版
|
|
|
+
|
|
|
+ 功能:
|
|
|
+ 1. 使用分布式锁确保同一时间只有一个进程在处理结算
|
|
|
+ 2. 添加对账机制,确保数据准确性
|
|
|
+ 3. 增加详细的日志记录
|
|
|
+ 4. 使用Redis缓存避免重复处理
|
|
|
|
|
|
返回值:
|
|
|
- 无返回值
|
|
|
"""
|
|
|
+ # 初始化Redis对象
|
|
|
+ redis_obj = RedisObject()
|
|
|
+
|
|
|
+ # 生成唯一的请求ID用于锁
|
|
|
+ request_id = f"settlement_task_{int(time.time())}"
|
|
|
+ lock_key = "lock:periodic_settlement"
|
|
|
+
|
|
|
+ # 尝试获取分布式锁
|
|
|
+ if not redis_obj.try_lock(lock_key, request_id, expire=10, time_unit_second=60):
|
|
|
+ LOGGER.info("周期结算任务已在其他进程中运行,本次跳过")
|
|
|
+ return
|
|
|
+
|
|
|
+ LOGGER.info("开始执行周期结算任务")
|
|
|
+
|
|
|
try:
|
|
|
+ n_time = int(time.time())
|
|
|
+
|
|
|
+ # 记录开始处理的时间
|
|
|
+ start_time = time.time()
|
|
|
+ LOGGER.info(f"开始查询到期的分期结算记录,当前时间戳: {n_time}")
|
|
|
+
|
|
|
# 根据条件查询需要更新结算信息的订单分期记录
|
|
|
- adoi_qs = AgentDeviceOrderInstallment.objects.filter(status=1, due_date__lte=int(time.time()))
|
|
|
- if not adoi_qs:
|
|
|
- # 如果没有找到符合条件的记录,直接返回
|
|
|
+ adoi_qs = AgentDeviceOrderInstallment.objects.filter(status=1, due_date__lte=n_time)
|
|
|
+
|
|
|
+ if not adoi_qs.exists():
|
|
|
+ LOGGER.info("没有找到需要结算的记录")
|
|
|
return
|
|
|
|
|
|
+ # 记录找到的记录数
|
|
|
+ record_count = adoi_qs.count()
|
|
|
+ LOGGER.info(f"找到 {record_count} 条需要结算的记录")
|
|
|
+
|
|
|
+ # 使用事务处理结算过程
|
|
|
+ from django.db import transaction
|
|
|
+
|
|
|
+ # 准备数据
|
|
|
+ settlement_records = [] # 用于记录处理的结算记录,后续对账使用
|
|
|
ids = []
|
|
|
a_account_list = []
|
|
|
adoi_set = set()
|
|
|
- n_time = int(time.time())
|
|
|
+ total_amount = Decimal('0.00')
|
|
|
+
|
|
|
for item in adoi_qs:
|
|
|
# 准备分期记录的id列表和账户记录列表
|
|
|
ids.append(item.id)
|
|
|
adoi_set.add(item.ado_id)
|
|
|
- a_account_list.append(AgentAccount(ac_id=item.ac_id, amount=item.amount,
|
|
|
- remark=f'周期结算',
|
|
|
- status=1, created_time=n_time,
|
|
|
- updated_time=n_time))
|
|
|
-
|
|
|
- batch_size = 100
|
|
|
-
|
|
|
- # 分批更新分期记录状态
|
|
|
- for i in range(0, len(ids), batch_size):
|
|
|
- AgentDeviceOrderInstallment.objects.filter(id__in=ids[i:i + batch_size]) \
|
|
|
- .update(status=2, settlement_time=n_time, updated_time=n_time)
|
|
|
-
|
|
|
- # 分批创建账户记录
|
|
|
- for i in range(0, len(a_account_list), batch_size):
|
|
|
- AgentAccount.objects.bulk_create(a_account_list[i:i + batch_size])
|
|
|
-
|
|
|
- # 检查是否所有分期都已结算,如果是,则更新订单状态为已结算
|
|
|
- for ado in adoi_set:
|
|
|
- adoi_qs = AgentDeviceOrderInstallment.objects.filter(ado_id=ado, status=1)
|
|
|
- if not adoi_qs.exists():
|
|
|
- AgentDeviceOrder.objects.filter(id=ado, status=1) \
|
|
|
+
|
|
|
+ # 记录结算金额
|
|
|
+ amount = Decimal(str(item.amount)).quantize(Decimal('0.01'))
|
|
|
+ total_amount += amount
|
|
|
+
|
|
|
+ # 创建账户记录对象
|
|
|
+ a_account_list.append(AgentAccount(
|
|
|
+ ac_id=item.ac_id,
|
|
|
+ amount=amount,
|
|
|
+ remark=f'周期结算 - 分期ID:{item.id}',
|
|
|
+ status=1,
|
|
|
+ created_time=n_time,
|
|
|
+ updated_time=n_time
|
|
|
+ ))
|
|
|
+
|
|
|
+ # 记录处理的结算记录
|
|
|
+ settlement_records.append({
|
|
|
+ 'id': item.id,
|
|
|
+ 'ac_id': item.ac_id,
|
|
|
+ 'amount': str(amount),
|
|
|
+ 'due_date': item.due_date
|
|
|
+ })
|
|
|
+
|
|
|
+ # 缓存结算记录用于对账
|
|
|
+ settlement_cache_key = f"settlement:records:{n_time}"
|
|
|
+ redis_obj.set_data(settlement_cache_key, str(settlement_records), expire=86400) # 缓存24小时
|
|
|
+
|
|
|
+ LOGGER.info(f"准备处理 {len(ids)} 条分期记录,总金额: {total_amount}")
|
|
|
+
|
|
|
+ # 使用事务确保数据一致性
|
|
|
+ with transaction.atomic():
|
|
|
+ batch_size = 100
|
|
|
+
|
|
|
+ # 分批更新分期记录状态
|
|
|
+ updated_count = 0
|
|
|
+ for i in range(0, len(ids), batch_size):
|
|
|
+ batch_ids = ids[i:i + batch_size]
|
|
|
+ update_result = AgentDeviceOrderInstallment.objects.filter(id__in=batch_ids) \
|
|
|
.update(status=2, settlement_time=n_time, updated_time=n_time)
|
|
|
+ updated_count += update_result
|
|
|
+ LOGGER.info(f"已更新分期记录状态: {updated_count}/{len(ids)}")
|
|
|
+
|
|
|
+ # 对账检查 - 确保所有记录都已更新
|
|
|
+ if updated_count != len(ids):
|
|
|
+ LOGGER.error(f"对账失败: 应更新 {len(ids)} 条记录,实际更新 {updated_count} 条")
|
|
|
+ # 在事务中抛出异常将触发回滚
|
|
|
+ raise Exception(f"结算记录更新不一致: 应更新 {len(ids)} 条,实际更新 {updated_count} 条")
|
|
|
+
|
|
|
+ # 分批创建账户记录
|
|
|
+ created_accounts = 0
|
|
|
+ for i in range(0, len(a_account_list), batch_size):
|
|
|
+ batch_accounts = a_account_list[i:i + batch_size]
|
|
|
+ created_batch = AgentAccount.objects.bulk_create(batch_accounts)
|
|
|
+ created_accounts += len(created_batch)
|
|
|
+ LOGGER.info(f"已创建账户记录: {created_accounts}/{len(a_account_list)}")
|
|
|
+
|
|
|
+ # 对账检查 - 确保所有账户记录都已创建
|
|
|
+ if created_accounts != len(a_account_list):
|
|
|
+ LOGGER.error(f"对账失败: 应创建 {len(a_account_list)} 条账户记录,实际创建 {created_accounts} 条")
|
|
|
+ raise Exception(
|
|
|
+ f"账户记录创建不一致: 应创建 {len(a_account_list)} 条,实际创建 {created_accounts} 条")
|
|
|
+
|
|
|
+ # 检查是否所有分期都已结算,如果是,则更新订单状态为已结算
|
|
|
+ updated_orders = 0
|
|
|
+ for ado_id in adoi_set:
|
|
|
+ # 检查是否还有未结算的分期
|
|
|
+ if not AgentDeviceOrderInstallment.objects.filter(ado_id=ado_id, status=1).exists():
|
|
|
+ # 更新订单状态为已结算
|
|
|
+ update_result = AgentDeviceOrder.objects.filter(id=ado_id, status=1) \
|
|
|
+ .update(status=2, settlement_time=n_time, updated_time=n_time)
|
|
|
+ if update_result > 0:
|
|
|
+ updated_orders += 1
|
|
|
+ LOGGER.info(f"订单 {ado_id} 所有分期已结算,已更新订单状态")
|
|
|
+
|
|
|
+ LOGGER.info(f"共更新了 {updated_orders} 个订单的状态为已结算")
|
|
|
+
|
|
|
+ # 记录结算摘要到Redis,用于后续查询
|
|
|
+ summary_key = f"settlement:summary:{n_time}"
|
|
|
+ summary_data = {
|
|
|
+ 'timestamp': n_time,
|
|
|
+ 'record_count': record_count,
|
|
|
+ 'total_amount': str(total_amount),
|
|
|
+ 'updated_records': updated_count,
|
|
|
+ 'created_accounts': created_accounts,
|
|
|
+ 'updated_orders': updated_orders,
|
|
|
+ 'duration': round(time.time() - start_time, 2)
|
|
|
+ }
|
|
|
+ redis_obj.set_hash_data(summary_key, summary_data)
|
|
|
+ redis_obj.set_expire(summary_key, 86400 * 7) # 保存7天
|
|
|
+
|
|
|
+ # 记录完成信息
|
|
|
+ end_time = time.time()
|
|
|
+ duration = round(end_time - start_time, 2)
|
|
|
+ LOGGER.info(f"周期结算任务完成,处理时间: {duration}秒,处理记录: {record_count}条,总金额: {total_amount}")
|
|
|
|
|
|
except Exception as e:
|
|
|
- # 记录异常信息
|
|
|
+ # 记录详细的异常信息
|
|
|
LOGGER.error(
|
|
|
- f'*****AgentOrderView.update_periodic_settlement:errLine:{e.__traceback__.tb_lineno}, errMsg:{str(e)}')
|
|
|
+ f'周期结算任务异常: 行号:{e.__traceback__.tb_lineno}, 错误类型:{type(e).__name__}, 错误信息:{repr(e)}')
|
|
|
+ finally:
|
|
|
+ # 释放分布式锁
|
|
|
+ redis_obj.release_lock(lock_key, request_id)
|
|
|
+ LOGGER.info("周期结算任务锁已释放")
|