第一次提交:阿龙电竞 Django 后端最新版本

This commit is contained in:
XingQue
2026-06-14 02:23:24 +08:00
commit 4f7bf00224
9654 changed files with 5417000 additions and 0 deletions

0
dingdan/__init__.py Normal file
View File

3
dingdan/admin.py Normal file
View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

10
dingdan/apps.py Normal file
View File

@@ -0,0 +1,10 @@
from django.apps import AppConfig
class DingdanConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'dingdan'
def ready(self):
# 导入信号处理,确保信号被注册
import dingdan.signals

View File

@@ -0,0 +1,39 @@
# dingdan/cross_platform_tasks.py
import logging
import requests
from django.conf import settings
logger = logging.getLogger(__name__)
def send_partner_sync_order(partner_order_id, jine, dashou_fencheng, jieshao, beizhu, create_time,nicheng):
"""
异步发送派单通知给对方平台使用简单线程非Celery
注意:此函数应在线程中调用,避免阻塞主请求。
生产环境建议使用Celery此处提供线程兼容版本。
"""
url = f"{settings.PARTNER_BASE_URL}/dingdan/partner_sync_order"
payload = {
'token': settings.CROSS_PLATFORM_TOKEN,
'partner_order_id': partner_order_id,
'jine': jine,
'dashou_fencheng': dashou_fencheng,
'jieshao': jieshao,
'beizhu': beizhu,
'create_time': create_time,
'nicheng':nicheng
}
try:
response = requests.post(url, json=payload, timeout=5)
if response.status_code == 200:
data = response.json()
if data.get('code') == 0:
logger.info(f"跨平台派单同步成功: {partner_order_id}")
# 可在此处保存对方返回的 local_order_id 到本地订单(如果需要)
# local_order_id = data['data'].get('local_order_id')
# Dingdan.objects.filter(dingdan_id=partner_order_id).update(partner_order_id=local_order_id)
else:
logger.error(f"跨平台派单同步业务失败: {data}")
else:
logger.error(f"跨平台派单同步HTTP失败: {response.status_code}")
except Exception as e:
logger.error(f"跨平台派单同步异常: {str(e)}", exc_info=True)

View File

@@ -0,0 +1,844 @@
# Generated by Django 4.2.27 on 2026-01-23 19:32
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="Chufajilu",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"dashouid",
models.CharField(
db_index=True,
max_length=7,
null=True,
verbose_name="被罚打手ID",
),
),
(
"qingqiuid",
models.CharField(
db_index=True,
max_length=7,
null=True,
verbose_name="请求处罚ID",
),
),
(
"chuliid",
models.CharField(
db_index=True,
max_length=11,
null=True,
verbose_name="处理处罚ID",
),
),
(
"cfliyou",
models.TextField(blank=True, null=True, verbose_name="处罚理由"),
),
(
"sqzhuangtai",
models.IntegerField(
blank=True,
default=0,
null=True,
verbose_name="处罚申请状态:0待处理,1成功,2驳回",
),
),
(
"bhliyou",
models.TextField(
blank=True, null=True, verbose_name="驳回处罚理由"
),
),
("jifen", models.IntegerField(default=0, verbose_name="扣除打手积分")),
(
"dingdan_id",
models.CharField(
db_index=True, max_length=32, null=True, verbose_name="订单ID"
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"db_table": "chufajilu",
},
),
migrations.CreateModel(
name="Dashoutupian",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"dingdan_id",
models.CharField(
db_index=True, max_length=32, null=True, verbose_name="订单ID"
),
),
(
"dashou",
models.CharField(
blank=True,
db_index=True,
max_length=32,
null=True,
verbose_name="接单打手ID",
),
),
(
"tupian",
models.CharField(
blank=True,
max_length=500,
null=True,
verbose_name="打手提交图片URL",
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"db_table": "dashoutupian",
},
),
migrations.CreateModel(
name="Dingdan",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"dingdan_id",
models.CharField(
db_index=True, max_length=32, unique=True, verbose_name="订单ID"
),
),
(
"zhuangtai",
models.IntegerField(
blank=True,
db_index=True,
default=1,
null=True,
verbose_name="订单状态",
),
),
(
"fadan_pingtai",
models.IntegerField(blank=True, null=True, verbose_name="发单平台"),
),
(
"jine",
models.DecimalField(
blank=True,
decimal_places=2,
max_digits=10,
null=True,
verbose_name="订单金额",
),
),
(
"dashou_fencheng",
models.DecimalField(
blank=True,
decimal_places=2,
max_digits=10,
null=True,
verbose_name="打手分成",
),
),
(
"jiedan_dashou_id",
models.CharField(
blank=True,
db_index=True,
max_length=32,
null=True,
verbose_name="接单打手ID",
),
),
(
"dashou_liuyan",
models.TextField(blank=True, null=True, verbose_name="打手留言"),
),
(
"zhiding_id",
models.CharField(
blank=True, max_length=32, null=True, verbose_name="指定ID"
),
),
(
"shangpin_id",
models.IntegerField(blank=True, null=True, verbose_name="商品ID"),
),
(
"leixing_id",
models.PositiveIntegerField(
blank=True, null=True, verbose_name="商品类型ID"
),
),
(
"tupian",
models.CharField(
blank=True,
max_length=500,
null=True,
verbose_name="商品图片URL",
),
),
(
"yaoqiuleixing",
models.PositiveIntegerField(
blank=True, null=True, verbose_name="抢单要求类型"
),
),
(
"huiyuan_id",
models.CharField(
blank=True, max_length=6, null=True, verbose_name="会员ID"
),
),
(
"yongjin",
models.DecimalField(
blank=True,
decimal_places=2,
max_digits=10,
null=True,
verbose_name="佣金要求",
),
),
(
"jieshao",
models.TextField(blank=True, null=True, verbose_name="订单介绍"),
),
(
"beizhu",
models.TextField(blank=True, null=True, verbose_name="订单备注"),
),
(
"nicheng",
models.CharField(
blank=True, max_length=50, null=True, verbose_name="游戏昵称"
),
),
(
"user1_id",
models.CharField(
db_index=True,
max_length=30,
null=True,
verbose_name="用户1标识",
),
),
(
"user2_id",
models.CharField(
db_index=True,
max_length=30,
null=True,
verbose_name="用户2打手标识",
),
),
(
"auto_task_id",
models.CharField(
blank=True,
default="",
max_length=255,
verbose_name="延时任务ID",
),
),
(
"auto_expire_at",
models.DateTimeField(
blank=True, null=True, verbose_name="计划过期时间"
),
),
(
"pending_dispatch",
models.BooleanField(
db_index=True, default=False, verbose_name="待调度标记"
),
),
(
"status_8_time",
models.DateTimeField(
blank=True, null=True, verbose_name="状态变为8的时间"
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"verbose_name": "订单",
"verbose_name_plural": "订单",
"db_table": "dingdan",
},
),
migrations.CreateModel(
name="Lilubiao",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"lilu",
models.DecimalField(
decimal_places=4,
max_digits=5,
null=True,
verbose_name="平台分成利率1是平台,2是商家",
),
),
(
"fadanpingtai",
models.CharField(
max_length=10,
null=True,
verbose_name="订单所属平台,(商家或平台)",
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"db_table": "lilubiao",
},
),
migrations.CreateModel(
name="Ptliushui",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"zonge",
models.DecimalField(
blank=True,
decimal_places=2,
max_digits=10,
null=True,
verbose_name="收取总金额",
),
),
(
"zhichuzonge",
models.DecimalField(
blank=True,
decimal_places=2,
max_digits=10,
null=True,
verbose_name="支出总金额",
),
),
(
"zongshouyi",
models.DecimalField(
blank=True,
decimal_places=2,
max_digits=10,
null=True,
verbose_name="总收益",
),
),
(
"rizonge",
models.DecimalField(
blank=True,
decimal_places=2,
max_digits=10,
null=True,
verbose_name="日收取",
),
),
(
"rizhichu",
models.DecimalField(
blank=True,
decimal_places=2,
max_digits=10,
null=True,
verbose_name="日支出",
),
),
(
"rishouyi",
models.DecimalField(
blank=True,
decimal_places=2,
max_digits=10,
null=True,
verbose_name="日收益",
),
),
(
"zongshoucishu",
models.IntegerField(default=0, verbose_name="总收取次数"),
),
(
"rishoucishu",
models.IntegerField(default=0, verbose_name="日收取次数"),
),
(
"zongzhichucishu",
models.IntegerField(default=0, verbose_name="总支出次数"),
),
(
"rizhichucishu",
models.IntegerField(default=0, verbose_name="日支出次数"),
),
],
options={
"db_table": "ptliushui",
},
),
migrations.CreateModel(
name="Tuikuanjilu",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"dingdan_id",
models.CharField(max_length=32, unique=True, verbose_name="订单ID"),
),
(
"dashouid",
models.CharField(
max_length=7, null=True, verbose_name="接单打手ID"
),
),
(
"qingqiuid",
models.CharField(
max_length=7, null=True, verbose_name="请求用户ID"
),
),
(
"chuliid",
models.CharField(
db_index=True, max_length=7, null=True, verbose_name="处理人ID"
),
),
("liyou", models.TextField(blank=True, null=True, verbose_name="理由")),
(
"sqzhuangtai",
models.IntegerField(
blank=True,
db_index=True,
default=0,
null=True,
verbose_name="申请状态:0待处理,1成功,2驳回",
),
),
(
"bhliyou",
models.TextField(blank=True, null=True, verbose_name="驳回理由"),
),
(
"jine",
models.DecimalField(
blank=True,
decimal_places=2,
max_digits=10,
null=True,
verbose_name="订单金额",
),
),
(
"dashou_fencheng",
models.DecimalField(
blank=True,
decimal_places=2,
max_digits=10,
null=True,
verbose_name="打手分成",
),
),
(
"jieshao",
models.TextField(blank=True, null=True, verbose_name="订单介绍"),
),
(
"beizhu",
models.TextField(blank=True, null=True, verbose_name="订单备注"),
),
(
"nicheng",
models.CharField(
blank=True, max_length=50, null=True, verbose_name="游戏昵称"
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"db_table": "tuikuanjilu",
"indexes": [
models.Index(
fields=["chuliid"], name="tuikuanjilu_chuliid_0b0f16_idx"
),
models.Index(
fields=["sqzhuangtai"], name="tuikuanjilu_sqzhuan_d89dc9_idx"
),
],
},
),
migrations.CreateModel(
name="Pingfen",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"dashou",
models.CharField(
blank=True,
db_index=True,
max_length=32,
null=True,
verbose_name="接单打手ID",
),
),
(
"zongfen",
models.PositiveIntegerField(default=0, verbose_name="总分"),
),
(
"cishu",
models.PositiveIntegerField(default=0, verbose_name="评分次数"),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"verbose_name": "评分表",
"db_table": "pingfenbiao",
"indexes": [
models.Index(
fields=["dashou"], name="pingfenbiao_dashou_f62f10_idx"
)
],
},
),
migrations.CreateModel(
name="Liaotian",
fields=[
(
"id",
models.BigAutoField(
primary_key=True, serialize=False, verbose_name="主键ID"
),
),
(
"user1_id",
models.CharField(
db_index=True, max_length=30, verbose_name="用户1标识"
),
),
(
"user2_id",
models.CharField(
db_index=True, max_length=30, verbose_name="用户2标识"
),
),
(
"dingdan_id",
models.CharField(max_length=32, unique=True, verbose_name="订单ID"),
),
(
"zhuangtai",
models.IntegerField(
choices=[(1, "开启中"), (0, "已关闭")],
db_index=True,
default=1,
verbose_name="聊天状态",
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"db_table": "liaotian",
"indexes": [
models.Index(
fields=["user1_id"], name="liaotian_user1_i_6be6cd_idx"
),
models.Index(
fields=["user2_id"], name="liaotian_user2_i_9f61a4_idx"
),
models.Index(
fields=["zhuangtai"], name="liaotian_zhuangt_5e8be5_idx"
),
],
},
),
migrations.CreateModel(
name="DingdanShangjia",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"shangjia_id",
models.CharField(
blank=True,
db_index=True,
max_length=32,
null=True,
verbose_name="商家ID",
),
),
(
"shangjia_pingjia",
models.TextField(blank=True, null=True, verbose_name="商家评价"),
),
(
"cfliyou",
models.TextField(
blank=True, null=True, verbose_name="商家处罚理由"
),
),
(
"sqzhuangtai",
models.IntegerField(
blank=True,
default=0,
null=True,
verbose_name="处罚申请状态:0待处理,1成功,2驳回",
),
),
(
"bhliyou",
models.TextField(
blank=True, null=True, verbose_name="驳回商家处罚理由"
),
),
(
"sjnicheng",
models.CharField(max_length=50, null=True, verbose_name="商家昵称"),
),
(
"dingdan",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="shangjia_kuozhan",
to="dingdan.dingdan",
verbose_name="订单",
),
),
],
options={
"verbose_name": "商家订单扩展",
"verbose_name_plural": "商家订单扩展",
"db_table": "dingdan_shangjia",
},
),
migrations.CreateModel(
name="DingdanPingtai",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"laoban_id",
models.CharField(
blank=True,
db_index=True,
max_length=32,
null=True,
verbose_name="老板ID",
),
),
(
"laoban_pingjia",
models.TextField(blank=True, null=True, verbose_name="老板评价"),
),
(
"dingdan",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="pingtai_kuozhan",
to="dingdan.dingdan",
verbose_name="订单",
),
),
],
options={
"verbose_name": "平台订单扩展",
"verbose_name_plural": "平台订单扩展",
"db_table": "dingdan_pingtai",
},
),
migrations.AddIndex(
model_name="dingdan",
index=models.Index(fields=["zhuangtai"], name="dingdan_zhuangt_2febe8_idx"),
),
migrations.AddIndex(
model_name="dingdan",
index=models.Index(
fields=["dingdan_id"], name="dingdan_dingdan_83dcb6_idx"
),
),
migrations.AddIndex(
model_name="dingdan",
index=models.Index(
fields=["jiedan_dashou_id"], name="dingdan_jiedan__921bfa_idx"
),
),
migrations.AddIndex(
model_name="dashoutupian",
index=models.Index(fields=["dashou"], name="dashoutupia_dashou_7de8bd_idx"),
),
migrations.AddIndex(
model_name="dashoutupian",
index=models.Index(
fields=["dingdan_id"], name="dashoutupia_dingdan_97c685_idx"
),
),
migrations.AddIndex(
model_name="chufajilu",
index=models.Index(
fields=["dashouid"], name="chufajilu_dashoui_07aac0_idx"
),
),
migrations.AddIndex(
model_name="chufajilu",
index=models.Index(
fields=["qingqiuid"], name="chufajilu_qingqiu_ac160e_idx"
),
),
migrations.AddIndex(
model_name="chufajilu",
index=models.Index(fields=["chuliid"], name="chufajilu_chuliid_cd63ac_idx"),
),
migrations.AddIndex(
model_name="chufajilu",
index=models.Index(
fields=["dingdan_id"], name="chufajilu_dingdan_b8f0c2_idx"
),
),
migrations.AddIndex(
model_name="dingdanshangjia",
index=models.Index(
fields=["shangjia_id"], name="dingdan_sha_shangji_64d28b_idx"
),
),
migrations.AddIndex(
model_name="dingdanpingtai",
index=models.Index(
fields=["laoban_id"], name="dingdan_pin_laoban__d55e6f_idx"
),
),
]

