forked from erp-dev/erp
269 lines
7.0 KiB
Python
269 lines
7.0 KiB
Python
"""日结模块统计服务函数"""
|
|
import logging
|
|
from datetime import datetime, date
|
|
|
|
from django.db.models import Q, Sum, Case, When, Value, CharField, IntegerField
|
|
from django.db.models.functions import Concat
|
|
|
|
from printing.models import PlateOrder
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def get_plate_order_summary_by_customer(
|
|
merchant_id: int,
|
|
settlement_date: date,
|
|
user=None
|
|
) -> list[dict]:
|
|
"""
|
|
获取按客户分组的开版订单统计
|
|
|
|
Args:
|
|
merchant_id: 商户ID
|
|
settlement_date: 统计日期
|
|
user: 当前用户(用于客户可见性过滤)
|
|
|
|
Returns:
|
|
list[dict]: 客户统计列表
|
|
"""
|
|
logger.info(
|
|
f'[settlement.services] 获取开版订单统计: '
|
|
f'merchant_id={merchant_id}, date={settlement_date}'
|
|
)
|
|
|
|
settlement_date = _validate_and_normalize_summary_args(
|
|
merchant_id=merchant_id,
|
|
settlement_date=settlement_date,
|
|
)
|
|
|
|
queryset = _get_plate_order_queryset(merchant_id, user)
|
|
aggregated_data = _aggregate_plate_orders_by_customer_and_type(
|
|
queryset, settlement_date
|
|
)
|
|
return _format_plate_order_summary(aggregated_data)
|
|
|
|
|
|
def _validate_and_normalize_summary_args(
|
|
merchant_id: int,
|
|
settlement_date: date,
|
|
) -> date:
|
|
"""校验并标准化统计参数。"""
|
|
if not isinstance(merchant_id, int) or merchant_id <= 0:
|
|
raise ValueError('merchant_id 必须为正整数')
|
|
|
|
if isinstance(settlement_date, datetime):
|
|
settlement_date = settlement_date.date()
|
|
|
|
if not isinstance(settlement_date, date):
|
|
raise ValueError('settlement_date 必须为 date 或 datetime 类型')
|
|
|
|
return settlement_date
|
|
|
|
|
|
def _get_plate_order_queryset(merchant_id: int, user=None):
|
|
"""
|
|
获取开版订单的基础查询集
|
|
|
|
Args:
|
|
merchant_id: 商户ID
|
|
user: 当前用户(用于客户可见性过滤)
|
|
|
|
Returns:
|
|
QuerySet[PlateOrder]: 过滤后的查询集
|
|
"""
|
|
queryset = PlateOrder.objects.filter(
|
|
merchant_id=merchant_id,
|
|
plate_type__isnull=False,
|
|
production_method__isnull=False
|
|
).select_related('customer')
|
|
|
|
if user and not user.is_superuser:
|
|
emp = getattr(user, 'employee', None)
|
|
if emp:
|
|
visible_customer_filter = (
|
|
Q(customer__created_by=emp) |
|
|
Q(customer__visible_employees=emp)
|
|
)
|
|
no_customer_filter = Q(customer__isnull=True)
|
|
queryset = queryset.filter(
|
|
visible_customer_filter | no_customer_filter
|
|
).distinct()
|
|
|
|
return queryset
|
|
|
|
|
|
def _get_month_date_range(settlement_date: date) -> tuple[date, date]:
|
|
"""
|
|
获取从月初到指定日期的日期范围
|
|
|
|
Args:
|
|
settlement_date: 统计日期
|
|
|
|
Returns:
|
|
tuple[date, date]: (月初日期, 统计日期)
|
|
"""
|
|
month_start = settlement_date.replace(day=1)
|
|
return month_start, settlement_date
|
|
|
|
|
|
def _aggregate_plate_orders_by_customer_and_type(queryset, settlement_date: date):
|
|
"""
|
|
按客户和类型分组聚合订单数据
|
|
|
|
Args:
|
|
queryset: 基础查询集
|
|
settlement_date: 统计日期
|
|
|
|
Returns:
|
|
QuerySet[PlateOrder]: 添加了聚合标注的查询集
|
|
"""
|
|
month_start, _ = _get_month_date_range(settlement_date)
|
|
|
|
queryset = queryset.annotate(
|
|
type=Concat(
|
|
'plate_type',
|
|
Value('-'),
|
|
'production_method',
|
|
output_field=CharField()
|
|
)
|
|
).values(
|
|
'customer__id',
|
|
'customer__name',
|
|
'type'
|
|
).annotate(
|
|
today=Sum(
|
|
Case(
|
|
When(
|
|
plate_date__date=settlement_date,
|
|
then=1
|
|
),
|
|
default=0,
|
|
output_field=IntegerField()
|
|
)
|
|
),
|
|
current_month=Sum(
|
|
Case(
|
|
When(
|
|
plate_date__date__gte=month_start,
|
|
plate_date__date__lte=settlement_date,
|
|
then=1
|
|
),
|
|
default=0,
|
|
output_field=IntegerField()
|
|
)
|
|
)
|
|
).order_by('customer__name', 'customer__id', 'type')
|
|
|
|
return queryset
|
|
|
|
|
|
def _format_plate_order_summary(aggregated_data):
|
|
"""
|
|
格式化聚合结果为 API 返回格式
|
|
|
|
Args:
|
|
aggregated_data: 聚合后的查询集
|
|
|
|
Returns:
|
|
list[dict]: 格式化后的数据
|
|
"""
|
|
result = {}
|
|
|
|
for item in aggregated_data:
|
|
client_id = item['customer__id']
|
|
client_name = item['customer__name']
|
|
client_key = (client_id, client_name)
|
|
if client_key not in result:
|
|
result[client_key] = {
|
|
'client_id': client_id,
|
|
'client_name': client_name,
|
|
'plate_order_count': []
|
|
}
|
|
|
|
plate_order_count = {
|
|
'type': item['type'],
|
|
'today': item['today'],
|
|
'current_month': item['current_month']
|
|
}
|
|
|
|
result[client_key]['plate_order_count'].append(plate_order_count)
|
|
|
|
for client_key in result:
|
|
result[client_key]['plate_order_count'] = _filter_zero_data(
|
|
result[client_key]['plate_order_count']
|
|
)
|
|
|
|
return [v for k, v in result.items() if v['plate_order_count']]
|
|
|
|
|
|
def _filter_zero_data(plate_order_counts):
|
|
"""
|
|
过滤全0数据
|
|
|
|
Args:
|
|
plate_order_counts: 订单统计列表
|
|
|
|
Returns:
|
|
list[dict]: 过滤后的列表
|
|
"""
|
|
return [
|
|
item for item in plate_order_counts
|
|
if item['today'] > 0 or item['current_month'] > 0
|
|
]
|
|
|
|
|
|
def calculate_plate_order_daily_summary(
|
|
merchant_id: int,
|
|
settlement_date: datetime.date
|
|
) -> dict:
|
|
"""
|
|
计算开版订单日结汇总(空壳实现)
|
|
|
|
Args:
|
|
merchant_id: 商户ID
|
|
settlement_date: 结算日期
|
|
|
|
Returns:
|
|
dict: 统计结果(空壳)
|
|
"""
|
|
logger.info(
|
|
f'[settlement.services] 计算开版订单日结汇总: '
|
|
f'merchant_id={merchant_id}, date={settlement_date}'
|
|
)
|
|
|
|
return {
|
|
'merchant_id': merchant_id,
|
|
'settlement_date': str(settlement_date),
|
|
'total_orders': 0,
|
|
'completed_orders': 0,
|
|
'in_progress_orders': 0,
|
|
}
|
|
|
|
|
|
def calculate_printing_order_daily_summary(
|
|
merchant_id: int,
|
|
settlement_date: datetime.date
|
|
) -> dict:
|
|
"""
|
|
计算生产订单日结汇总(空壳实现)
|
|
|
|
Args:
|
|
merchant_id: 商户ID
|
|
settlement_date: 结算日期
|
|
|
|
Returns:
|
|
dict: 统计结果(空壳)
|
|
"""
|
|
logger.info(
|
|
f'[settlement.services] 计算生产订单日结汇总: '
|
|
f'merchant_id={merchant_id}, date={settlement_date}'
|
|
)
|
|
|
|
return {
|
|
'merchant_id': merchant_id,
|
|
'settlement_date': str(settlement_date),
|
|
'total_orders': 0,
|
|
'completed_orders': 0,
|
|
'in_progress_orders': 0,
|
|
}
|