feat: 管事分佣明细v2与打手本人入账额展示
This commit is contained in:
1 parent
b49da23bd7
commit
712d497672
4 files changed
+185
-3
No files matched your search
+68
-1
@@ -797,6 +797,11 @@ class DashouDingdanHuoquView1(APIView):
|
||||
if wants_auto_settle_pending(data):
|
||||
query &= Q(Status=8, AutoSettleEligible=True, AutoExpireAt__isnull=False)
|
||||
|
||||
# 佣金记录页:with_my_share=1 时追加本人入账额(不改 jine 语义)
|
||||
with_my_share = str(data.get('with_my_share') or '').strip().lower() in (
|
||||
'1', 'true', 'yes', 'y',
|
||||
)
|
||||
|
||||
# 5. 执行查询,按创建时间倒序
|
||||
dingdan_query = Order.query.filter(query).order_by('-CreateTime')
|
||||
|
||||
@@ -826,12 +831,18 @@ class DashouDingdanHuoquView1(APIView):
|
||||
from orders.services.team_recruit import batch_team_list_flags
|
||||
page_oids = [o.OrderID for o in current_page_orders]
|
||||
team_flags = batch_team_list_flags(page_oids, viewer_uid=yonghuid)
|
||||
|
||||
settle_map = {}
|
||||
if with_my_share and page_oids:
|
||||
settle_map = self._batch_my_settle_amounts(page_oids, yonghuid)
|
||||
|
||||
order_list = []
|
||||
for order in current_page_orders:
|
||||
full_amt = float(order.PlayerCommission) if order.PlayerCommission else 0.0
|
||||
order_data = {
|
||||
'dingdan_id': order.OrderID,
|
||||
'zhuangtai': order.Status,
|
||||
'jine': float(order.PlayerCommission) if order.PlayerCommission else 0.0,
|
||||
'jine': full_amt,
|
||||
'jieshao': order.Description or '',
|
||||
'tupian': order.ImageURL or '',
|
||||
'nicheng': order.Nickname or '',
|
||||
@@ -840,6 +851,15 @@ class DashouDingdanHuoquView1(APIView):
|
||||
order_data.update(order_auto_settle_payload(order))
|
||||
tf = team_flags.get(order.OrderID) or {'has_team': False}
|
||||
order_data.update(tf)
|
||||
if with_my_share:
|
||||
is_team = bool(tf.get('has_team'))
|
||||
my_amt = settle_map.get(order.OrderID)
|
||||
if my_amt is None:
|
||||
my_amt = full_amt
|
||||
order_data['my_settle_amount'] = float(my_amt)
|
||||
order_data['is_team'] = is_team
|
||||
if 'team_role' not in order_data:
|
||||
order_data['team_role'] = tf.get('team_role') or ''
|
||||
order_list.append(order_data)
|
||||
|
||||
# 8. 判断是否还有更多数据
|
||||
@@ -878,6 +898,53 @@ class DashouDingdanHuoquView1(APIView):
|
||||
'data': None
|
||||
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
@staticmethod
|
||||
def _batch_my_settle_amounts(order_ids, user_uid):
|
||||
"""
|
||||
本人实际入账额:优先 team_settle_ledger;否则 TeamMember.share_amount;
|
||||
都没有则由调用方回落 PlayerCommission。
|
||||
返回 {order_id: float}
|
||||
"""
|
||||
from decimal import Decimal
|
||||
from orders.models import TeamSettleLedger, TeamRecruit, TeamMember
|
||||
|
||||
oids = [str(x) for x in (order_ids or []) if x]
|
||||
uid = (user_uid or '').strip()
|
||||
if not oids or not uid:
|
||||
return {}
|
||||
|
||||
out = {}
|
||||
try:
|
||||
for row in TeamSettleLedger.query.filter(order_id__in=oids, user_uid=uid):
|
||||
oid = row.order_id
|
||||
amt = Decimal(str(row.amount or 0))
|
||||
out[oid] = float(out.get(oid, 0) + float(amt))
|
||||
except Exception as e:
|
||||
logger.warning('batch settle ledger 失败: %s', e)
|
||||
|
||||
missing = [oid for oid in oids if oid not in out]
|
||||
if not missing:
|
||||
return out
|
||||
|
||||
try:
|
||||
recs = list(TeamRecruit.query.filter(order_id__in=missing).order_by('-id'))
|
||||
best = {}
|
||||
for r in recs:
|
||||
if r.order_id not in best:
|
||||
best[r.order_id] = r
|
||||
if best:
|
||||
rid_to_oid = {r.id: oid for oid, r in best.items()}
|
||||
for m in TeamMember.query.filter(
|
||||
recruit_id__in=list(rid_to_oid.keys()),
|
||||
user_uid=uid,
|
||||
join_status=TeamMember.JOIN_ACTIVE,
|
||||
):
|
||||
oid = rid_to_oid.get(m.recruit_id)
|
||||
if oid and oid not in out:
|
||||
out[oid] = float(Decimal(str(m.share_amount or 0)))
|
||||
except Exception as e:
|
||||
logger.warning('batch member share 失败: %s', e)
|
||||
return out
|
||||
|
||||
|
||||
class DashouCOSZhengshuView(APIView):
|
||||
|
||||
+2
-1
@@ -4,7 +4,7 @@ from django.views.decorators.csrf import csrf_exempt
|
||||
from .views import ShangpinHuoquView, ShangpinXiangqingHuoquView, DashouHuiyuanList, \
|
||||
YajinGoumai, YajinHuitiao, YajinShibai, YajinLunxun, JifenBuchong, JifenHuitiao, JifenShibai, \
|
||||
JifenLunxun, HuiyuanGoumai, HuiyuanHuitiao, HuiyuanShibai, HuiyuanLunxun, ShangjiaChenggong, \
|
||||
ShangjiaChongzhi, ShangjiaHuitiao, ShangjiaShibai, GuanshiFenhongListAPI, AdGetAllDataView, ShangpinLeixingFabuView, \
|
||||
ShangjiaChongzhi, ShangjiaHuitiao, ShangjiaShibai, GuanshiFenhongListAPI, GuanshiFenhongListV2API, AdGetAllDataView, ShangpinLeixingFabuView, \
|
||||
ShangpinZhuanquFabuView, ShangpinFabuView, GuizeTupianShangchuanView, AdHuiyuanHqView, HuiyuanXiugaiView, \
|
||||
AdHuiyuanFbView, AdShangpinHuQu, AdLeixingXiuGai, AdLunboXiuGai, AdZhuanquXiuGai, AdGonggaoXiuGai, \
|
||||
AdShangpinGuizeXiuGai, AdShangpinXiuGai, AdShangpinNeiRongHuoQu, \
|
||||
@@ -56,6 +56,7 @@ urlpatterns = [
|
||||
path('sjshibai', ShangjiaShibai.as_view(), name='商家支付失败'), # 商家支付失败处理
|
||||
path('sjcg', ShangjiaChenggong.as_view(), name='商家支付成功'), # 商家支付成功轮询
|
||||
path('fenhonghq', GuanshiFenhongListAPI.as_view(), name='管事获取打手充值记录'),
|
||||
path('guanshi-fenhong-v2', GuanshiFenhongListV2API.as_view(), name='管事分红明细v2'),
|
||||
path('adhqlx', AdGetAllDataView.as_view(), name='管理员获取商品类型会员类型专区类型'),
|
||||
path('leixingfabu', ShangpinLeixingFabuView.as_view(), name='添加商品类型'),
|
||||
# 商品专区相关接口
|
||||
|
||||
@@ -21,6 +21,7 @@ from .product_query import (
|
||||
ShangpinXiangqingHuoquView,
|
||||
DashouHuiyuanList,
|
||||
GuanshiFenhongListAPI,
|
||||
GuanshiFenhongListV2API,
|
||||
AdGetAllDataView,
|
||||
HuiyuanTypeListView,
|
||||
HuiyuanRecordListView,
|
||||
@@ -97,7 +98,7 @@ logger = logging.getLogger(__name__)
|
||||
__all__ = [
|
||||
# product_query
|
||||
'ShangpinHuoquView', 'ShangpinXiangqingHuoquView', 'DashouHuiyuanList',
|
||||
'GuanshiFenhongListAPI', 'AdGetAllDataView',
|
||||
'GuanshiFenhongListAPI', 'GuanshiFenhongListV2API', 'AdGetAllDataView',
|
||||
'HuiyuanTypeListView', 'HuiyuanRecordListView', 'ZuzhangFenhongView',
|
||||
# yajin_payment
|
||||
'YajinGoumai', 'YajinHuitiao', 'YajinShibai', 'YajinLunxun',
|
||||
|
||||
@@ -457,6 +457,119 @@ class GuanshiFenhongListAPI(APIView):
|
||||
})
|
||||
|
||||
|
||||
FENHONG_LEIXING_LABELS = {
|
||||
1: '会员分红',
|
||||
2: '押金分红',
|
||||
3: '订单分佣',
|
||||
}
|
||||
|
||||
|
||||
class GuanshiFenhongListV2API(APIView):
|
||||
"""
|
||||
管事分红明细 v2(旧 fenhonghq 不动)。
|
||||
POST /shangpin/guanshi-fenhong-v2
|
||||
- 列表带类型/说明/订单号/双时间字段
|
||||
- 可选 fenhong_leixing 筛选;分项统计始终按管事全量汇总
|
||||
"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
try:
|
||||
from django.db.models import Sum, Count
|
||||
|
||||
yonghuid = request.user.UserUID
|
||||
page = int(request.data.get('page', 1) or 1)
|
||||
page_size = int(request.data.get('page_size', 50) or 50)
|
||||
if page < 1:
|
||||
page = 1
|
||||
if page_size < 1 or page_size > 100:
|
||||
page_size = 50
|
||||
|
||||
leixing_raw = request.data.get('fenhong_leixing', None)
|
||||
leixing_filter = None
|
||||
if leixing_raw is not None and str(leixing_raw).strip() != '':
|
||||
try:
|
||||
leixing_filter = int(leixing_raw)
|
||||
except (TypeError, ValueError):
|
||||
return Response({'code': 400, 'msg': 'fenhong_leixing 无效', 'data': {}})
|
||||
if leixing_filter not in FENHONG_LEIXING_LABELS:
|
||||
return Response({'code': 400, 'msg': 'fenhong_leixing 无效', 'data': {}})
|
||||
|
||||
base_qs = Gsfenhong.objects.filter(guanshi=yonghuid)
|
||||
|
||||
# 分项统计:始终全量(不被列表筛选缩小)
|
||||
amount_by = {'1': '0.00', '2': '0.00', '3': '0.00'}
|
||||
count_by = {'1': 0, '2': 0, '3': 0}
|
||||
total_amount = Decimal('0.00')
|
||||
for row in base_qs.values('fenhong_leixing').annotate(
|
||||
amount=Sum('fenhong'), cnt=Count('id'),
|
||||
):
|
||||
key = str(int(row.get('fenhong_leixing') or 1))
|
||||
amt = Decimal(str(row.get('amount') or 0)).quantize(Decimal('0.01'))
|
||||
cnt = int(row.get('cnt') or 0)
|
||||
if key in amount_by:
|
||||
amount_by[key] = str(amt)
|
||||
count_by[key] = cnt
|
||||
total_amount += amt
|
||||
|
||||
list_qs = base_qs
|
||||
if leixing_filter is not None:
|
||||
list_qs = list_qs.filter(fenhong_leixing=leixing_filter)
|
||||
|
||||
zong_tiaoshu = list_qs.count()
|
||||
chongzhi_dashou_shuliang = base_qs.values('dashouid').distinct().count()
|
||||
offset = (page - 1) * page_size
|
||||
rows = list(
|
||||
list_qs.order_by('-CreateTime')
|
||||
.values(
|
||||
'dingdan_id', 'dashouid', 'avatar', 'nicheng', 'fenhong',
|
||||
'shuoming', 'fenhong_leixing', 'CreateTime',
|
||||
)[offset:offset + page_size]
|
||||
)
|
||||
|
||||
formatted_list = []
|
||||
for item in rows:
|
||||
leixing = int(item.get('fenhong_leixing') or 1)
|
||||
ts = ''
|
||||
if item.get('CreateTime'):
|
||||
ts = item['CreateTime'].strftime('%Y-%m-%d %H:%M:%S')
|
||||
formatted_list.append({
|
||||
'yonghuid': item.get('dashouid') or '',
|
||||
'avatar': item.get('avatar') or '',
|
||||
'nicheng': item.get('nicheng') or '未知用户',
|
||||
'fenhong': str(item.get('fenhong') or '0'),
|
||||
'CreateTime': ts,
|
||||
'create_time': ts,
|
||||
'fenhong_leixing': leixing,
|
||||
'leixing_label': FENHONG_LEIXING_LABELS.get(leixing, '分红'),
|
||||
'shuoming': (item.get('shuoming') or '').strip(),
|
||||
'dingdan_id': item.get('dingdan_id') or '',
|
||||
})
|
||||
|
||||
return Response({
|
||||
'code': 200,
|
||||
'msg': '成功',
|
||||
'data': {
|
||||
'list': formatted_list,
|
||||
'total': zong_tiaoshu,
|
||||
'chongzhi_dashou_shuliang': chongzhi_dashou_shuliang,
|
||||
'page': page,
|
||||
'page_size': page_size,
|
||||
'has_more': len(formatted_list) == page_size,
|
||||
'total_amount': str(total_amount.quantize(Decimal('0.01'))),
|
||||
'amount_by_leixing': amount_by,
|
||||
'count_by_leixing': count_by,
|
||||
},
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error('查询管事分红记录 v2 失败: %s', e, exc_info=True)
|
||||
return Response({
|
||||
'code': 500,
|
||||
'msg': f'服务器错误: {str(e)}',
|
||||
'data': {},
|
||||
})
|
||||
|
||||
|
||||
# views.py - 商品模块视图
|
||||
class AdGetAllDataView(APIView):
|
||||
"""
|
||||
|
||||
Reference in new issue
Block a user