View File

@@ -0,0 +1,20 @@
# Generated by Django 4.2.27 on 2026-01-30 14:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0001_initial"),
]
operations = [
migrations.AlterField(
model_name="tuikuanjilu",
name="chuliid",
field=models.CharField(
db_index=True, max_length=11, null=True, verbose_name="处理人ID"
),
),
]

View File

@@ -0,0 +1,76 @@
# Generated by Django 4.2.27 on 2026-02-09 18:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0002_alter_tuikuanjilu_chuliid"),
]
operations = [
migrations.AddField(
model_name="chufajilu",
name="ssliyou",
field=models.TextField(blank=True, null=True, verbose_name="打手申诉理由"),
),
migrations.CreateModel(
name="Chufatupian",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"dingdan_id",
models.CharField(
db_index=True, max_length=32, null=True, verbose_name="订单ID"
),
),
(
"yonghuid",
models.CharField(
blank=True,
db_index=True,
max_length=32,
null=True,
verbose_name="用户ID",
),
),
(
"tupian",
models.CharField(
blank=True,
max_length=500,
null=True,
verbose_name="证据图片URL",
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"db_table": "chufatupian",
"indexes": [
models.Index(
fields=["yonghuid"], name="chufatupian_yonghui_71e585_idx"
),
models.Index(
fields=["dingdan_id"], name="chufatupian_dingdan_ce0dd4_idx"
),
],
},
),
]

View File

@@ -0,0 +1,20 @@
# Generated by Django 4.2.27 on 2026-02-13 23:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0003_chufajilu_ssliyou_chufatupian"),
]
operations = [
migrations.AddField(
model_name="dingdan",
name="tkly",
field=models.CharField(
blank=True, max_length=500, null=True, verbose_name="退款/拒绝理由"
),
),
]

View File

@@ -0,0 +1,31 @@
# Generated by Django 4.2.27 on 2026-02-14 19:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0004_dingdan_tkly"),
]
operations = [
migrations.AddField(
model_name="dingdan",
name="is_cross",
field=models.IntegerField(
default=0, verbose_name="是否跨平台订单(0否,1是)"
),
),
migrations.AddField(
model_name="dingdan",
name="partner_order_id",
field=models.CharField(
blank=True,
db_index=True,
max_length=32,
null=True,
verbose_name="对方平台订单ID",
),
),
]

View File

@@ -0,0 +1,27 @@
# Generated by Django 4.2.27 on 2026-02-22 01:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0005_dingdan_is_cross_dingdan_partner_order_id"),
]
operations = [
migrations.AddField(
model_name="dingdan",
name="clkf",
field=models.CharField(
db_index=True, max_length=20, null=True, verbose_name="处理客服"
),
),
migrations.AddField(
model_name="dingdanpingtai",
name="jjjs_biaoshi",
field=models.IntegerField(
default=0, verbose_name="拒绝结算标记(1表示拒绝结算)"
),
),
]

View File

@@ -0,0 +1,30 @@
# Generated by Django 4.2.27 on 2026-02-25 16:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0006_dingdan_clkf_dingdanpingtai_jjjs_biaoshi"),
]
operations = [
migrations.AddField(
model_name="dingdan",
name="wechat_transaction_id",
field=models.CharField(
blank=True,
db_index=True,
max_length=64,
null=True,
verbose_name="微信支付订单号",
),
),
migrations.AddIndex(
model_name="dingdan",
index=models.Index(
fields=["wechat_transaction_id"], name="dingdan_wechat__278b79_idx"
),
),
]

View File

@@ -0,0 +1,33 @@
# Generated by Django 4.2.27 on 2026-03-24 17:42
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0007_dingdan_wechat_transaction_id_and_more"),
]
operations = [
migrations.AddField(
model_name="dingdan",
name="dispatch_type",
field=models.IntegerField(
choices=[(1, "我方派单"), (2, "对方派单")],
default=0,
verbose_name="派发情况",
),
),
migrations.AddField(
model_name="dingdan",
name="partner_club_id",
field=models.CharField(
blank=True,
db_index=True,
max_length=6,
null=True,
verbose_name="对方俱乐部ID",
),
),
]

View File

@@ -0,0 +1,257 @@
# Generated by Django 4.2.27 on 2026-04-01 23:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0008_dingdan_dispatch_type_dingdan_partner_club_id"),
]
operations = [
migrations.CreateModel(
name="PreSettlement",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"dingdan_id",
models.CharField(
db_index=True,
max_length=32,
unique=True,
verbose_name="我方订单ID",
),
),
(
"partner_order_id",
models.CharField(
db_index=True, max_length=32, verbose_name="对方订单ID"
),
),
(
"partner_club_id",
models.CharField(
db_index=True, max_length=6, verbose_name="对方俱乐部ID"
),
),
(
"dashou_id",
models.CharField(
db_index=True, max_length=7, verbose_name="接单打手ID"
),
),
(
"amount",
models.DecimalField(
decimal_places=2, max_digits=10, verbose_name="打手应分金额"
),
),
(
"order_amount",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="订单原金额",
),
),
(
"status",
models.SmallIntegerField(
choices=[(0, "待结算"), (1, "已结算"), (2, "已拒绝")],
default=0,
verbose_name="结算状态",
),
),
(
"process_time",
models.DateTimeField(
blank=True, null=True, verbose_name="处理时间"
),
),
(
"operator",
models.CharField(
blank=True, default="", max_length=32, verbose_name="操作人"
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"verbose_name": "预结算表",
"verbose_name_plural": "预结算表",
"db_table": "pre_settlement",
"indexes": [
models.Index(
fields=["dingdan_id"], name="pre_settlem_dingdan_4f3541_idx"
),
models.Index(
fields=["partner_order_id"],
name="pre_settlem_partner_45b29e_idx",
),
models.Index(
fields=["partner_club_id"],
name="pre_settlem_partner_d2c44c_idx",
),
models.Index(
fields=["dashou_id"], name="pre_settlem_dashou__d5fe7c_idx"
),
models.Index(
fields=["status"], name="pre_settlem_status_0aa711_idx"
),
],
},
),
migrations.CreateModel(
name="OrderDashouHistory",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"dingdan_id",
models.CharField(
db_index=True, max_length=32, verbose_name="订单ID"
),
),
(
"dashou_id",
models.CharField(
db_index=True, max_length=7, verbose_name="打手ID"
),
),
(
"times",
models.PositiveSmallIntegerField(
verbose_name="第几次接单从1开始"
),
),
(
"operator",
models.CharField(max_length=11, verbose_name="操作客服ID"),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
],
options={
"verbose_name": "订单打手变更历史",
"verbose_name_plural": "订单打手变更历史",
"db_table": "order_dashou_history",
"indexes": [
models.Index(
fields=["dingdan_id"], name="order_dasho_dingdan_1e79ab_idx"
),
models.Index(
fields=["dashou_id"], name="order_dasho_dashou__0a637c_idx"
),
],
},
),
migrations.CreateModel(
name="CrossPlatformOrderData",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"dingdan_id",
models.CharField(
db_index=True,
max_length=32,
unique=True,
verbose_name="我方订单ID",
),
),
(
"partner_order_id",
models.CharField(
db_index=True, max_length=32, verbose_name="对方平台订单ID"
),
),
(
"partner_club_id",
models.CharField(
db_index=True, max_length=6, verbose_name="对方俱乐部ID"
),
),
(
"partner_order_status",
models.IntegerField(default=0, verbose_name="对方平台订单状态"),
),
(
"partner_dashou_id",
models.CharField(
blank=True,
default="",
max_length=32,
verbose_name="对方平台接单打手ID",
),
),
(
"partner_amount",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="对方平台订单金额",
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"verbose_name": "跨平台订单扩展",
"verbose_name_plural": "跨平台订单扩展",
"db_table": "cross_platform_order_data",
"indexes": [
models.Index(
fields=["dingdan_id"], name="cross_platf_dingdan_498d08_idx"
),
models.Index(
fields=["partner_order_id"],
name="cross_platf_partner_5d5615_idx",
),
models.Index(
fields=["partner_club_id"],
name="cross_platf_partner_1054e1_idx",
),
],
},
),
]

View File

