فهرست منبع

增值服务代理订单分季度结算划入代理商账户

zhangdongming 1 ماه پیش
والد
کامیت
f39164a7e6
1فایلهای تغییر یافته به همراه149 افزوده شده و 30 حذف شده
  1. 149 30
      AdminController/CloudServiceManage/AgentOrderController.py

+ 149 - 30
AdminController/CloudServiceManage/AgentOrderController.py

@@ -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("周期结算任务锁已释放")