forked from erp-dev/erp
feat: new module for daily settlement
This commit is contained in:
1
settlement/management/commands/__init__.py
Normal file
1
settlement/management/commands/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""Settlement management commands"""
|
||||
151
settlement/management/commands/run_daily_settlement.py
Normal file
151
settlement/management/commands/run_daily_settlement.py
Normal file
@@ -0,0 +1,151 @@
|
||||
"""
|
||||
手动触发日结任务(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}'
|
||||
)
|
||||
Reference in New Issue
Block a user