@@ -0,0 +1,24 @@
# Generated by Django 4.2.27 on 2026-04-04 15:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0009_presettlement_orderdashouhistory_and_more"),
]
operations = [
migrations.AlterField(
model_name="presettlement",
name="dingdan_id",
field=models.CharField(
db_index=True, max_length=32, verbose_name="我方订单ID"
),
),
migrations.AlterUniqueTogether(
name="presettlement",
unique_together={("dingdan_id", "dashou_id")},
),
]

View File

@@ -0,0 +1,211 @@
# Generated by Django 4.2.27 on 2026-05-06 11:30
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0010_alter_presettlement_dingdan_id_and_more"),
]
operations = [
migrations.AddField(
model_name="dingdanshangjia",
name="partner_yonghu_id",
field=models.CharField(
blank=True, max_length=32, null=True, verbose_name="对方平台用户ID"
),
),
migrations.CreateModel(
name="FadanFenhong",
fields=[
(
"id",
models.AutoField(
primary_key=True, serialize=False, verbose_name="自增主键"
),
),
(
"fenhongzhe_id",
models.CharField(
db_index=True, max_length=20, verbose_name="分红者ID"
),
),
(
"zonge",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="分红总额",
),
),
(
"ketixian_fenhong",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="可提现分红",
),
),
(
"shenfen",
models.IntegerField(
choices=[(1, "商家"), (2, "客服"), (3, "平台管理者")],
default=1,
verbose_name="分红者身份",
),
),
(
"fenhong_cishu",
models.IntegerField(default=0, verbose_name="分红次数"),
),
(
"yingde_lilv",
models.DecimalField(
decimal_places=4,
default=0.0,
max_digits=5,
verbose_name="分红应得利率",
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"verbose_name": "罚款分红",
"verbose_name_plural": "罚款分红",
"db_table": "fadan_fenhong",
"indexes": [
models.Index(
fields=["fenhongzhe_id"], name="fadan_fenhong_zhe_idx"
),
models.Index(fields=["shenfen"], name="fadan_fenhong_sf_idx"),
],
},
),
migrations.CreateModel(
name="Fadan",
fields=[
(
"id",
models.AutoField(
primary_key=True, serialize=False, verbose_name="自增主键"
),
),
(
"beichufa_id",
models.CharField(
db_index=True, max_length=20, verbose_name="被处罚用户ID"
),
),
(
"shenqing_chufa",
models.CharField(
blank=True,
max_length=20,
null=True,
verbose_name="申请处罚者ID",
),
),
(
"shenfen",
models.IntegerField(
choices=[(1, "打手"), (2, "管事"), (3, "商家"), (4, "组长")],
default=1,
verbose_name="被处罚者身份",
),
),
(
"chufaliyou",
models.TextField(blank=True, null=True, verbose_name="处罚理由"),
),
(
"fakuanjine",
models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=10,
verbose_name="罚款金额",
),
),
(
"guanliandingdan_id",
models.CharField(
blank=True,
db_index=True,
max_length=32,
null=True,
verbose_name="关联订单ID",
),
),
(
"zhuangtai",
models.IntegerField(
choices=[
(1, "待缴纳"),
(2, "已缴纳"),
(3, "申诉中"),
(4, "已驳回"),
],
db_index=True,
default=1,
verbose_name="罚单状态",
),
),
(
"yingxiang_qiangdan",
models.IntegerField(
choices=[(1, "影响抢单"), (0, "不影响抢单")],
db_index=True,
default=1,
verbose_name="是否影响抢单",
),
),
(
"shensuliyou",
models.TextField(blank=True, null=True, verbose_name="申诉理由"),
),
(
"tongyi_chufaliyou",
models.TextField(
blank=True, null=True, verbose_name="同意处罚理由"
),
),
(
"bohuiliyou",
models.TextField(blank=True, null=True, verbose_name="驳回理由"),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"verbose_name": "罚单",
"verbose_name_plural": "罚单",
"db_table": "fadan",
"indexes": [
models.Index(
fields=["beichufa_id", "yingxiang_qiangdan", "zhuangtai"],
name="fadan_qiangdan_check",
),
models.Index(
fields=["guanliandingdan_id"], name="fadan_dingdan_idx"
),
],
},
),
]

View File

@@ -0,0 +1,114 @@
# Generated by Django 4.2.27 on 2026-05-13 08:51
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0011_dingdanshangjia_partner_yonghu_id_fadanfenhong_fadan"),
]
operations = [
migrations.AddField(
model_name="fadan",
name="chulizhe",
field=models.CharField(
blank=True, max_length=20, null=True, verbose_name="处理者"
),
),
migrations.AddField(
model_name="fadan",
name="chulizhe_shenfen",
field=models.IntegerField(
choices=[(1, "客服"), (2, "售后"), (3, "管理员")],
default=2,
verbose_name="处理者身份",
),
),
migrations.AddField(
model_name="fadan",
name="partner_club_id",
field=models.CharField(
blank=True,
db_index=True,
max_length=6,
null=True,
verbose_name="对方俱乐部ID",
),
),
migrations.AddField(
model_name="fadan",
name="shenqingren_shenfen",
field=models.IntegerField(
choices=[
(1, "客服"),
(2, "售后"),
(3, "管理员"),
(4, "店铺"),
(5, "商家"),
],
default=1,
verbose_name="申请处罚人身份",
),
),
migrations.CreateModel(
name="FadanShensuTupian",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"beichufa_id",
models.CharField(
db_index=True, max_length=7, verbose_name="被处罚用户ID"
),
),
(
"tupian_url",
models.CharField(max_length=500, verbose_name="图片相对URL"),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"yongtu",
models.IntegerField(
choices=[(1, "处罚证据图片"), (2, "申诉图片")],
default=2,
verbose_name="图片用途",
),
),
(
"fadan",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="shensu_tupians",
to="dingdan.fadan",
verbose_name="关联罚单",
),
),
],
options={
"verbose_name": "罚款申诉图片",
"verbose_name_plural": "罚款申诉图片",
"db_table": "fadan_shensu_tupian",
"indexes": [
models.Index(
fields=["fadan_id"], name="fadan_shens_fadan_i_78fab9_idx"
),
models.Index(
fields=["beichufa_id"], name="fadan_shens_beichuf_59748e_idx"
),
],
},
),
]

View File

@@ -0,0 +1,63 @@
# Generated by Django 4.2.27 on 2026-05-19 17:30
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0012_fadan_chulizhe_fadan_chulizhe_shenfen_and_more"),
]
operations = [
migrations.AddField(
model_name="dingdanpingtai",
name="dianpu_id",
field=models.PositiveIntegerField(
blank=True, db_index=True, null=True, verbose_name="所属店铺ID"
),
),
migrations.AddField(
model_name="dingdanpingtai",
name="dianpu_shouyi",
field=models.DecimalField(
blank=True,
decimal_places=2,
default=0.0,
max_digits=10,
null=True,
verbose_name="店铺收益",
),
),
migrations.AddField(
model_name="dingdanpingtai",
name="pingtai_shouyi",
field=models.DecimalField(
blank=True,
decimal_places=2,
default=0.0,
max_digits=10,
null=True,
verbose_name="平台收益",
),
),
migrations.AddField(
model_name="dingdanpingtai",
name="shangji_dianpu_id",
field=models.PositiveIntegerField(
blank=True, db_index=True, null=True, verbose_name="该订单的上级店铺ID"
),
),
migrations.AddField(
model_name="dingdanpingtai",
name="shangji_fenhong",
field=models.DecimalField(
blank=True,
decimal_places=2,
default=0.0,
max_digits=10,
null=True,
verbose_name="上级分红金额",
),
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 4.2.27 on 2026-06-05 13:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0013_dingdanpingtai_dianpu_id_and_more"),
]
operations = [
migrations.AddField(
model_name="fadan",
name="shenqingren_fenhong_jine",
field=models.DecimalField(
decimal_places=2,
default=0.0,
max_digits=12,
verbose_name="申请人分红金额",
),
),
]

View File

@@ -0,0 +1,77 @@
# Generated by Django 4.2.27 on 2026-06-05 14:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0014_fadan_shenqingren_fenhong_jine"),
]
operations = [
migrations.CreateModel(
name="FadanFenhongLilv",
fields=[
(
"shenfen",
models.IntegerField(
choices=[
(1, "客服"),
(2, "售后"),
(3, "管理员"),
(4, "店铺"),
(5, "商家"),
],
primary_key=True,
serialize=False,
verbose_name="申请处罚人身份",
),
),
(
"lilv",
models.DecimalField(
decimal_places=4,
default=0.0,
max_digits=5,
verbose_name="分红费率",
),
),
(
"create_time",
models.DateTimeField(auto_now_add=True, verbose_name="创建时间"),
),
(
"update_time",
models.DateTimeField(auto_now=True, verbose_name="更新时间"),
),
],
options={
"verbose_name": "罚款分红费率配置",
"verbose_name_plural": "罚款分红费率配置",
"db_table": "fadan_fenhong_lilv",
},
),
migrations.AddField(
model_name="fadanfenhong",
name="is_individual_rate",
field=models.BooleanField(
default=False, verbose_name="是否单独开启分红利率"
),
),
migrations.AlterField(
model_name="fadanfenhong",
name="shenfen",
field=models.IntegerField(
choices=[
(1, "商家"),
(2, "客服"),
(3, "平台管理者"),
(4, "店铺"),
(5, "售后"),
],
default=1,
verbose_name="分红者身份",
),
),
]

View File

@@ -0,0 +1,25 @@
# Generated by Django 4.2.27 on 2026-06-11 23:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dingdan", "0015_fadanfenhonglilv_fadanfenhong_is_individual_rate_and_more"),
]
operations = [
migrations.AddField(
model_name="dingdan",
name="guanshi_fencheng",
field=models.DecimalField(
blank=True,
decimal_places=2,
default=0,
max_digits=10,
null=True,
verbose_name="管事分成",
),
),
]

View File

539
dingdan/models.py Normal file
View File

