forked from erp-dev/erp
feat: settlement first api beta
This commit is contained in:
@@ -1,10 +1,217 @@
|
||||
"""日结模块统计服务函数"""
|
||||
import logging
|
||||
from datetime import datetime
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user