1
0
forked from erp-dev/erp
Files
erpnew/settlement/management/commands/run_daily_settlement.py

152 lines
4.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
手动触发日结任务management command
用法:
python manage.py run_daily_settlement
选项:
--merchant-id: 仅处理指定商户ID
--date: 指定结算日期YYYY-MM-DD默认为昨天
--sync: 同步执行(阻塞),默认为异步(通过 Celery
"""
from datetime import datetime
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from django.utils import timezone
from settlement.models import DailySettlementConfig
class Command(BaseCommand):
help = '手动触发日结任务(支持指定商户、日期、同步/异步执行)'
def add_arguments(self, parser):
parser.add_argument(
'--merchant-id',
type=int,
help='仅处理指定商户ID',
)
parser.add_argument(
'--date',
type=str,
help='指定结算日期YYYY-MM-DD默认为昨天',
)
parser.add_argument(
'--sync',
action='store_true',
help='同步执行(阻塞),默认为异步(通过 Celery',
)
def handle(self, *args, **options):
from settlement.tasks import run_daily_settlement, run_merchant_daily_settlement
merchant_id = options.get('merchant_id')
date_str = options.get('date')
sync_mode = bool(options['sync'])
# 解析日期
if date_str:
try:
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date()
except ValueError as e:
raise CommandError(f'--date 必须为 YYYY-MM-DD 格式: {e}')
else:
date_obj = timezone.localdate() - timezone.timedelta(days=1)
self.stdout.write(f'[日结] 开始执行: 日期={date_obj}, 同步模式={sync_mode}')
if merchant_id:
# 处理单个商户
self._handle_single_merchant(
merchant_id=merchant_id,
date_obj=date_obj,
sync_mode=sync_mode
)
else:
# 处理所有商户
self._handle_all_merchants(
date_obj=date_obj,
sync_mode=sync_mode
)
def _handle_single_merchant(self, merchant_id: int, date_obj, sync_mode: bool):
"""处理单个商户的日结"""
from settlement.tasks import run_merchant_daily_settlement
try:
config = DailySettlementConfig.objects.select_related('merchant').get(
merchant_id=merchant_id
)
except DailySettlementConfig.DoesNotExist:
self.stderr.write(
self.style.ERROR(
f'商户 {merchant_id} 未配置日结,跳过'
)
)
return
if not config.settlement_modules:
self.stdout.write(
f'商户 {config.merchant.name} (ID={merchant_id}) 未配置统计模块,跳过'
)
return
self.stdout.write(
f'处理商户: {config.merchant.name} (ID={merchant_id}), '
f'模块={config.settlement_modules}'
)
if sync_mode:
# 同步执行
result = run_merchant_daily_settlement(
merchant_id=merchant_id,
settlement_date=str(date_obj)
)
self.stdout.write(
self.style.SUCCESS(
f'商户 {merchant_id} 日结完成: {result}'
)
)
else:
# 异步执行(通过 Celery
task = run_merchant_daily_settlement.delay(
merchant_id=merchant_id,
settlement_date=str(date_obj)
)
self.stdout.write(
f'商户 {merchant_id} 日结任务已提交: task_id={task.id}'
)
def _handle_all_merchants(self, date_obj, sync_mode: bool):
"""处理所有商户的日结"""
from settlement.tasks import run_daily_settlement
configs = DailySettlementConfig.objects.filter(
settlement_modules__len__gt=0
).select_related('merchant')
if not configs.exists():
self.stdout.write('没有配置日结的商户,跳过')
return
self.stdout.write(
f'{configs.count()} 个商户需要执行日结'
)
if sync_mode:
# 同步执行(逐个商户)
for config in configs:
self._handle_single_merchant(
merchant_id=config.merchant.id,
date_obj=date_obj,
sync_mode=True
)
else:
# 异步执行(通过 Celery
task = run_daily_settlement.delay()
self.stdout.write(
f'所有商户日结任务已提交: task_id={task.id}'
)