@@ -0,0 +1,539 @@
from django.db import models
class Dingdan(models.Model):
"""订单主表"""
# 核心编号:唯一且不可为空[citation:3][citation:9]
dingdan_id = models.CharField(max_length=32, unique=True,db_index=True, verbose_name='订单ID')
# 状态与平台:用整数表示,具体含义由业务逻辑定义
zhuangtai = models.IntegerField(default=1, null=True, blank=True,db_index=True, verbose_name='订单状态')
fadan_pingtai = models.IntegerField(null=True, blank=True, verbose_name='发单平台')
# 金额相关
jine = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name='订单金额')
dashou_fencheng = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name='打手分成')
guanshi_fencheng = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, default=0, verbose_name='管事分成')
# 用户与商品关联ID
jiedan_dashou_id = models.CharField(max_length=32, null=True, db_index=True,blank=True, verbose_name='接单打手ID')
dashou_liuyan = models.TextField(null=True, blank=True, verbose_name='打手留言')
zhiding_id = models.CharField(max_length=32, null=True, blank=True, verbose_name='指定ID')
shangpin_id = models.IntegerField(null=True, blank=True, verbose_name='商品ID')
leixing_id = models.PositiveIntegerField(null=True, blank=True, verbose_name='商品类型ID') # 直接存数字
tupian = models.CharField(max_length=500, null=True, blank=True, verbose_name='商品图片URL')
yaoqiuleixing = models.PositiveIntegerField(null=True, blank=True, verbose_name='抢单要求类型')
huiyuan_id = models.CharField(max_length=6, null=True, blank=True, verbose_name='会员ID')
yongjin = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name='佣金要求')
# 订单描述信息
jieshao = models.TextField(null=True, blank=True, verbose_name='订单介绍')
beizhu = models.TextField(null=True, blank=True, verbose_name='订单备注')
partner_order_id = models.CharField(max_length=32, null=True, blank=True, db_index=True,verbose_name='对方平台订单ID')
is_cross = models.IntegerField(default=0, verbose_name='是否跨平台订单(0否,1是)')
dispatch_type = models.IntegerField(default=0, choices=[(1, '我方派单'), (2, '对方派单')], verbose_name='派发情况')
# 🔥 新增对方俱乐部ID
partner_club_id = models.CharField(max_length=6, null=True, blank=True, db_index=True, verbose_name='对方俱乐部ID')
tkly = models.CharField(max_length=500, blank=True, null=True, verbose_name='退款/拒绝理由')
# 新增字段:游戏昵称(前端提交的游戏昵称)
nicheng = models.CharField(max_length=50, null=True, blank=True, verbose_name='游戏昵称')
user1_id = models.CharField(max_length=30,null=True, db_index=True, verbose_name='用户1标识')
user2_id = models.CharField(max_length=30, null=True,db_index=True, verbose_name='用户2打手标识')
#liaotian_pindao = models.CharField(max_length=255, blank=True, null=True, verbose_name='聊天频道名')
# 时间戳
auto_task_id = models.CharField('延时任务ID', max_length=255, blank=True, default='')
auto_expire_at = models.DateTimeField('计划过期时间', null=True, blank=True)
pending_dispatch = models.BooleanField('待调度标记', default=False, db_index=True)
status_8_time = models.DateTimeField('状态变为8的时间', null=True, blank=True)
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
clkf = models.CharField(max_length=20, null=True, db_index=True, verbose_name='处理客服')
wechat_transaction_id = models.CharField(
max_length=64,
blank=True,
null=True,
db_index=True,
verbose_name='微信支付订单号'
)
class Meta:
db_table = 'dingdan'
verbose_name = '订单'
verbose_name_plural = '订单'
# 为高频查询字段添加索引
indexes = [
models.Index(fields=['zhuangtai']),
models.Index(fields=['dingdan_id']),
models.Index(fields=['jiedan_dashou_id']),
# 🆕 为新增字段添加索引(可选)
models.Index(fields=['wechat_transaction_id']),
]
def __str__(self):
return self.dingdan_id
class DingdanPingtai(models.Model):
"""平台订单扩展表 (当 fadan_pingtai=1 时使用)"""
dingdan = models.OneToOneField(Dingdan, on_delete=models.CASCADE, related_name='pingtai_kuozhan', verbose_name='订单')
laoban_id = models.CharField(max_length=32, null=True, blank=True, db_index=True,verbose_name='老板ID')
laoban_pingjia = models.TextField(null=True, blank=True, verbose_name='老板评价')
jjjs_biaoshi = models.IntegerField(default=0, verbose_name='拒绝结算标记(1表示拒绝结算)')
pingtai_shouyi = models.DecimalField(max_digits=10,decimal_places=2,null=True,blank=True,default=0.00,verbose_name='平台收益')
dianpu_shouyi = models.DecimalField(max_digits=10,decimal_places=2, null=True,blank=True,default=0.00,verbose_name='店铺收益')
dianpu_id = models.PositiveIntegerField(null=True,blank=True,db_index=True,verbose_name='所属店铺ID')
# ---------- 上级分红快照 ----------
shangji_dianpu_id = models.PositiveIntegerField(null=True, blank=True, db_index=True,
verbose_name='该订单的上级店铺ID')
shangji_fenhong = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, default=0.00,
verbose_name='上级分红金额')
class Meta:
db_table = 'dingdan_pingtai'
verbose_name = '平台订单扩展'
verbose_name_plural = '平台订单扩展'
indexes = [
models.Index(fields=['laoban_id']),
]
def __str__(self):
return f"平台扩展-{self.dingdan.dingdan_id}"
class DingdanShangjia(models.Model):
"""商家发单扩展表 (当 fadan_pingtai=2 时使用)"""
dingdan = models.OneToOneField(Dingdan, on_delete=models.CASCADE, related_name='shangjia_kuozhan', verbose_name='订单')
shangjia_id = models.CharField(max_length=32, null=True, blank=True,db_index=True, verbose_name='商家ID')
shangjia_pingjia = models.TextField(null=True, blank=True, verbose_name='商家评价')
cfliyou = models.TextField(null=True, blank=True, verbose_name='商家处罚理由')
sqzhuangtai =models.IntegerField(default=0, null=True, blank=True, verbose_name='处罚申请状态:0待处理,1成功,2驳回')
bhliyou = models.TextField(null=True, blank=True, verbose_name='驳回商家处罚理由')
sjnicheng =models.CharField(max_length=50,null=True, verbose_name='商家昵称')
partner_yonghu_id = models.CharField(max_length=32, blank=True, null=True, verbose_name='对方平台用户ID')
class Meta:
db_table = 'dingdan_shangjia'
verbose_name = '商家订单扩展'
verbose_name_plural = '商家订单扩展'
indexes = [
models.Index(fields=['shangjia_id']),
]
def __str__(self):
return f"商家扩展-{self.dingdan.dingdan_id}"
class CrossPlatformOrderData(models.Model):
"""
跨平台订单扩展数据表
存储我方订单与对方平台订单的关联及对方订单状态
"""
dingdan_id = models.CharField(max_length=32, unique=True, db_index=True, verbose_name='我方订单ID')
partner_order_id = models.CharField(max_length=32, db_index=True, verbose_name='对方平台订单ID')
partner_club_id = models.CharField(max_length=6, db_index=True, verbose_name='对方俱乐部ID')
partner_order_status = models.IntegerField(default=0, verbose_name='对方平台订单状态') # 对方订单当前状态码
partner_dashou_id = models.CharField(max_length=32, blank=True, default='', verbose_name='对方平台接单打手ID')
partner_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='对方平台订单金额')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'cross_platform_order_data'
verbose_name = '跨平台订单扩展'
verbose_name_plural = '跨平台订单扩展'
indexes = [
models.Index(fields=['dingdan_id']),
models.Index(fields=['partner_order_id']),
models.Index(fields=['partner_club_id']),
]
def __str__(self):
return f"{self.dingdan_id} -> {self.partner_order_id}"
# 建议路径dingdan/models.py 或 独立 fadan/models.py
from django.db import models
class Fadan(models.Model):
"""罚单表——平台各类处罚信息"""
id = models.AutoField(primary_key=True, verbose_name='自增主键')
beichufa_id = models.CharField(max_length=20, db_index=True, verbose_name='被处罚用户ID') # 直接用yonghuid后续可改为外键
shenqing_chufa = models.CharField(max_length=20, blank=True, null=True, verbose_name='申请处罚者ID')
shenfen = models.IntegerField(choices=[(1, '打手'), (2, '管事'), (3, '商家'), (4, '组长')], default=1, verbose_name='被处罚者身份')
chufaliyou = models.TextField(blank=True, null=True, verbose_name='处罚理由')
fakuanjine = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='罚款金额')
guanliandingdan_id = models.CharField(max_length=32, blank=True, null=True, db_index=True, verbose_name='关联订单ID')
zhuangtai = models.IntegerField(choices=[(1, '待缴纳'), (2, '已缴纳'), (3, '申诉中'), (4, '已驳回')], default=1, db_index=True, verbose_name='罚单状态')
yingxiang_qiangdan = models.IntegerField(choices=[(1, '影响抢单'), (0, '不影响抢单')], default=1, db_index=True, verbose_name='是否影响抢单')
shensuliyou = models.TextField(blank=True, null=True, verbose_name='申诉理由')
tongyi_chufaliyou = models.TextField(blank=True, null=True, verbose_name='同意处罚理由')
bohuiliyou = models.TextField(blank=True, null=True, verbose_name='驳回理由')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
# 在 Fadan 模型中添加
partner_club_id = models.CharField(max_length=6, blank=True, null=True, db_index=True, verbose_name='对方俱乐部ID')
# 在 class Fadan 中添加
shenqingren_shenfen = models.IntegerField(
choices=[(1, '客服'), (2, '售后'), (3, '管理员'),(4,'店铺'),(5,'商家')], # 按实际扩展
default=1,
verbose_name='申请处罚人身份'
)
chulizhe_shenfen = models.IntegerField(
choices=[(1, '客服'), (2, '售后'), (3, '管理员')],
default=2,
verbose_name='处理者身份'
)
chulizhe = models.CharField(max_length=20, blank=True, null=True, verbose_name='处理者')
# ========== 新增字段 ==========
shenqingren_fenhong_jine = models.DecimalField(
max_digits=12, decimal_places=2, default=0.00,
verbose_name='申请人分红金额'
)
class Meta:
db_table = 'fadan'
verbose_name = '罚单'
verbose_name_plural = '罚单'
indexes = [
models.Index(fields=['beichufa_id', 'yingxiang_qiangdan', 'zhuangtai'], name='fadan_qiangdan_check'),
models.Index(fields=['guanliandingdan_id'], name='fadan_dingdan_idx'),
]
def __str__(self):
return f"{self.beichufa_id} - 罚款{self.fakuanjine}元 - 状态{self.zhuangtai}"
# ==================== 罚款申诉图片表 ====================
class FadanShensuTupian(models.Model):
"""罚款申诉图片,关联罚单"""
fadan = models.ForeignKey(Fadan, on_delete=models.CASCADE, related_name='shensu_tupians', verbose_name='关联罚单')
beichufa_id = models.CharField(max_length=7, db_index=True, verbose_name='被处罚用户ID') # 冗余,便于直接按用户查
tupian_url = models.CharField(max_length=500, verbose_name='图片相对URL')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
# 在 FadanShensuTupian 模型中添加
yongtu = models.IntegerField(
choices=[(1, '处罚证据图片'), (2, '申诉图片')],
default=2,
verbose_name='图片用途'
)
class Meta:
db_table = 'fadan_shensu_tupian'
verbose_name = '罚款申诉图片'
verbose_name_plural = '罚款申诉图片'
indexes = [
models.Index(fields=['fadan_id']),
models.Index(fields=['beichufa_id']),
]
# 与 Fadan 放在同一个文件或独立的 fadan/models.py
class FadanFenhong(models.Model):
"""罚款分红表——记录罚款产生的分红信息"""
id = models.AutoField(primary_key=True, verbose_name='自增主键')
fenhongzhe_id = models.CharField(max_length=20, db_index=True, verbose_name='分红者ID')
zonge = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='分红总额')
ketixian_fenhong = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='可提现分红')
shenfen = models.IntegerField(choices=[(1, '商家'), (2, '客服'), (3, '平台管理者'),(4,'店铺'),(5, '售后')], default=1, verbose_name='分红者身份')
fenhong_cishu = models.IntegerField(default=0, verbose_name='分红次数')
# ✅ 新增字段:是否单独开启分红利率(若开启,则使用本记录的 yingde_lilv否则使用全局配置
is_individual_rate = models.BooleanField(default=False, verbose_name='是否单独开启分红利率')
yingde_lilv = models.DecimalField(max_digits=5, decimal_places=4, default=0.0000, verbose_name='分红应得利率')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'fadan_fenhong'
verbose_name = '罚款分红'
verbose_name_plural = '罚款分红'
indexes = [
models.Index(fields=['fenhongzhe_id'], name='fadan_fenhong_zhe_idx'),
models.Index(fields=['shenfen'], name='fadan_fenhong_sf_idx'),
]
def __str__(self):
return f"{self.fenhongzhe_id} - 分红{self.ketixian_fenhong}"
class FadanFenhongLilv(models.Model):
shenfen = models.IntegerField(primary_key=True, choices=[(1, '客服'), (2, '售后'), (3, '管理员'), (4, '店铺'), (5, '商家')], verbose_name='申请处罚人身份')
lilv = models.DecimalField(max_digits=5, decimal_places=4, default=0.0000, verbose_name='分红费率')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'fadan_fenhong_lilv'
verbose_name = '罚款分红费率配置'
verbose_name_plural = verbose_name
def __str__(self):
return f"身份{self.shenfen} - 费率{self.lilv}"
# apps/dingdan/models.py 中添加
class PreSettlement(models.Model):
"""
预结算表
用于记录对方平台派单订单的待结算款项,等待对方确认后才能真正入账
"""
STATUS_CHOICES = (
(0, '待结算'),
(1, '已结算'),
(2, '已拒绝'),
)
# 我方订单ID
dingdan_id = models.CharField(max_length=32, db_index=True, verbose_name='我方订单ID')
# 对方订单ID
partner_order_id = models.CharField(max_length=32, db_index=True, verbose_name='对方订单ID')
# 对方俱乐部ID
partner_club_id = models.CharField(max_length=6, db_index=True, verbose_name='对方俱乐部ID')
# 接单打手ID
dashou_id = models.CharField(max_length=7, db_index=True, verbose_name='接单打手ID')
# 打手应分金额
amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='打手应分金额')
# 订单金额(原金额,可选)
order_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='订单原金额')
# 结算状态
status = models.SmallIntegerField(choices=STATUS_CHOICES, default=0, verbose_name='结算状态')
# 处理时间(结算或拒绝的时间)
process_time = models.DateTimeField(null=True, blank=True, verbose_name='处理时间')
# 处理客服/对方操作人(可选)
operator = models.CharField(max_length=32, blank=True, default='', verbose_name='操作人')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'pre_settlement'
verbose_name = '预结算表'
verbose_name_plural = verbose_name
unique_together = [['dingdan_id', 'dashou_id']]
indexes = [
models.Index(fields=['dingdan_id']),
models.Index(fields=['partner_order_id']),
models.Index(fields=['partner_club_id']),
models.Index(fields=['dashou_id']),
models.Index(fields=['status']),
]
def __str__(self):
return f"预结算-{self.dingdan_id} -> {self.partner_order_id}"
# apps/dingdan/models.py 中添加
class OrderDashouHistory(models.Model):
"""
订单打手变更历史表
记录订单每次更换打手的操作
"""
dingdan_id = models.CharField(max_length=32, db_index=True, verbose_name='订单ID')
dashou_id = models.CharField(max_length=7, db_index=True, verbose_name='打手ID')
times = models.PositiveSmallIntegerField(verbose_name='第几次接单从1开始')
operator = models.CharField(max_length=11, verbose_name='操作客服ID')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
class Meta:
db_table = 'order_dashou_history'
verbose_name = '订单打手变更历史'
verbose_name_plural = '订单打手变更历史'
indexes = [
models.Index(fields=['dingdan_id']),
models.Index(fields=['dashou_id']),
]
def __str__(self):
return f"{self.dingdan_id} -> {self.dashou_id}{self.times}"
class Dashoutupian(models.Model):
dingdan_id = models.CharField(max_length=32,db_index=True, null=True, verbose_name='订单ID')
dashou = models.CharField(max_length=32, null=True, blank=True,db_index=True, verbose_name='接单打手ID')
tupian = models.CharField(max_length=500, null=True, blank=True, verbose_name='打手提交图片URL')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'dashoutupian'
indexes = [
models.Index(fields=['dashou']),
models.Index(fields=['dingdan_id']),
]
class Pingfen(models.Model):
dashou = models.CharField(max_length=32, null=True, blank=True, db_index=True,verbose_name='接单打手ID')
zongfen = models.PositiveIntegerField(default=0, verbose_name='总分')
cishu = models.PositiveIntegerField(default=0, verbose_name='评分次数')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'pingfenbiao'
verbose_name = '评分表'
indexes = [
models.Index(fields=['dashou']),
]
def __str__(self):
return f"{self.dashou} - 平均分: {self.pingjun_fen():.2f}"
def pingjun_fen(self):
"""计算平均分"""
if self.cishu > 0:
return float(self.zongfen) / self.cishu
return 0.0
class Lilubiao(models.Model):
lilu = models.DecimalField(max_digits=5, decimal_places=4,null=True, verbose_name='平台分成利率1是平台,2是商家')
#sahngjialilu = models.DecimalField(max_digits=5, decimal_places=4,null=True, verbose_name='商家利率')
fadanpingtai = models.CharField(max_length=10,null=True,verbose_name='订单所属平台,(商家或平台)')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'lilubiao'
class Chufajilu(models.Model):
dashouid = models.CharField(max_length=7, null=True, db_index=True, verbose_name='被罚打手ID')
qingqiuid = models.CharField(max_length=7, null=True, db_index=True, verbose_name='请求处罚ID')
chuliid = models.CharField(max_length=11, null=True, db_index=True, verbose_name='处理处罚ID')
cfliyou = models.TextField(null=True, blank=True, verbose_name='处罚理由')
sqzhuangtai = models.IntegerField(default=0, null=True, blank=True, verbose_name='处罚申请状态:0待处理,1成功,2驳回')
bhliyou = models.TextField(null=True, blank=True, verbose_name='驳回处罚理由')
ssliyou = models.TextField(null=True, blank=True, verbose_name='打手申诉理由')
jifen = models.IntegerField(default=0, verbose_name='扣除打手积分')
dingdan_id = models.CharField(max_length=32, null=True, db_index=True, verbose_name='订单ID')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'chufajilu'
indexes = [
models.Index(fields=['dashouid']),
models.Index(fields=['qingqiuid']),
models.Index(fields=['chuliid']),
models.Index(fields=['dingdan_id']),
]
class Chufatupian(models.Model):
dingdan_id = models.CharField(max_length=32,db_index=True, null=True, verbose_name='订单ID')
yonghuid = models.CharField(max_length=32, null=True, blank=True,db_index=True, verbose_name='用户ID')
tupian = models.CharField(max_length=500, null=True, blank=True, verbose_name='证据图片URL')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'chufatupian'
indexes = [
models.Index(fields=['yonghuid']),
models.Index(fields=['dingdan_id']),
]
class Tuikuanjilu(models.Model):
dingdan_id = models.CharField(max_length=32, unique=True, verbose_name='订单ID')
dashouid = models.CharField(max_length=7, null=True, verbose_name='接单打手ID')
qingqiuid = models.CharField(max_length=7, null=True, verbose_name='请求用户ID')
chuliid = models.CharField(max_length=11, null=True, db_index=True, verbose_name='处理人ID')
liyou = models.TextField(null=True, blank=True, verbose_name='理由')
sqzhuangtai = models.IntegerField(default=0, null=True, blank=True,db_index=True, verbose_name='申请状态:0待处理,1成功,2驳回')
bhliyou = models.TextField(null=True, blank=True, verbose_name='驳回理由')
jine = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name='订单金额')
dashou_fencheng = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name='打手分成')
jieshao = models.TextField(null=True, blank=True, verbose_name='订单介绍')
beizhu = models.TextField(null=True, blank=True, verbose_name='订单备注')
# 新增字段:游戏昵称(前端提交的游戏昵称)
nicheng = models.CharField(max_length=50, null=True, blank=True, verbose_name='游戏昵称')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'tuikuanjilu'
indexes = [
models.Index(fields=['chuliid']),
models.Index(fields=['sqzhuangtai']),
]
class Ptliushui(models.Model):
zonge = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name='收取总金额')
zhichuzonge = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name='支出总金额')
zongshouyi = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name='总收益')
rizonge = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name='日收取')
rizhichu = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name='日支出')
rishouyi = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name='日收益')
zongshoucishu = models.IntegerField(default=0, verbose_name='总收取次数')
rishoucishu = models.IntegerField(default=0, verbose_name='日收取次数')
zongzhichucishu = models.IntegerField(default=0, verbose_name='总支出次数')
rizhichucishu = models.IntegerField(default=0, verbose_name='日支出次数')
class Meta:
db_table = 'ptliushui'
# models.py - ChatRelation 模型
class Liaotian(models.Model):
"""聊天关系表 - 极简设计,不设置唯一约束"""
# 主键
id = models.BigAutoField(primary_key=True, verbose_name='主键ID')
# 聊天双方的用户标识GoEasy的user_id
user1_id = models.CharField(max_length=30, db_index=True, verbose_name='用户1标识')
user2_id = models.CharField(max_length=30, db_index=True, verbose_name='用户2标识')
# 关联的订单(可以为空,但实际业务中应该关联)
dingdan_id = models.CharField(max_length=32, unique=True, verbose_name='订单ID')
# 状态与平台:用整数表示,具体含义由业务逻辑定义
zhuangtai = models.IntegerField(default=1,db_index=True,choices=[(1, '开启中'), (0, '已关闭')],verbose_name='聊天状态')
# 时间戳
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
db_table = 'liaotian'
indexes = [
models.Index(fields=['user1_id']),
models.Index(fields=['user2_id']),
models.Index(fields=['zhuangtai']),
]
def __str__(self):
return f'{self.user1_id}{self.user2_id} ({self.zhuangtai})'

272
dingdan/signals.py Normal file
View File

@@ -0,0 +1,272 @@
"""
阿龙电竞 - 订单信号处理(优化版)
核心原则:绝对不影响订单提交的性能和稳定性
设计理念:订单状态变化只记录,不执行,由接口或定时任务处理具体逻辑
"""
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.conf import settings
from django.utils import timezone
import logging
import threading
import time
from dingdan.models import Dingdan
# dingdan/signals.py
"""
阿龙电竞 - 订单信号处理器(生产稳定版)
经过验证100%可靠
"""
import sys
import importlib
import logging
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.conf import settings
from django.utils import timezone
logger = logging.getLogger(__name__)
# 🔧 关键修复确保redis模块正确加载
def ensure_redis_loaded():
"""确保redis模块正确加载避免导入冲突"""
if 'redis' not in sys.modules:
# 如果redis模块未加载尝试导入
try:
import redis
#logger.debug("✅ Redis模块正常加载")
except ImportError:
#logger.warning("⚠️ Redis模块未安装尝试自动安装")
import subprocess
subprocess.call([sys.executable, "-m", "pip", "install", "redis==4.5.4", "-q"])
import redis
# 确保redis.Redis属性存在
import redis
if redis.Redis is None:
#logger.warning("⚠️ Redis.Redis属性为None强制重新加载模块")
importlib.reload(redis)
return redis
# 预加载redis模块
ensure_redis_loaded()
@receiver(pre_save, sender='dingdan.Dingdan')
def handle_order_status_8(sender, instance, **kwargs):
"""
订单状态变为8时提交定时任务
"""
# 跳过新增的订单
if instance.pk is None:
return
try:
# 动态导入,避免循环依赖
from dingdan.models import Dingdan
# 获取旧状态
old = Dingdan.objects.filter(pk=instance.pk).values_list('zhuangtai', flat=True).first()
# 状态从 非8 变为 8
if old != 8 and instance.zhuangtai == 8:
logger.info(f"📅 订单 {instance.dingdan_id} 状态变为8提交定时任务")
# 设置时间标记
instance.status_8_time = timezone.now()
instance.pending_dispatch = True
# 使用配置中的超时时间
expire_seconds = getattr(settings, 'ORDER_EXPIRE_SECONDS', 48 * 60 * 60)
# 提交Celery任务
try:
from dingdan.tasks import process_expired_order
task_result = process_expired_order.apply_async(
args=[instance.dingdan_id],
countdown=expire_seconds,
queue='order_tasks',
priority=9
)
logger.info(f"✅ 任务提交成功,订单: {instance.dingdan_id}, 任务ID: {task_result.id}")
# 保存任务信息
instance.auto_task_id = task_result.id
instance.auto_expire_at = timezone.now() + timezone.timedelta(seconds=expire_seconds)
except Exception as e:
logger.error(f"❌ 任务提交失败: {e}")
instance.pending_dispatch = True
instance.auto_task_id = f"failed_{timezone.now().timestamp()}"
# 状态从 8 变为 非8
elif old == 8 and instance.zhuangtai != 8:
instance.status_8_time = None
instance.pending_dispatch = False
instance.auto_task_id = ''
logger.info(f"📅 订单 {instance.dingdan_id} 状态离开8")
except Exception as e:
logger.error(f"信号处理失败: {e}")
logger = logging.getLogger(__name__)
'''def try_start_celery_task_async(dingdan_id, countdown):
"""
异步尝试启动Celery任务在独立线程中运行
如果Redis不可用立即失败不影响主流程
"""
def _async_task():
try:
# 设置超时时间500毫秒避免长时间等待
import socket
socket.setdefaulttimeout(0.5)
from dingdan.tasks import process_expired_order
from celery.exceptions import TimeoutError
# 尝试启动任务,设置极短的超时
task = process_expired_order.apply_async(
args=[dingdan_id],
countdown=countdown,
queue='order_tasks',
priority=9,
expires=countdown + 3600 # 任务1小时后过期避免堆积
)
# 不等待任务结果,立即返回
logger.info(f"订单 {dingdan_id} 异步任务已提交任务ID: {task.id}")
except Exception as e:
# 记录警告,但不要影响主流程
logger.warning(f"订单 {dingdan_id} 异步任务提交失败: {str(e)}")
# 这个失败不影响订单保存,系统有补偿机制
# 启动异步线程(后台运行,不阻塞主流程)
thread = threading.Thread(target=_async_task)
thread.daemon = True # 设置为守护线程,主线程退出时会自动结束
thread.start()
@receiver(pre_save, sender=Dingdan)
def handle_order_status_change_lightweight(sender, instance, **kwargs):
"""
轻量级订单状态变化监听器
设计原则:
1. 绝对不阻塞订单保存
2. 不依赖外部服务可用性
3. 只记录,不执行
"""
try:
# 1. 快速检查:如果是新建订单,直接返回
if instance.pk is None:
return
# 2. 快速获取旧状态(使用数据库当前值,不加载完整对象)
try:
old_status = Dingdan.objects.filter(pk=instance.pk).values_list('zhuangtai', flat=True).first()
except Exception:
old_status = None
# 3. 状态变化判断
if old_status is None or old_status != instance.zhuangtai:
# 状态发生变化,记录到订单扩展字段或日志(但不要阻塞)
try:
# 这里只是示例,实际可以根据需要记录状态变化历史
pass
except:
pass # 即使记录失败也不影响主流程
# 4. 特殊状态处理状态变为8
if old_status != 8 and instance.zhuangtai == 8:
# 4.1 立即记录日志(不等待)
logger.info(f"订单 {instance.dingdan_id} 状态变为8")
# 4.2 异步尝试启动定时任务(不阻塞主流程)
# 使用线程池或直接新线程,确保不阻塞
try:
# 启动异步线程尝试提交Celery任务
if hasattr(settings, 'CELERY_BROKER_URL') and settings.CELERY_BROKER_URL:
# 在独立线程中尝试,完全不阻塞
threading.Thread(
target=try_start_celery_task_async,
args=(instance.dingdan_id, settings.ORDER_EXPIRE_SECONDS),
daemon=True
).start()
except Exception as e:
# 即使线程启动失败也不影响主流程
logger.warning(f"启动异步任务线程失败: {str(e)}")
# 5. 状态从8变为其他
elif old_status == 8 and instance.zhuangtai != 8:
# 状态不再是8记录日志即可
# 定时任务执行时会检查状态如果不是8会自动跳过
logger.info(f"订单 {instance.dingdan_id} 状态从8变为{instance.zhuangtai}")
except Exception as e:
# 捕获所有异常,确保不影响订单保存
# 只记录错误,不抛出异常
logger.error(f"信号处理异常(已捕获,不影响订单): {str(e)}")'''
'''from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.conf import settings
import logging
from dingdan.models import Dingdan
from dingdan.tasks import process_expired_order
logger = logging.getLogger(__name__)
@receiver(pre_save, sender=Dingdan)
def handle_order_status_change(sender, instance, **kwargs):
"""
监听订单状态变化
当状态变为8时启动48小时延时任务
当状态从8变为其他时任务执行时会自动跳过无需取消
"""
try:
# 如果是新建订单,没有旧记录,直接返回
if instance.pk is None:
return
# 获取数据库中旧的订单记录
old_instance = Dingdan.objects.get(pk=instance.pk)
# ============ 状态从非8变为8 ============
if old_instance.zhuangtai != 8 and instance.zhuangtai == 8:
# 启动48小时后的延时任务countdown单位
task = process_expired_order.apply_async(
args=[instance.dingdan_id],
countdown=settings.ORDER_EXPIRE_SECONDS, # 172800秒 = 48小时
queue='order_tasks',
priority=9 # 高优先级
)
logger.info(
f"订单 {instance.dingdan_id} 状态变为8已启动48小时延时任务"
f"任务ID: {task.id}"
)
# 记录任务启动成功(可选,可以存储到订单表或日志表)
# ============ 状态从8变为其他 ============
# 我们不需要取消任务因为任务执行时会检查状态是否为8
# 如果不是状态8任务会自动跳过处理
except Dingdan.DoesNotExist:
# 新订单,无需处理
pass
except Exception as e:
logger.error(f"处理订单状态变化信号失败订单ID: {instance.dingdan_id if hasattr(instance, 'dingdan_id') else '未知'}, 错误: {str(e)}")
# 不抛出异常,避免影响订单保存的主流程
# 信号处理失败不影响订单保存,有周期性检查作为备用方案'''

208
dingdan/tasks.py Normal file
View File

@@ -0,0 +1,208 @@
"""
阿龙电竞 - 订单定时任务
处理订单超时自动确认等逻辑
完整版本,包含所有必要的异常处理
"""
from celery import shared_task
from django.db import transaction
from django.db.models import F, Q
from django.conf import settings
from django.utils import timezone
from datetime import timedelta
from decimal import Decimal
import logging
# 导入模型 - 确保路径正确
from dingdan.models import Dingdan, DingdanShangjia
from yonghu.models import UserMain, UserDashou, UserShangjia
from utils.celery_utils import safe_decimal_operation, log_task_execution, rollback_on_failure
logger = logging.getLogger(__name__)
@shared_task(bind=True, max_retries=3, default_retry_delay=60)
def process_expired_order(self, dingdan_id):
"""
处理单个超时订单(订单状态=8超过48小时未处理
"""
try:
# 使用select_for_update锁定记录防止并发修改
with transaction.atomic():
# 获取订单,同时锁定记录
order = Dingdan.objects.select_for_update().get(
dingdan_id=dingdan_id
)
# 其余代码不变...
# ... 保持原有代码
# 再次检查订单状态是否为8
if order.zhuangtai != 8:
logger.info(f"订单{dingdan_id}状态已不是8当前:{order.zhuangtai}),跳过处理")
return f"订单{dingdan_id}状态已变更,跳过处理"
# 获取发单平台类型
fadan_pingtai = order.fadan_pingtai
# 获取打手ID和分成金额
dashou_id = order.jiedan_dashou_id
dashou_fencheng = safe_decimal_operation(order.dashou_fencheng)
# 1. 更新订单状态为3已完成
order.zhuangtai = 3
order.save(update_fields=['zhuangtai'])
# 2. 更新打手信息(如果存在)
updated_dashou = False
if dashou_id:
try:
# 查询打手用户主表
dashou_user = UserMain.objects.filter(yonghuid=dashou_id).first()
if dashou_user:
# 获取打手扩展表
dashou_profile = getattr(dashou_user, 'dashou_profile', None)
if dashou_profile:
# 使用F表达式原子更新
UserDashou.objects.filter(pk=dashou_profile.pk).update(
chengjiaozongliang=F('chengjiaozongliang') + 1,
yue=F('yue') + dashou_fencheng,
zonge=F('zonge') + dashou_fencheng,
jinrishouyi=F('jinrishouyi') + dashou_fencheng,
jinyueshouyi=F('jinyueshouyi') + dashou_fencheng
)
updated_dashou = True
logger.info(f"更新打手{dashou_id}信息成功")
except Exception as e:
logger.error(f"更新打手信息失败打手ID: {dashou_id}, 错误: {str(e)}")
# 继续执行,不中断流程
# 3. 如果是商家发单,更新商家信息
updated_shangjia = False
if fadan_pingtai == 2: # 商家发单
try:
# 获取商家扩展信息
shangjia_kuozhan = getattr(order, 'shangjia_kuozhan', None)
if shangjia_kuozhan:
shangjia_id = shangjia_kuozhan.shangjia_id
if shangjia_id:
# 查询商家用户
shangjia_user = UserMain.objects.filter(yonghuid=shangjia_id).first()
if shangjia_user:
shangjia_profile = getattr(shangjia_user, 'shop_profile', None)
if shangjia_profile:
# 更新商家成交订单数量
UserShangjia.objects.filter(pk=shangjia_profile.pk).update(
chengjiao=F('chengjiao') + 1
)
updated_shangjia = True
logger.info(f"更新商家{shangjia_id}信息成功")
except Exception as e:
logger.error(f"更新商家信息失败订单ID: {dingdan_id}, 错误: {str(e)}")
# 继续执行,不中断流程
# 记录任务执行结果
result_msg = f"订单{dingdan_id}自动结算完成"
if updated_dashou:
result_msg += ",打手信息已更新"
if updated_shangjia:
result_msg += ",商家信息已更新"
log_task_execution(f"自动结算订单 {dingdan_id}", True, result_msg)
return result_msg
except Dingdan.DoesNotExist:
error_msg = f"订单{dingdan_id}不存在"
logger.warning(error_msg)
return error_msg
except Exception as e:
error_msg = f"处理订单{dingdan_id}时发生错误: {str(e)}"
logger.error(error_msg)
# 重试机制
if self.request.retries < self.max_retries:
logger.info(f"订单{dingdan_id}处理失败,准备第{self.request.retries + 1}次重试")
raise self.retry(exc=e)
log_task_execution(f"自动结算订单 {dingdan_id}", False, error_msg)
return error_msg
@shared_task
@rollback_on_failure("批量检查超时订单")
def check_order_expire_task():
"""
批量检查超时订单(补偿机制)
每5分钟执行一次作为信号处理的备用方案
查找状态为8且创建时间超过72小时的订单宽松时间防止误处理
"""
try:
# 计算更宽松的时间点当前时间减去72小时48+24小时
# 这样避免误处理刚变为状态8的订单
check_time = timezone.now() - timedelta(seconds=settings.ORDER_EXPIRE_SECONDS + 86400) # 48+24=72小时
# 查询状态为8且创建时间早于检查时间的订单
expired_orders = Dingdan.objects.filter(
zhuangtai=8,
create_time__lt=check_time
).values_list('dingdan_id', flat=True)
expired_count = expired_orders.count()
if expired_count == 0:
logger.info("补偿检查:无超时订单")
return {"success": True, "message": "无超时订单", "count": 0}
# 分批处理超时订单(避免一次处理太多)
batch_size = 10
processed_count = 0
for i in range(0, expired_count, batch_size):
batch = expired_orders[i:i+batch_size]
# 异步处理每个超时订单
for dingdan_id in batch:
process_expired_order.apply_async(
args=[dingdan_id],
queue='order_tasks',
priority=8 # 补偿任务的优先级低一些
)
processed_count += 1
result_msg = f"补偿检查:发现{expired_count}个可能超时的订单,已提交处理{processed_count}"
log_task_execution("批量检查超时订单", True, result_msg)
return {
"success": True,
"message": result_msg,
"total_count": expired_count,
"processed_count": processed_count
}
except Exception as e:
error_msg = f"批量检查超时订单失败: {str(e)}"
logger.error(error_msg)
log_task_execution("批量检查超时订单", False, error_msg)
return {
"success": False,
"message": error_msg,
"error": str(e)
}

3
dingdan/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

71
dingdan/tongzhi_tasks.py Normal file
View File

@@ -0,0 +1,71 @@
# dingdan/tongzhi_tasks.py
import logging
from concurrent.futures import ThreadPoolExecutor, as_completed
from a_long_dianjing.celery_app import app
from yonghu.models import OfficialAccountUser
from utils.weixin_broadcast import WeixinBroadcastSender
logger = logging.getLogger('weixin_broadcast')
@app.task(bind=True, max_retries=3, default_retry_delay=60)
def dingdan_guangbo(self, order_info):
"""
异步并发广播订单模板消息给所有关注服务号的用户
order_info 字典字段示例:
{
'dingdan_id': 'PT123456',
'game_type': '王者荣耀',
'amount': '88.00',
'order_desc': '星耀上王者'
}
"""
sender = WeixinBroadcastSender()
template_data = sender.build_order_message_data(order_info)
order_id = order_info.get('dingdan_id')
# 查询所有已关注用户
try:
openids = list(
OfficialAccountUser.objects
.filter(is_subscribed=True)
.values_list('official_openid', flat=True)
)
except Exception as e:
logger.error(f'查询订阅用户失败: {e}')
raise self.retry(exc=e)
if not openids:
return {'success': True, 'msg': '无订阅用户'}
total = len(openids)
logger.info(f'📊 Celery 广播订单 {order_id} 开始,目标人数: {total}')
success = 0
fail = 0
# 20 个线程并发发送,微信接口耗时 200-500ms1000 人约 15 秒完成
with ThreadPoolExecutor(max_workers=20) as executor:
future_map = {
executor.submit(sender.send_to_user, openid, template_data, order_id): openid
for openid in openids
}
for future in as_completed(future_map):
openid = future_map[future]
try:
res = future.result(timeout=30)
if res.get('success'):
success += 1
else:
fail += 1
except Exception as e:
fail += 1
logger.error(f'发送异常 {openid[:10]}...: {e}')
logger.info(f'🏁 广播完成:成功 {success},失败 {fail},总计 {total}')
return {
'success': True,
'total': total,
'success_count': success,
'fail_count': fail
}

96
dingdan/urls.py Normal file
View File

@@ -0,0 +1,96 @@
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from .views import CreateOrderView, WechatPayNotifyView, \
PaymentFailView, PaymentVerifyView, DingdanHuoquView, DingdanXiangqingView, JiedanView, \
ShangpinLeixingView, ShangjiaPaifaView, ShangjiaDingdanHuoquView, ShangjiaJiesuanView, \
ShangjiaDingdanXiangqingView, ShangjiaChufaShenqingView, ShangjiaTuikuanShenqingView, \
ShangjiaChexiaoView, DashouDingdanHuoquView, ShangpinLeixingHuoquView, QiangdanView, \
DashouDingdanHuoquView1, DashouCOSZhengshuView, DashouTijiaoView, DashouDingdanXiangqingView, AdGetDingdanXiangQing, \
AdTongYiTuiKuanPingTai, AdTongYiTuiKuanShangJia, AdQiangZhiJieDan, AdJuJueTuiKuan,\
AdGengHuanDaShou,ShangjiaCOSZhengshuView, DashouHuoquLeixingView,AdJuJueJieSuan, AdZhuanYiDaTing, AdQuXiaoZhiDing,PartnerNotifyClaimView, PartnerSyncOrderView, PartnerCheckClaimView, PartnerRefundNotifyView,DashouXiugaiView,VirtualCreateOrderView, VirtualPayNotifyView, VirtualPaymentVerifyView,VirtualPaymentFailView,DaiLiQunLiaoXiaoXiView,\
ShangjiaLianjieLiuYanZhuanFaView, ZxsjghdsView, \
ShangjiaFakuanApplyView, ShangjiaFakuaiXiugaiView
urlpatterns = [
path('xiadan', CreateOrderView.as_view(), name='下单订单生成接口'),
#path('pay-notify/', WechatPayNotifyView.as_view(), name='老板下单微信支付回调'),
path('pay-notify/', csrf_exempt(WechatPayNotifyView.as_view()), name='老板下单微信支付回调'),
path('shibai', PaymentFailView.as_view(), name='老板支付失败接口'),
path('fucha', PaymentVerifyView.as_view(), name='老板支付成功复查接口'),
path('dingdanhuoqu', DingdanHuoquView.as_view(), name='老板订单获取'),
path('dingdanxiangqing', DingdanXiangqingView.as_view(), name='老板订单详情获取'),
path('jiedan', JiedanView.as_view(), name='老板结单'),
path('sjspleixing', ShangpinLeixingView.as_view(), name='派单获取商品类型'),
path('sjpaifa', ShangjiaPaifaView.as_view(), name='商家发单'),
path('sjdingdanhq', ShangjiaDingdanHuoquView.as_view(), name='商家订单获取'),
path('sjddxq', ShangjiaDingdanXiangqingView.as_view(), name='商家订单详情获取'),
path('sjjiesuan', ShangjiaJiesuanView.as_view(), name='商家结单'),
path('sjchexiao', ShangjiaChexiaoView.as_view(), name='商家撤销订单'),
path('sjtkshenqing', ShangjiaTuikuanShenqingView.as_view(), name='商家退款申请'),
path('sjchufa', ShangjiaChufaShenqingView.as_view(), name='商家处罚打手申请'),
#path('ddlxhq', ShangpinLeixingHuoquView.as_view(), name='打手抢单页商品类型获取'),
path('dshqdingdan', DashouDingdanHuoquView1.as_view(), name='打手订单列表页面获取'),
# 获取订单列表
path('ddhq', DashouDingdanHuoquView.as_view(), name='打手抢单页获取订单'),
path('qiangdan', QiangdanView.as_view(), name='打手抢单'),
path('dsscpz', DashouCOSZhengshuView.as_view(), name='打手上传图片OSS参数获取接口'),
# 打手提交订单完成接口
path('dstijiao', DashouTijiaoView.as_view(), name='打手订单提交'),
# 打手订单详情获取接口
path('dsddxq', DashouDingdanXiangqingView.as_view(), name='打手获取订单详情'),
path('adddxq', AdGetDingdanXiangQing.as_view(), name='管理员获取订单详情页面具体信息'),
path('adddpttk', AdTongYiTuiKuanPingTai.as_view(), name='同意平台订单退款'),
# 商家订单退款接口(之前写的)
path('adddsjtk', AdTongYiTuiKuanShangJia.as_view(), name='同意商家退款'),
# 强制结单接口
#path('adddqzjd', AdQiangZhiJieDan.as_view(), name='强制结单'),
# 拒绝退款接口
path('adddjj', AdJuJueTuiKuan.as_view(), name='拒绝退款'),
# 更换打手接口
path('adddgh', AdGengHuanDaShou.as_view(), name='管理更换打手'),
path('sjscpz', ShangjiaCOSZhengshuView.as_view(), name='商家上传证据图片获取密钥'),
path('dsqdhqddlx', DashouHuoquLeixingView.as_view(), name='打手抢单页面获取订单类型'),
path('adddjjjs', AdJuJueJieSuan.as_view(), name='管理员拒绝给打手钱'),
path('adddzydt', AdZhuanYiDaTing.as_view(), name='订单转移大厅'),
path('adddqxzd', AdQuXiaoZhiDing.as_view(), name='取消指定'),
path('partner_sync_order', csrf_exempt(PartnerSyncOrderView.as_view()), name='东道主派单接口'),
path('partner_check_claim', csrf_exempt(PartnerCheckClaimView.as_view()), name='对方抢单检查接口'),
path('partner_notify_claim', csrf_exempt(PartnerNotifyClaimView.as_view()), name='东道主订单被抢通知接口'),
#path('partner_refund_notify', csrf_exempt(PartnerRefundNotifyView.as_view()), name='接受东道主退款通知'),
path('dsxiugaidd', DashouXiugaiView.as_view(), name='打手修改订单详情'),
path('kptxxfs', DaiLiQunLiaoXiaoXiView.as_view(), name='前端聊天转发'), # 群聊消息代理发送
path('virtual_xiadan', VirtualCreateOrderView.as_view(),name='虚拟支付下单'),
path('virtual_notify', VirtualPayNotifyView.as_view(),name='虚拟支付下单回调'),
path('virtual_fucha', VirtualPaymentVerifyView.as_view(),name='虚拟支付下单成功复查'),
path('shibai', VirtualPaymentFailView.as_view(),name='虚拟支付下单失败'), # 或复用原 PaymentFailView
path('sjljlbxxzf', ShangjiaLianjieLiuYanZhuanFaView.as_view(), name='商家链接老板聊天转发'),
path('zxsjghds', ZxsjghdsView.as_view(), name='商家更换打手'), # 商家更换打手
path('sjfksq', ShangjiaFakuanApplyView.as_view(), name='商家罚款'),
path('sjfkxgycx', ShangjiaFakuaiXiugaiView.as_view(), name='商家罚款和退款修改'),
]

442
dingdan/utils.py Normal file
View File

@@ -0,0 +1,442 @@
import threading
import requests
from django.conf import settings
from peizhi.models import Club
from shangpin.models import ShangpinLeixing
from dingdan.models import Dingdan # 根据实际路径导入
import logging
from datetime import date
from django.db import transaction
from django.db.models import F
from peizhi.models import DailyDispatchStat # 假设模型在 peizhi 应用中
logger = logging.getLogger(__name__)
# 可选:线程池限制(避免大量线程同时创建,建议使用 Celery这里简单用线程
THREAD_POOL_SIZE = 10
_semaphore = threading.Semaphore(THREAD_POOL_SIZE)
def sync_order_to_partners(dingdan_id):
"""
异步向所有开启互通的合作平台同步订单。
使用信号量限制并发线程数。
"""
def _task():
_semaphore.acquire()
try:
_sync_order_task(dingdan_id)
finally:
_semaphore.release()
thread = threading.Thread(target=_task)
thread.daemon = True
thread.start()
def _sync_order_task(dingdan_id):
"""实际同步任务(在线程中执行)"""
try:
# 获取订单对象(只取必要字段,提升性能)
dingdan = Dingdan.objects.only(
'dingdan_id', 'zhuangtai', 'jine', 'dashou_fencheng', 'jieshao',
'beizhu', 'nicheng', 'leixing_id', 'yaoqiuleixing', 'huiyuan_id',
'yongjin', 'zhiding_id', 'create_time'
).get(dingdan_id=dingdan_id)
# 基本条件判断
if dingdan.zhuangtai != 1:
logger.info(f"订单 {dingdan_id} 状态 {dingdan.zhuangtai} 不是1不同步")
return
if dingdan.zhiding_id:
logger.info(f"订单 {dingdan_id} 是指定单,不同步")
return
if dingdan.yaoqiuleixing != 1:
logger.info(f"订单 {dingdan_id} 抢单要求类型不是会员抢单,不同步")
return
if not dingdan.leixing_id:
logger.info(f"订单 {dingdan_id} 无商品类型,不同步")
return
try:
leixing = ShangpinLeixing.objects.get(id=dingdan.leixing_id)
if not leixing.is_cross_enabled:
logger.info(f"订单 {dingdan_id} 的商品类型未开启互通,不同步")
return
except ShangpinLeixing.DoesNotExist:
logger.info(f"订单 {dingdan_id} 的商品类型不存在,不同步")
return
# 查询所有开启互通的俱乐部
clubs = Club.objects.filter(is_interop_enabled=True).select_related()
if not clubs.exists():
return
# 为每个俱乐部发送订单
for club in clubs:
_send_to_single_partner(dingdan, club)
except Exception as e:
logger.error(f"同步订单任务异常: {e}", exc_info=True)
def _send_to_single_partner(dingdan, club):
"""向单个俱乐部发送订单(带重试,幂等处理)"""
# 计算实际金额:订单打手分成 × 对方费率
actual_amount = dingdan.dashou_fencheng * club.dashou_rate
# 构建请求数据
payload = {
'token': settings.CROSS_PLATFORM_TOKEN,
'our_club_id': club.club_id, # 我方在对方系统中的标识(存储于对方表的 partner_club_id
'partner_club_id': club.partner_club_id, # 对方自己的俱乐部ID
'partner_order_id': dingdan.dingdan_id, # 我方订单ID作为对方的外部订单号
'jine': str(actual_amount), # 对方平台应展示的订单金额
'dashou_fencheng': str(actual_amount), # 对方平台打手分成(与金额一致)
'jieshao': dingdan.jieshao,
'beizhu': dingdan.beizhu,
'create_time': dingdan.create_time.isoformat(),
'nicheng': dingdan.nicheng,
'leixing_id': dingdan.leixing_id, # 我方商品类型ID对方需要映射
'user_id': get_order_user_id(dingdan), # 对方平台下单用户ID不带前缀
}
# 重试机制最多3次指数退避
for attempt in range(1, 4):
try:
response = requests.post(
club.partner_domain + '/dingdan/partner_sync_order',
json=payload,
timeout=5
)
if response.status_code == 200:
data = response.json()
# 对方返回 code=0 表示成功(包括新建或已存在)
if data.get('code') == 0:
# 判断本次响应是新创建还是已存在
status = data.get('data', {}).get('status', '')
if status == 'existed':
# 订单已经存在于对方系统,不重复统计
logger.info(f"订单 {dingdan.dingdan_id} 在俱乐部 {club.club_id} 已存在,跳过统计")
else:
# 新创建成功,更新统计
try:
update_daily_dispatch_stat(
direction=1, # 我方派单
partner_club_id=club.partner_club_id,
dispatch_amount=actual_amount,
)
logger.info(f"成功同步订单 {dingdan.dingdan_id} 到俱乐部 {club.club_id}")
except Exception as e:
logger.error(f"更新派单统计失败: {e}", exc_info=True)
# 标记订单为跨平台(仅当第一次成功时标记,避免重复标记)
if not dingdan.is_cross:
Dingdan.objects.filter(dingdan_id=dingdan.dingdan_id).update(
is_cross=1,
dispatch_type=1 # 我方派单
)
logger.info(f"订单 {dingdan.dingdan_id} 已标记为跨平台订单")
break
else:
# 对方返回业务错误(如映射不存在等),不重试
logger.error(f"同步订单失败(业务): {data}")
break
else:
logger.error(f"同步订单HTTP失败: {response.status_code}")
except Exception as e:
logger.error(f"同步订单异常(尝试 {attempt}/3: {e}")
if attempt < 3:
import time
time.sleep(2 ** attempt) # 指数退避
else:
logger.error(f"同步订单 {dingdan.dingdan_id} 到俱乐部 {club.club_id} 最终失败")
# 获取下单方ID根据订单类型
def get_order_user_id(order):
from dingdan.models import DingdanPingtai, DingdanShangjia
if order.fadan_pingtai == 1:
try:
ext = DingdanPingtai.objects.get(dingdan=order)
return ext.laoban_id # 老板ID
except DingdanPingtai.DoesNotExist:
return None
elif order.fadan_pingtai == 2:
try:
ext = DingdanShangjia.objects.get(dingdan=order)
return ext.shangjia_id # 商家ID
except DingdanShangjia.DoesNotExist:
return None
return None
# dingdan/utils/dispatch_stat.py
import logging
import logging
from datetime import date
from decimal import Decimal
from django.db import transaction
from django.db.models import F
from peizhi.models import DailyDispatchStat # 请根据实际模型位置修改导入路径
logger = logging.getLogger(__name__)
def update_daily_dispatch_stat(direction, partner_club_id,
dispatch_amount=None, dispatch_count=1,
claimed_amount=None, claimed_count=1,
success_amount=None, success_count=1):
"""
原子更新每日派单统计(支持派单、抢单、成交三种类型)。
只更新传递了非None参数的字段未传递的字段保持不变。
参数:
direction: 1=我方派单2=对方派单
partner_club_id: 对方俱乐部ID
dispatch_amount: 派单金额Decimal如果提供则累加到 dispatch_amount 和 dispatch_count
dispatch_count: 派单数量默认为1与 dispatch_amount 同时提供时生效
claimed_amount: 抢单金额Decimal如果提供则累加到 claimed_amount 和 claimed_count
claimed_count: 抢单数量默认为1与 claimed_amount 同时提供时生效
success_amount: 成交金额Decimal如果提供则累加到 success_amount 和 success_count
success_count: 成交数量默认为1与 success_amount 同时提供时生效
"""
today = date.today()
year, month, day = today.year, today.month, today.day
with transaction.atomic():
# 使用 select_for_update 锁定行,避免并发累加冲突
stat, created = DailyDispatchStat.objects.select_for_update().get_or_create(
date=today,
year=year,
month=month,
day=day,
direction=direction,
partner_club_id=partner_club_id,
defaults={
'dispatch_count': dispatch_count if dispatch_amount is not None else 0,
'dispatch_amount': dispatch_amount or Decimal('0.00'),
'claimed_count': claimed_count if claimed_amount is not None else 0,
'claimed_amount': claimed_amount or Decimal('0.00'),
'success_count': success_count if success_amount is not None else 0,
'success_amount': success_amount or Decimal('0.00'),
}
)
if not created:
update_fields = []
if dispatch_amount is not None:
stat.dispatch_count = F('dispatch_count') + dispatch_count
stat.dispatch_amount = F('dispatch_amount') + dispatch_amount
update_fields.extend(['dispatch_count', 'dispatch_amount'])
if claimed_amount is not None:
stat.claimed_count = F('claimed_count') + claimed_count
stat.claimed_amount = F('claimed_amount') + claimed_amount
update_fields.extend(['claimed_count', 'claimed_amount'])
if success_amount is not None:
stat.success_count = F('success_count') + success_count
stat.success_amount = F('success_amount') + success_amount
update_fields.extend(['success_count', 'success_amount'])
if update_fields:
stat.save(update_fields=update_fields)
logger.info(f"更新派单统计: 日期={today}, 方向={direction}, 俱乐部={partner_club_id}, "
f"派单+{dispatch_count if dispatch_amount else 0}单/{dispatch_amount or 0}, "
f"抢单+{claimed_count if claimed_amount else 0}单/{claimed_amount or 0}, "
f"成交+{success_count if success_amount else 0}单/{success_amount or 0}")
from peizhi.models import DailyIncomeStat
logger = logging.getLogger(__name__)
def update_daily_income(amount):
"""
原子更新当日收入统计金额累加笔数加1
用于微信支付成功回调。
参数:
amount: Decimal 本次收入金额
"""
today = date.today()
year, month, day = today.year, today.month, today.day
with transaction.atomic():
stat, created = DailyIncomeStat.objects.select_for_update().get_or_create(
date=today,
defaults={
'year': year,
'month': month,
'day': day,
'total_amount': amount,
'total_count': 1
}
)
if not created:
# 原子累加
stat.total_amount = F('total_amount') + amount
stat.total_count = F('total_count') + 1
stat.save(update_fields=['total_amount', 'total_count'])
logger.info(
f"每日收入更新: {today}, +{amount}元, 总金额={stat.total_amount if created else stat.total_amount + amount}, 总笔数={stat.total_count if created else stat.total_count + 1}")
from peizhi.models import DailyPayoutStat
logger = logging.getLogger(__name__)
def update_daily_payout(amount):
"""
原子更新当日出款统计金额累加笔数加1
用于提现成功、结算打款等场景。
参数:
amount: Decimal 本次出款金额
"""
today = date.today()
year, month, day = today.year, today.month, today.day
with transaction.atomic():
stat, created = DailyPayoutStat.objects.select_for_update().get_or_create(
date=today,
defaults={
'year': year,
'month': month,
'day': day,
'total_amount': amount,
'total_count': 1
}
)
if not created:
# 原子累加
stat.total_amount = F('total_amount') + amount
stat.total_count = F('total_count') + 1
stat.save(update_fields=['total_amount', 'total_count'])
logger.info(f"每日出款更新: {today}, +{amount}元, 总金额={stat.total_amount if created else stat.total_amount + amount}, 总笔数={stat.total_count if created else stat.total_count + 1}")
from decimal import Decimal
from dingdan.models import Lilubiao
def calc_shangjia_order_fencheng(jine):
"""
商家发单时计算打手/管事分成。
打手优先:打手+管事 > 订单金额时,管事分成为 0。
"""
jine = Decimal(str(jine))
try:
lilu_obj = Lilubiao.objects.get(fadanpingtai='3')
rate_dashou = Decimal(str(lilu_obj.lilu)) if lilu_obj.lilu and lilu_obj.lilu > 0 else Decimal('1')
except Lilubiao.DoesNotExist:
rate_dashou = Decimal('1')
lilu_guanshi_obj = Lilubiao.objects.filter(fadanpingtai='13').first()
rate_guanshi = (
Decimal(str(lilu_guanshi_obj.lilu))
if lilu_guanshi_obj and lilu_guanshi_obj.lilu is not None
else Decimal('0')
)
dashou_fencheng = (jine * rate_dashou).quantize(Decimal('0.01'))
guanshi_raw = (jine * rate_guanshi).quantize(Decimal('0.01'))
if dashou_fencheng + guanshi_raw > jine:
guanshi_fencheng = Decimal('0.00')
else:
guanshi_fencheng = guanshi_raw
return dashou_fencheng, guanshi_fencheng
def settle_shangjia_order_guanshi_fenhong(order, dashou_id):
"""
商家订单结单时结算管事分红(幂等,失败不抛异常阻断主流程)。
"""
from shangpin.models import Gsfenhong
from yonghu.models import UserDashou, UserGuanshi
if getattr(order, 'fadan_pingtai', None) != 2:
return
guanshi_fencheng = order.guanshi_fencheng or Decimal('0')
if guanshi_fencheng <= 0:
return
if Gsfenhong.objects.filter(dingdan_id=order.dingdan_id).exists():
logger.info(f"商家订单管事分红已处理: {order.dingdan_id}")
return
if not dashou_id:
return
try:
dashou = UserDashou.objects.select_related('user').get(user__yonghuid=dashou_id)
except UserDashou.DoesNotExist:
logger.info(f"商家订单管事分红跳过: 打手{dashou_id}不存在")
return
guanshi_id = dashou.yaoqingren
if not guanshi_id:
logger.info(f"商家订单管事分红跳过: 打手{dashou_id}无邀请管事")
return
try:
with transaction.atomic():
guanshi = UserGuanshi.objects.select_for_update().get(user__yonghuid=guanshi_id)
UserGuanshi.objects.filter(id=guanshi.id).update(
yue=F('yue') + guanshi_fencheng,
chongzhifenrun=F('chongzhifenrun') + guanshi_fencheng,
)
user_main = dashou.user
Gsfenhong.objects.create(
dingdan_id=order.dingdan_id,
guanshi=guanshi_id,
dashouid=dashou_id,
shuoming='商家订单分红',
fenhong=guanshi_fencheng,
avatar=user_main.avatar if user_main else None,
nicheng=dashou.nicheng or '未知打手',
fenhong_leixing=3,
)
logger.info(
f"商家订单管事分红成功: 订单{order.dingdan_id}, 管事{guanshi_id}, "
f"打手{dashou_id}, 金额{guanshi_fencheng}"
)
except UserGuanshi.DoesNotExist:
logger.warning(f"商家订单管事分红跳过: 管事{guanshi_id}不存在")
return
except Exception as e:
logger.error(f"商家订单管事分红失败: {e}", exc_info=True)
return
try:
from houtai.utils import update_guanshi_daily_by_action
update_guanshi_daily_by_action(
yonghuid=guanshi_id,
action=3,
amount=guanshi_fencheng,
)
except Exception as e:
logger.error(f"商家订单管事日统计更新失败: {e}")

9292
dingdan/views.py Normal file

File diff suppressed because it is too large Load Diff