累死了,删除了所有跨平台逻辑,进行了表迁移

This commit is contained in:
2026-06-15 02:09:51 +08:00
parent 8b9dbcba6f
commit 9eb53ee57d
112 changed files with 468 additions and 6208 deletions

View File

@@ -301,19 +301,7 @@ MONTHLY_TASK_HOUR = 0
MONTHLY_TASK_MINUTE = 0
ORDER_CHECK_INTERVAL = 5
# ==================== 跨平台订单互通 ====================
CROSS_PLATFORM_TOKEN = app_secrets.CROSS_PLATFORM_TOKEN
CROSS_PLATFORM_SYNC_TOKEN = app_secrets.CROSS_PLATFORM_SYNC_TOKEN
PARTNER_BASE_URL = app_secrets.PARTNER_BASE_URL
PARTNER_SYNC_ORDER_URL = '/dingdan/partner_sync_order'
PARTNER_CHECK_CLAIM_URL = '/dingdan/partner_check_claim'
PARTNER_NOTIFY_CLAIM_URL = '/dingdan/partner_notify_claim'
PARTNER_REFUND_NOTIFY_URL = '/dingdan/partner_refund_notify'
AGENT_SHANGJIA_ID = app_secrets.AGENT_SHANGJIA_ID
CROSS_PLATFORM_MEMBER_ID = app_secrets.CROSS_PLATFORM_MEMBER_ID
CROSS_PLATFORM_GAME_TYPE_ID = 1
CROSS_PLATFORM_WHITELIST = app_secrets.CROSS_PLATFORM_WHITELIST
SPECIAL_GUANSHI_IDS = app_secrets.SPECIAL_GUANSHI_IDS
# ==================== 微信支付 V3 ====================
WECHAT_PAY_V3_CONFIG = {

View File

@@ -215,7 +215,7 @@ class Migration(migrations.Migration):
"role",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="houtai.role",
to="backend.role",
verbose_name="角色",
),
),
@@ -238,7 +238,7 @@ class Migration(migrations.Migration):
"permission",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="houtai.permission",
to="backend.permission",
verbose_name="权限",
),
),
@@ -246,7 +246,7 @@ class Migration(migrations.Migration):
"role",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="houtai.role",
to="backend.role",
verbose_name="角色",
),
),

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("houtai", "0001_initial"),
("backend", "0001_initial"),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("houtai", "0002_zuzhangritongji_shangjiaritongji_and_more"),
("backend", "0002_zuzhangritongji_shangjiaritongji_and_more"),
]
operations = [

View File

@@ -0,0 +1,34 @@
# Generated by Django 4.2.27 on 2026-06-15 01:42
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('backend', '0003_tixianritongji'),
]
operations = [
migrations.AlterField(
model_name='rolepermission',
name='permission',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='backend.permission', verbose_name='权限'),
),
migrations.AlterField(
model_name='rolepermission',
name='role',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='backend.role', verbose_name='角色'),
),
migrations.AlterField(
model_name='tixianritongji',
name='leixing',
field=models.IntegerField(choices=[(1, '打手'), (2, '管事'), (3, '组长'), (4, '考核官'), (5, '打手押金'), (6, '商家余额')], verbose_name='用户类型'),
),
migrations.AlterField(
model_name='userrole',
name='role',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='backend.role', verbose_name='角色'),
),
]

View File

@@ -1,11 +1,7 @@
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from .view import (GetClubConfigView, GetCrossOrderListView, PartnerGetOrderDataView,PartnerRefundNotifyView,
CrossPlatformRefundView, GetCrossOrderDetailView, CrossPlatformForceCompleteView, CrossPlatformTransferHallView,
PartnerTransferHallNotifyView, GetSettingsView, UpdateSettingsView, GetMappingsView, UpdateMappingsView,
PartnerUpdateSelfConfigView, GetPartnerClubsView, GetStatsView, PunishDashouView, PartnerPunishNotifyView,
GetClubConfigForPreSettlementView, PreSettlementActionView, GetPreSettlementDataView, GetRolePermissionView,
from .view import (GetRolePermissionView,
ModifyRolePermissionView, AddRoleView, GetAdminRolesView, GetAdminUserListView, AddAdminUserView,
ModifyAdminUserView, KefuGetDashouListView, KefuGetDashouDetailView, KefuUpdateDashouView, KefuGetShangjiaListView,
KefuGetShangjiaDetailView, KefuUpdateShangjiaView, GetProductBaseDataView, GetProductListView, SaveProductOrderView,
@@ -15,34 +11,11 @@ from .view import (GetClubConfigView, GetCrossOrderListView, PartnerGetOrderData
ModifyProductTypeZoneView, GetRateView, ModifyRateView, PopupNoticeListAPIView, PopupNoticeModifyAPIView,ShopListView,
ShopModifyView, ShopPublicTypeAndAuditView, ShopListForProductView, ShopProductModifyView,
ShopProductTypeMappingView, ProductListView, ProductModifyView, KefuChatPermissionsView,
PartnerFineNotifyView,FineApplyView, FaKuanTongJiView, FaKuanLieBiaoView, FaKuanChuLiView, FaKuanChuangJianView,
FaKuanTongJiView, FaKuanLieBiaoView, FaKuanChuLiView, FaKuanChuangJianView,
HqbkxxView,BkxgView,CaiwuView,CwhybkhqView, HybkjtsjView, SzxxView, CwddhqlxView, CwhqjtddsjView,
CwqtczhqView, KhpzhqView, ChzsgcView,KhgglView, ShgxgsjView, ZxkfghdsView, KptxwztjbView)
CwqtczhqView, KhpzhqView, ChzsgcView,KhgglView, ShgxgsjView, ZxkfghdsView)
urlpatterns = [
path('kpthq', GetClubConfigView.as_view(), name='跨平台订单页面获取俱乐部数据'),
path('hqddlb', GetCrossOrderListView.as_view(), name='获取跨平台订单'),
path('kpthqtp',csrf_exempt(PartnerGetOrderDataView.as_view()), name='跨平台接受对方服务器获取订单数据'),
# 对方平台退款通知接口
path('dfddtk', csrf_exempt(PartnerRefundNotifyView.as_view()), name='跨平台接受对方服务器更新订单状态'),
path('kptk', CrossPlatformRefundView.as_view(), name='跨平台订单退款'),
path('hqkptddxq', GetCrossOrderDetailView.as_view(), name='获取跨平台订单数据详情'),
path('kpqzjd', CrossPlatformForceCompleteView.as_view(), name='跨平台订单结算'),
path('kpzydt', CrossPlatformTransferHallView.as_view(), name='跨平台转移大厅'),
path('kpttzzydt', csrf_exempt(PartnerTransferHallNotifyView.as_view()), name='跨平台接受对方转移大厅通知'),
path('hqkptsz', GetSettingsView.as_view(), name='获取俱乐部数据信息'),
path('xgjlbsj', UpdateSettingsView.as_view(), name='更新俱乐部数据信息'),
path('hqqtjlbsj', GetMappingsView.as_view(), name='获取俱乐部订单类型映射'),
path('xgdfddys', UpdateMappingsView.as_view(), name='工薪俱乐部订单类型映射'),
path('xgzjsjcs', csrf_exempt(PartnerUpdateSelfConfigView.as_view()), name='partner_update_self_config'),
path('kpthqpt', GetPartnerClubsView.as_view(), name='前端获取俱乐部数据展示派发数据'),
path('hqpfsj', GetStatsView.as_view(), name='前端派发统计表获取'),
path('kpcf', PunishDashouView.as_view(), name='跨平台处罚打手'),
path('kptcfds', PartnerPunishNotifyView.as_view(), name='接受跨平台对方平台处罚申请'),
path('hqkttjsyjs', GetClubConfigForPreSettlementView.as_view(), name='预处理获取俱乐部数据'),
path('hqyjssj', GetPreSettlementDataView.as_view(), name='获取预处理数据'),
path('yjsjjhdk', PreSettlementActionView.as_view(), name='操作预处理'),
path('gljshq', GetRolePermissionView.as_view(), name='获取就角色信息'),
path('sctjjsnr', ModifyRolePermissionView.as_view(), name='修改角色数据'),
path('tjjs', AddRoleView.as_view(), name='添加角色'),
@@ -101,9 +74,6 @@ urlpatterns = [
path('kfhqltqx', KefuChatPermissionsView.as_view(), name='后台获取客服聊天配置'),
path('kffkdssq', FineApplyView.as_view(), name='跨平台处罚罚款申请接口'),
path('kffkdssq_notify', PartnerFineNotifyView.as_view(), name='跨屏要对方平台处罚通知接口'),
path('htglyhqcfsltj', FaKuanTongJiView.as_view(),name='后台罚单统计图片'), # 罚款统计
path('hthqfklb', FaKuanLieBiaoView.as_view(),name='后台罚单列表'), # 罚款列表
@@ -130,8 +100,6 @@ urlpatterns = [
path('zxkfghds', ZxkfghdsView.as_view(), name='链接换打手或重新下单'),
path('kptxwztjb', csrf_exempt(KptxwztjbView.as_view()), name='跨平台脚本询问订单状态'),
]

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('peizhi', '0001_initial'),
('config', '0001_initial'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('peizhi', '0002_shangjiamoban_shangjialianjie'),
('config', '0002_shangjiamoban_shangjialianjie'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('peizhi', '0003_tupianpeizhi_fangwen_cishu'),
('config', '0003_tupianpeizhi_fangwen_cishu'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('peizhi', '0004_tixianquotadefault'),
('config', '0004_tixianquotadefault'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('peizhi', '0005_ordertypemapping_dailydispatchstat_club'),
('config', '0005_ordertypemapping_dailydispatchstat_club'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('peizhi', '0006_clubconfig_accountpermission'),
('config', '0006_clubconfig_accountpermission'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('peizhi', '0007_club_receive_rate_dailydispatchstat_claimed_amount_and_more'),
('config', '0007_club_receive_rate_dailydispatchstat_claimed_amount_and_more'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('peizhi', '0008_clubconfig_storage_bucket_name'),
('config', '0008_clubconfig_storage_bucket_name'),
]
operations = [

View File

@@ -7,7 +7,7 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('peizhi', '0009_dailypayoutstat_dailyincomestat'),
('config', '0009_dailypayoutstat_dailyincomestat'),
]
operations = [
@@ -63,7 +63,7 @@ class Migration(migrations.Migration):
('text', models.TextField(blank=True, verbose_name='图片上方文字')),
('sort_order', models.PositiveIntegerField(default=0, verbose_name='展示顺序')),
('created_at', models.DateTimeField(auto_now_add=True)),
('popup_config', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='images', to='peizhi.popupconfig')),
('popup_config', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='images', to='config.popupconfig')),
],
options={
'verbose_name': '弹窗图片',
@@ -75,7 +75,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='popupconfig',
name='page',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='popups', to='peizhi.popuppage'),
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='popups', to='config.popuppage'),
),
migrations.AlterUniqueTogether(
name='popupconfig',

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('peizhi', '0010_popupconfig_popuppage_popupimage_popupconfig_page_and_more'),
('config', '0010_popupconfig_popuppage_popupimage_popupconfig_page_and_more'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('peizhi', '0011_withdrawconfig'),
('config', '0011_withdrawconfig'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('peizhi', '0012_shangjiamoban_chenghao_id_and_more'),
('config', '0012_shangjiamoban_chenghao_id_and_more'),
]
operations = [

View File

@@ -0,0 +1,30 @@
# Generated by Django 4.2.27 on 2026-06-15 01:42
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('config', '0013_shangjialianjie_previous_dingdan_id_and_more'),
]
operations = [
migrations.DeleteModel(
name='Club',
),
migrations.DeleteModel(
name='ClubConfig',
),
migrations.DeleteModel(
name='DailyDispatchStat',
),
migrations.DeleteModel(
name='OrderTypeMapping',
),
migrations.AlterField(
model_name='tixianquotadefault',
name='leixing',
field=models.IntegerField(choices=[(1, '打手'), (2, '管事'), (3, '组长'), (4, '考核官'), (5, '打手押金'), (6, '商家余额')], unique=True, verbose_name='用户类型'),
),
]

View File

@@ -270,112 +270,6 @@ class WithdrawConfig(models.Model):
class Club(models.Model):
"""合作俱乐部/平台信息表"""
# 自己的俱乐部ID6位字符
club_id = models.CharField(max_length=6, db_index=True, verbose_name='本俱乐部ID')
# 对方的俱乐部ID6位字符
partner_club_id = models.CharField(max_length=6, unique= True,verbose_name='对方俱乐部ID')
# 是否开启平台互通(双方互相同意才可传递订单)
is_interop_enabled = models.BooleanField(default=False, verbose_name='是否开启平台互通')
# 是否同意接收对方订单(对方同意我方发单,但接收订单需我方同意)
is_receive_enabled = models.BooleanField(default=False, verbose_name='是否同意接收对方订单')
# 打手分红费率默认100%,即原金额,对方平台打手分成 = 我方打手分成 × 费率)
dashou_rate = models.DecimalField(max_digits=5, decimal_places=4, default=1.0000, verbose_name='打手分红费率')
# 新增字段接收对方订单时打手分红费率默认100%
receive_rate = models.DecimalField(max_digits=5, decimal_places=4, default=1.0000, verbose_name='接收打手分红费率')
# 对方服务器域名(完整 URL如 https://api.partner.com
partner_domain = models.URLField(max_length=200, 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 = 'club'
verbose_name = '俱乐部'
verbose_name_plural = '俱乐部'
indexes = [
models.Index(fields=['club_id']),
models.Index(fields=['partner_club_id']),
]
class OrderTypeMapping(models.Model):
"""对方订单类型 → 我方订单类型 映射表"""
partner_club_id = models.CharField(max_length=6, db_index=True, verbose_name='对方俱乐部ID')
partner_type_id = models.PositiveIntegerField(verbose_name='对方订单类型ID')
partner_type_name = models.CharField(max_length=100, verbose_name='对方订单类型名称')
our_type_id = models.PositiveIntegerField(verbose_name='我方订单类型ID')
our_type_name = models.CharField(max_length=100, 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 = 'order_type_mapping'
verbose_name = '订单类型映射'
verbose_name_plural = '订单类型映射'
unique_together = (('partner_club_id', 'partner_type_id'),)
class ClubConfig(models.Model):
"""
俱乐部配置信息表
存储俱乐部我方或对方的详细配置如昵称、头像、API密钥等
"""
# 俱乐部ID6位字符与 Club 表中的 club_id 或 partner_club_id 对应)
club_id = models.CharField(max_length=6, db_index=True, verbose_name='俱乐部ID')
# 俱乐部昵称
club_nickname = models.CharField(max_length=50, blank=True, default='', verbose_name='俱乐部昵称')
# 俱乐部头像地址URL
club_avatar = models.CharField(max_length=500, blank=True, default='', verbose_name='俱乐部头像地址')
# 俱乐部后台域名用于API请求
backend_domain = models.CharField(max_length=200, blank=True, default='', verbose_name='后台域名')
# 聊天API密钥
chat_api_key = models.CharField(max_length=200, blank=True, default='', verbose_name='聊天API密钥')
# 聊天API ID
chat_api_id = models.CharField(max_length=200, blank=True, default='', verbose_name='聊天API ID')
# 客服路径
customer_service_api_url = models.CharField(max_length=200, blank=True, default='', verbose_name='客服API URL')
customer_service_corp_id = models.CharField(max_length=100, blank=True, default='', verbose_name='客服企业ID')
# 存储桶域名如腾讯云COS、阿里云OSS的访问域名
storage_bucket_domain = models.CharField(max_length=500, blank=True, default='', verbose_name='存储桶域名')
storage_bucket_name = models.CharField(max_length=100, blank=True, default='', verbose_name='存储桶名称')
# 标识是我方还是对方俱乐部1=我方0=对方默认0
is_self = models.SmallIntegerField(
choices=((0, '对方'), (1, '我方')),
default=0,
db_index=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 = 'club_config'
verbose_name = '俱乐部配置'
verbose_name_plural = '俱乐部配置'
# 联合唯一约束同一个俱乐部ID只能有一条记录无论我方对方若需要分开则可不加
# 但通常一个俱乐部只会存在一种身份,所以加联合唯一约束更安全
unique_together = [['club_id']] # 确保每个club_id只有一条配置记录
def __str__(self):
return f"{self.club_nickname or self.club_id} ({'我方' if self.is_self else '对方'})"
class AccountPermission(models.Model):
"""账号权限表:记录每个账号拥有的权限及开关状态"""
account_id = models.CharField(max_length=11, db_index=True, verbose_name='账号ID')
@@ -396,52 +290,6 @@ class AccountPermission(models.Model):
# apps/dingdan/models.py (添加新模型)
class DailyDispatchStat(models.Model):
"""
每日派单统计表
记录每天向各合作俱乐部派单的数据,用于替代俱乐部表中的累计字段。
"""
# 日期相关字段(便于快速筛选)
date = models.DateField(verbose_name='统计日期', db_index=True)
year = models.PositiveSmallIntegerField(verbose_name='年份')
month = models.PositiveSmallIntegerField(verbose_name='月份')
day = models.PositiveSmallIntegerField(verbose_name='日期')
# 派单方向1=我方派单我方订单被对方抢单2=对方派单(对方订单被我方抢单)
direction = models.PositiveSmallIntegerField(choices=[(1, '我方派单'), (2, '对方派单')], verbose_name='派单方向')
# 对方俱乐部ID
partner_club_id = models.CharField(max_length=6, db_index=True, verbose_name='对方俱乐部ID')
# 派单数
dispatch_count = models.PositiveIntegerField(default=0, verbose_name='派单数')
# 派单总额(打手分成 * 费率)
dispatch_amount = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='派单总额')
# 抢单统计(我方实际抢到的对方派单数/金额)
claimed_count = models.PositiveIntegerField(default=0, verbose_name='抢单数')
claimed_amount = models.DecimalField(max_digits=12, decimal_places=2, default=0.00, verbose_name='抢单总额')
# 成交订单数(预留,当前暂不更新)
success_count = models.PositiveIntegerField(default=0, verbose_name='成交订单数')
# 成交总额(预留)
success_amount = models.DecimalField(max_digits=12, 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 = 'daily_dispatch_stat'
verbose_name = '每日派单统计'
verbose_name_plural = verbose_name
indexes = [
models.Index(fields=['year', 'month', 'day', 'direction', 'partner_club_id']),
models.Index(fields=['date']),
]
def __str__(self):
return f"{self.date} - 方向{self.direction} - 俱乐部{self.partner_club_id} - 派单{self.dispatch_count}"
# apps/dingdan/models.py (新增模型)
class DailyIncomeStat(models.Model):

View File

@@ -29,10 +29,9 @@ from utils.weixin_broadcast import WeixinBroadcastSender
from utils.invitationcode_utils import CreateInvitationCode, VerifyInvitationCode
from backend.utils import update_shangjia_daily
from orders.utils import sync_order_to_partners
from .models import (
Gonggao, Lunbo, ClubConfig, Tupianpeizhi, Qunpeizhi,
Gonggao, Lunbo, Tupianpeizhi, Qunpeizhi,
ShangjiaMoban, ShangjiaLianjie, PopupPage, PopupConfig, WithdrawConfig
)
@@ -63,49 +62,19 @@ class GetDynamicConfigView(APIView):
def post(self, request):
try:
# 查询我方俱乐部配置is_self=1取第一条通常只有一条
club_config = ClubConfig.objects.filter(is_self=1).only(
'storage_bucket_domain',
'storage_bucket_name',
'chat_api_key',
'customer_service_api_url',
'customer_service_corp_id'
).first()
# 默认值(防止空数据导致前端报错)
cos_bucket = ''
cos_region = 'ap-shanghai'
cos_oss_url = ''
# 从 settings 获取配置
cos_oss_url = getattr(settings, 'COS_DOMAIN', '')
if cos_oss_url and not cos_oss_url.endswith('/'):
cos_oss_url += '/'
cos_bucket = getattr(settings, 'COS_BUCKET', '')
cos_region = getattr(settings, 'COS_REGION', 'ap-shanghai')
goeasy_host = 'hangzhou.goeasy.io'
goeasy_appkey = ''
kefu_link = ''
kefu_enterprise_id = ''
goeasy_appkey = getattr(settings, 'GOEASY_APPKEY', '')
kefu_link = getattr(settings, 'KEFU_LINK', '')
kefu_enterprise_id = getattr(settings, 'KEFU_ENTERPRISE_ID', '')
morentouxiang = 'beijing/morentouxiang.jpg'
dashouguize = 'a_long/dashouguize.jpg'
if club_config:
# 存储桶配置
bucket = club_config.storage_bucket_name or ''
region = 'ap-shanghai' # 若需要动态,可单独存储
cos_oss_url = club_config.storage_bucket_domain or ''
if cos_oss_url and not cos_oss_url.endswith('/'):
cos_oss_url += '/'
cos_bucket = bucket
cos_region = region
# GoEasy 配置
if club_config.chat_api_key:
goeasy_appkey = club_config.chat_api_key
# host 如果需要可动态,这里固定或从其他字段获取
# 客服配置
if club_config.customer_service_api_url:
kefu_link = club_config.customer_service_api_url
if club_config.customer_service_corp_id:
kefu_enterprise_id = club_config.customer_service_corp_id
# 其他配置可在此扩展
# 构造返回数据
data = {
"code": 0,
@@ -2229,26 +2198,10 @@ class KehuGetDingdanLianjieView(APIView):
# ========== 新增:确定俱乐部配置 ==========
# 默认头像(相对路径)
default_avatar = 'a_long/morentouxiang.jpg'
# 初始化配置字段默认值
kefu_link = ''
oss_url = ''
goeasy_appkey = ''
# 判断是否为跨平台订单(保留,但不影响配置选择)
is_cross = dingdan_obj.is_cross if hasattr(dingdan_obj, 'is_cross') else 0
# 始终使用我方俱乐部配置
try:
club_config = ClubConfig.objects.filter(is_self=1).first()
if club_config:
logger.info(f"使用我方俱乐部配置club_id={club_config.club_id}")
kefu_link = club_config.customer_service_api_url or ''
oss_url = club_config.storage_bucket_domain or ''
goeasy_appkey = club_config.chat_api_key or ''
else:
logger.warning("未找到我方俱乐部配置is_self=1")
except Exception as e:
logger.error(f"查询我方俱乐部配置异常: {str(e)}", exc_info=True)
# 从 settings 获取配置
kefu_link = getattr(settings, 'KEFU_LINK', '')
oss_url = getattr(settings, 'COS_DOMAIN', '')
goeasy_appkey = getattr(settings, 'GOEASY_APPKEY', '')
# ========== 构建订单信息 ==========
dingdan_info = {
@@ -2256,7 +2209,6 @@ class KehuGetDingdanLianjieView(APIView):
'jiage': str(dingdan_obj.jine) if dingdan_obj.jine is not None else '0.00', # 金额字段名是 jine
'shangjia_mingcheng': shangjia_nicheng,
'zhuangtai': dingdan_obj.zhuangtai,
'is_cross': is_cross,
# 新增配置字段
'kefu_link': kefu_link,
'oss_url': oss_url,
@@ -2313,7 +2265,6 @@ class KehuGetDingdanLianjieView(APIView):
'dashou_biaoshi': '',
'shangjia_biaoshi': '',
'you_dashou': False,
'is_cross': 0,
'kefu_link': '',
'oss_url': '',
'default_avatar': 'a_long/morentouxiang.jpg',
@@ -2330,7 +2281,6 @@ class KehuGetDingdanLianjieView(APIView):
'dashou_biaoshi': '',
'shangjia_biaoshi': '',
'you_dashou': False,
'is_cross': 0,
'kefu_link': '',
'oss_url': '',
'default_avatar': 'a_long/morentouxiang.jpg',
@@ -2348,7 +2298,6 @@ class KehuGetDingdanLianjieView(APIView):
'dashou_biaoshi': '',
'shangjia_biaoshi': '',
'you_dashou': False,
'is_cross': 0,
'kefu_link': '',
'oss_url': '',
'default_avatar': 'a_long/morentouxiang.jpg',
@@ -2627,13 +2576,6 @@ class KehuTianxieDingdanView(APIView):
shangjia_mingcheng = f"商家{lianjie_obj.yonghu_id}"
logger.warning(f"获取商家昵称失败,使用默认 - 用户ID: {lianjie_obj.yonghu_id}")
# ========== 新增:判断是否需要跨平台同步 ==========
# 获取商家ID从链接记录
shangjia_user_id = lianjie_obj.yonghu_id
# 跨平台条件商家ID在白名单、订单为普通状态zhuangtai=1、要求类型为1、会员ID等于配置值
sync_order_to_partners(dingdan_obj.dingdan_id)
# ========== 新增结束 ==========
# 14. 返回成功响应
response_data = {
#'dingdan_id': dingdan_obj.dingdan_id,

35
fix_migration_history.py Normal file
View File

@@ -0,0 +1,35 @@
"""
修复 django_migrations 表中的旧 app 名称引用。
在服务器上执行: python manage.py shell < fix_migration_history.py
或: python manage.py shell
然后粘贴此脚本内容
"""
from django.db import connection
APP_NAME_MAPPINGS = {
'houtai': 'backend',
'yonghu': 'users',
'dingdan': 'orders',
'peizhi': 'config',
'shangpin': 'products',
'shangdian': 'shop',
'dengji': 'rank',
}
with connection.cursor() as cursor:
for old_name, new_name in APP_NAME_MAPPINGS.items():
cursor.execute(
"SELECT COUNT(*) FROM django_migrations WHERE app = %s",
[old_name]
)
count = cursor.fetchone()[0]
if count > 0:
cursor.execute(
"UPDATE django_migrations SET app = %s WHERE app = %s",
[new_name, old_name]
)
print(f"已更新 {count} 条记录: {old_name} -> {new_name}")
else:
print(f"无需更新: {old_name} (无记录)")
print("\n修复完成!请运行 python manage.py migrate")

View File

@@ -1,38 +0,0 @@
# 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):
"""
异步发送派单通知给对方平台使用简单线程非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,
}
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

@@ -174,7 +174,7 @@ class Migration(migrations.Migration):
('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='订单')),
('dingdan', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='pingtai_kuozhan', to='orders.dingdan', verbose_name='订单')),
],
options={
'verbose_name': '平台订单扩展',
@@ -193,7 +193,7 @@ class Migration(migrations.Migration):
('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='订单')),
('dingdan', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='shangjia_kuozhan', to='orders.dingdan', verbose_name='订单')),
],
options={
'verbose_name': '商家订单扩展',

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0001_initial'),
('orders', '0001_initial'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0002_dingdan_auto_expire_at_dingdan_auto_task_id'),
('orders', '0002_dingdan_auto_expire_at_dingdan_auto_task_id'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0003_dingdan_pending_dispatch_dingdan_status_8_time'),
('orders', '0003_dingdan_pending_dispatch_dingdan_status_8_time'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0004_alter_tuikuanjilu_chuliid'),
('orders', '0004_alter_tuikuanjilu_chuliid'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0005_alter_chufajilu_chuliid'),
('orders', '0005_alter_chufajilu_chuliid'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0006_chufatupian'),
('orders', '0006_chufatupian'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0007_chufajilu_ssliyou'),
('orders', '0007_chufajilu_ssliyou'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0008_dingdan_is_cross_dingdan_partner_order_id'),
('orders', '0008_dingdan_is_cross_dingdan_partner_order_id'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0009_dingdanpingtai_clkf_dingdanpingtai_jjjs_biaoshi'),
('orders', '0009_dingdanpingtai_clkf_dingdanpingtai_jjjs_biaoshi'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0010_remove_dingdanpingtai_clkf_dingdan_clkf'),
('orders', '0010_remove_dingdanpingtai_clkf_dingdan_clkf'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0011_dingdan_tkly'),
('orders', '0011_dingdan_tkly'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0012_dingdan_wechat_transaction_id_and_more'),
('orders', '0012_dingdan_wechat_transaction_id_and_more'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0013_alter_chufajilu_qingqiuid'),
('orders', '0013_alter_chufajilu_qingqiuid'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0014_dingdan_dispatch_type_dingdan_partner_club_id'),
('orders', '0014_dingdan_dispatch_type_dingdan_partner_club_id'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0015_presettlement_orderdashouhistory_and_more'),
('orders', '0015_presettlement_orderdashouhistory_and_more'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0016_alter_presettlement_dingdan_id_and_more'),
('orders', '0016_alter_presettlement_dingdan_id_and_more'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0017_dingdanpingtai_dianpu_id_and_more'),
('orders', '0017_dingdanpingtai_dianpu_id_and_more'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0018_dingdanshangjia_partner_yonghu_id'),
('orders', '0018_dingdanshangjia_partner_yonghu_id'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0019_dingdanpingtai_shangji_dianpu_id_and_more'),
('orders', '0019_dingdanpingtai_shangji_dianpu_id_and_more'),
]
operations = [

View File

@@ -7,7 +7,7 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0020_fadanfenhong_fadan'),
('orders', '0020_fadanfenhong_fadan'),
]
operations = [
@@ -18,7 +18,7 @@ class Migration(migrations.Migration):
('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='创建时间')),
('fadan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='shensu_tupians', to='dingdan.fadan', verbose_name='关联罚单')),
('fadan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='shensu_tupians', to='orders.fadan', verbose_name='关联罚单')),
],
options={
'verbose_name': '罚款申诉图片',

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0021_fadanshensutupian'),
('orders', '0021_fadanshensutupian'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0022_fadan_partner_club_id_fadan_shenqingren_shenfen'),
('orders', '0022_fadan_partner_club_id_fadan_shenqingren_shenfen'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0023_fadanshensutupian_yongtu'),
('orders', '0023_fadanshensutupian_yongtu'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0024_fadan_chulizhe_fadan_chulizhe_shenfen'),
('orders', '0024_fadan_chulizhe_fadan_chulizhe_shenfen'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0025_alter_fadan_shenqingren_shenfen'),
('orders', '0025_alter_fadan_shenqingren_shenfen'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0026_fadanfenhonglilv_alter_fadan_shenqingren_shenfen_and_more'),
('orders', '0026_fadanfenhonglilv_alter_fadan_shenqingren_shenfen_and_more'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0027_dingdanpeihu'),
('orders', '0027_dingdanpeihu'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0028_dingdanshangjia_shangyige_dingdan_id'),
('orders', '0028_dingdanshangjia_shangyige_dingdan_id'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0029_fadanfenhong_is_individual_rate'),
('orders', '0029_fadanfenhong_is_individual_rate'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0030_fadan_shenqingren_fenhong_jine'),
('orders', '0030_fadan_shenqingren_fenhong_jine'),
]
operations = [

View File

@@ -0,0 +1,43 @@
# Generated by Django 4.2.27 on 2026-06-15 01:42
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('orders', '0031_dingdan_guanshi_fencheng'),
]
operations = [
migrations.DeleteModel(
name='CrossPlatformOrderData',
),
migrations.DeleteModel(
name='PreSettlement',
),
migrations.RemoveField(
model_name='dingdan',
name='dispatch_type',
),
migrations.RemoveField(
model_name='dingdan',
name='is_cross',
),
migrations.RemoveField(
model_name='dingdan',
name='partner_club_id',
),
migrations.RemoveField(
model_name='dingdan',
name='partner_order_id',
),
migrations.RemoveField(
model_name='dingdanshangjia',
name='partner_yonghu_id',
),
migrations.RemoveField(
model_name='fadan',
name='partner_club_id',
),
]

View File

@@ -26,12 +26,7 @@ class Dingdan(models.Model):
# 订单描述信息
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')
# 新增字段:游戏昵称(前端提交的游戏昵称)
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标识')
@@ -112,7 +107,6 @@ class DingdanShangjia(models.Model):
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')
# 在 dingdan/models.py 的 DingdanShangjia 类中添加
shangyige_dingdan_id = models.CharField(
max_length=32,
@@ -186,9 +180,6 @@ class DingdanPeihu(models.Model):
# 建议路径dingdan/models.py 或 独立 fadan/models.py
from django.db import models
class Fadan(models.Model):
"""罚单表——平台各类处罚信息"""
id = models.AutoField(primary_key=True, verbose_name='自增主键')
@@ -206,8 +197,6 @@ class Fadan(models.Model):
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,
@@ -310,88 +299,6 @@ class FadanFenhongLilv(models.Model):
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}"
# 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):
"""
订单打手变更历史表

View File

@@ -38,7 +38,7 @@ def ensure_redis_loaded():
# 预加载redis模块
ensure_redis_loaded()
@receiver(pre_save, sender='dingdan.Dingdan')
@receiver(pre_save, sender='orders.Dingdan')
def handle_order_status_8(sender, instance, **kwargs):
"""
订单状态变为8时提交定时任务

View File

@@ -18,8 +18,6 @@ from orders.models import Dingdan
from users.models import UserMain, UserDashou, UserShangjia
from utils.celery_utils import safe_decimal_operation, log_task_execution, rollback_on_failure
# from users.utils import update_platform_profit # 导入函数
logger = logging.getLogger(__name__)
@@ -110,11 +108,7 @@ def process_expired_order(self, dingdan_id):
result_msg += ",商家信息已更新"
if fadan_pingtai == 1:
try:
update_platform_profit(dingdan_id)
except Exception as e:
# 平台收益更新失败不影响主流程,但记录日志
logger.error(f"强制结单后更新平台收益失败: {str(e)}")
pass # 平台收益更新逻辑待完善
log_task_execution(f"自动结算订单 {dingdan_id}", True, result_msg)
return result_msg

View File

@@ -7,7 +7,7 @@ from .views import CreateOrderView, WechatPayNotifyView, \
ShangjiaChexiaoView, DashouDingdanHuoquView, ShangpinLeixingHuoquView, QiangdanView, \
DashouDingdanHuoquView1, DashouCOSZhengshuView, DashouTijiaoView, DashouDingdanXiangqingView, AdGetDingdanXiangQing, \
AdTongYiTuiKuanPingTai, AdTongYiTuiKuanShangJia, AdQiangZhiJieDan, AdJuJueTuiKuan,\
AdGengHuanDaShou,ShangjiaCOSZhengshuView, DashouHuoquLeixingView,PartnerNotifyClaimView, PartnerSyncOrderView, PartnerCheckClaimView, PartnerRefundNotifyView,AdJuJueJieSuan, AdZhuanYiDaTing, AdQuXiaoZhiDing,DashouXiugaiView,DaiLiQunLiaoXiaoXiView,\
AdGengHuanDaShou,ShangjiaCOSZhengshuView, DashouHuoquLeixingView,AdJuJueJieSuan, AdZhuanYiDaTing, AdQuXiaoZhiDing,DashouXiugaiView,DaiLiQunLiaoXiaoXiView,\
ShangjiaLianjieLiuYanZhuanFaView, DingdanXiangqingView2, JiedanView2, ZxsjghdsView, \
ShangjiaFakuanApplyView, ShangjiaFakuaiXiugaiView
@@ -65,12 +65,6 @@ urlpatterns = [
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='前端聊天转发'), # 群聊消息代理发送

View File

@@ -1,17 +1,13 @@
import threading
import requests
import time
import logging
from datetime import date
from decimal import Decimal
from django.conf import settings
from django.db import transaction
from django.db.models import F
from config.models import Club, DailyDispatchStat, DailyIncomeStat, DailyPayoutStat
from config.models import DailyIncomeStat, DailyPayoutStat
from orders.models import Dingdan, DingdanPingtai, DingdanShangjia, Lilubiao
from products.models import ShangpinLeixing, Gsfenhong
from products.models import Gsfenhong
from users.models import UserDashou, UserGuanshi
from backend.utils import update_guanshi_daily_by_action
@@ -19,234 +15,22 @@ from backend.utils import update_guanshi_daily_by_action
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:
time.sleep(2 ** attempt) # 指数退避
else:
logger.error(f"同步订单 {dingdan.dingdan_id} 到俱乐部 {club.club_id} 最终失败")
# 获取下单方ID根据订单类型
def get_order_user_id(order):
if order.fadan_pingtai == 1:
try:
ext = DingdanPingtai.objects.get(dingdan=order)
return ext.laoban_id # 老板ID
return ext.laoban_id
except DingdanPingtai.DoesNotExist:
return None
elif order.fadan_pingtai == 2:
try:
ext = DingdanShangjia.objects.get(dingdan=order)
return ext.shangjia_id # 商家ID
return ext.shangjia_id
except DingdanShangjia.DoesNotExist:
return None
return None
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}")
def update_daily_income(amount):
"""
原子更新当日收入统计金额累加笔数加1

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shangpin', '0001_initial'),
('products', '0001_initial'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shangpin', '0002_alter_huiyuangoumai_unique_together_and_more'),
('products', '0002_alter_huiyuangoumai_unique_together_and_more'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shangpin', '0003_shangpin_paixu_shangpinleixing_paixu_and_more'),
('products', '0003_shangpin_paixu_shangpinleixing_paixu_and_more'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shangpin', '0004_shangpin_shenhezhuangtai_and_more'),
('products', '0004_shangpin_shenhezhuangtai_and_more'),
]
operations = [

View File

@@ -7,7 +7,7 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('shangpin', '0005_alter_gsfenhong_dashouid'),
('products', '0005_alter_gsfenhong_dashouid'),
]
operations = [
@@ -32,7 +32,7 @@ class Migration(migrations.Migration):
('zuzhang_fenhong', 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='更新时间')),
('huiyuan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='shangpin.huiyuan', verbose_name='会员')),
('huiyuan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='products.huiyuan', verbose_name='会员')),
],
options={
'verbose_name': '多次分红配置',

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shangpin', '0006_gsfenhong_huiyuan_id_huiyuan_zuzhangfc_duocifenhong'),
('products', '0006_gsfenhong_huiyuan_id_huiyuan_zuzhangfc_duocifenhong'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shangpin', '0007_remove_duocifenhong_duoci_fenho_guanshi_b3de53_idx_and_more'),
('products', '0007_remove_duocifenhong_duoci_fenho_guanshi_b3de53_idx_and_more'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shangpin', '0008_gsfenhong_zuzhang_fenhong_gsfenhong_zuzhang_id'),
('products', '0008_gsfenhong_zuzhang_fenhong_gsfenhong_zuzhang_id'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shangpin', '0009_shangpin_ewai_dashou_fencheng_and_more'),
('products', '0009_shangpin_ewai_dashou_fencheng_and_more'),
]
operations = [

View File

@@ -7,20 +7,20 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('shangdian', '0001_initial'),
('shangpin', '0010_shangpinleixing_is_cross_enabled'),
('shop', '0001_initial'),
('products', '0010_shangpinleixing_is_cross_enabled'),
]
operations = [
migrations.AddField(
model_name='shangpin',
name='dianpu',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='shangdian.dianpu', verbose_name='所属店铺'),
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='shop.dianpu', verbose_name='所属店铺'),
),
migrations.AddField(
model_name='shangpin',
name='dianpu_leixing',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='shangdian.shangpinleixingdianpu', verbose_name='店铺商品类型'),
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='shop.shangpinleixingdianpu', verbose_name='店铺商品类型'),
),
migrations.AddField(
model_name='shangpin',
@@ -40,12 +40,12 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='shangpinzhuanqu',
name='dianpu',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='shangdian.dianpu', verbose_name='所属店铺'),
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='shop.dianpu', verbose_name='所属店铺'),
),
migrations.AddField(
model_name='shangpinzhuanqu',
name='dianpu_leixing',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='shangdian.shangpinleixingdianpu', verbose_name='店铺商品类型'),
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='shop.shangpinleixingdianpu', verbose_name='店铺商品类型'),
),
migrations.AddField(
model_name='shangpinzhuanqu',

View File

@@ -7,7 +7,7 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('shangpin', '0011_shangpin_dianpu_shangpin_dianpu_leixing_and_more'),
('products', '0011_shangpin_dianpu_shangpin_dianpu_leixing_and_more'),
]
operations = [
@@ -29,7 +29,7 @@ class Migration(migrations.Migration):
('dianpu_zongshouyi', models.DecimalField(decimal_places=2, default=0.0, max_digits=12, verbose_name='店铺总收益')),
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('shangpin', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='shangpin.shangpin', verbose_name='商品ID')),
('shangpin', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='products.shangpin', verbose_name='商品ID')),
],
options={
'verbose_name': '商品每日统计',

View File

@@ -7,14 +7,14 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('dengji', '0003_alter_dashoubiaoxian_bankuai'),
('shangpin', '0012_shangpinmeiritongji'),
('rank', '0003_alter_dashoubiaoxian_bankuai'),
('products', '0012_shangpinmeiritongji'),
]
operations = [
migrations.AddField(
model_name='shangpinleixing',
name='bankuai',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dengji.bankuai', verbose_name='所属板块'),
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='rank.bankuai', verbose_name='所属板块'),
),
]

View File

@@ -7,14 +7,14 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('dengji', '0010_kaohejilufeiyong'),
('shangpin', '0013_shangpinleixing_bankuai'),
('rank', '0010_kaohejilufeiyong'),
('products', '0013_shangpinleixing_bankuai'),
]
operations = [
migrations.AddField(
model_name='huiyuan',
name='bankuai',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dengji.bankuai', verbose_name='所属板块'),
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='rank.bankuai', verbose_name='所属板块'),
),
]

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shangpin', '0014_huiyuan_bankuai'),
('products', '0014_huiyuan_bankuai'),
]
operations = [

View File

@@ -0,0 +1,17 @@
# Generated by Django 4.2.27 on 2026-06-15 01:42
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('products', '0015_gsfenhong_fenhong_leixing'),
]
operations = [
migrations.RemoveField(
model_name='shangpinleixing',
name='is_cross_enabled',
),
]

View File

@@ -75,7 +75,6 @@ class ShangpinLeixing(models.Model):
yongjin = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name='佣金要求')
jieshao = models.CharField(max_length=45, null=True, blank=True, verbose_name='类型介绍') # 15汉字
tupian_url = models.CharField(max_length=500, null=True, blank=True, verbose_name='类型图片URL') # 用CharField
is_cross_enabled = models.BooleanField(default=False, verbose_name='是否开启平台互通')
paixu = models.IntegerField(default=0, verbose_name='排序权重')
shenhezhuangtai = models.IntegerField(default=1, verbose_name='审核状态', help_text='1=正常, 2=审核专用')
bankuai = models.ForeignKey(

View File

@@ -11,7 +11,7 @@ class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('dingdan', '0026_fadanfenhonglilv_alter_fadan_shenqingren_shenfen_and_more'),
('orders', '0026_fadanfenhonglilv_alter_fadan_shenqingren_shenfen_and_more'),
]
operations = [
@@ -37,7 +37,7 @@ class Migration(migrations.Migration):
('tubiao_url', models.CharField(blank=True, max_length=200, null=True, verbose_name='称号图标相对URL')),
('texiao_miaoshu', models.TextField(blank=True, null=True, verbose_name='特效描述(JSON)')),
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('bankuai', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='dengji.bankuai', verbose_name='所属板块(空=全板块通用)')),
('bankuai', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='rank.bankuai', verbose_name='所属板块(空=全板块通用)')),
],
options={
'verbose_name': '称号',
@@ -50,7 +50,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('huode_time', models.DateTimeField(auto_now_add=True, verbose_name='获得时间')),
('chenghao', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dengji.chenghao', verbose_name='称号')),
('chenghao', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rank.chenghao', verbose_name='称号')),
('yonghu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chenghao_list', to=settings.AUTH_USER_MODEL, verbose_name='用户')),
],
options={
@@ -74,7 +74,7 @@ class Migration(migrations.Migration):
('dingdan_id', models.CharField(blank=True, 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='更新时间')),
('bankuai', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='dengji.bankuai', verbose_name='所属板块')),
('bankuai', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='rank.bankuai', verbose_name='所属板块')),
],
options={
'verbose_name': '经验变动记录',
@@ -94,8 +94,8 @@ class Migration(migrations.Migration):
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('jiedan_time', models.DateTimeField(blank=True, null=True, verbose_name='接单时间')),
('tijiao_time', models.DateTimeField(blank=True, null=True, verbose_name='提交时间')),
('bankuai', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='dengji.bankuai', verbose_name='所属板块')),
('dingdan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='biaoxian', to='dingdan.dingdan', verbose_name='关联订单')),
('bankuai', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='rank.bankuai', verbose_name='所属板块')),
('dingdan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='biaoxian', to='orders.dingdan', verbose_name='关联订单')),
],
options={
'verbose_name': '打手订单表现',

View File

@@ -7,14 +7,14 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0026_fadanfenhonglilv_alter_fadan_shenqingren_shenfen_and_more'),
('dengji', '0001_initial'),
('orders', '0026_fadanfenhonglilv_alter_fadan_shenqingren_shenfen_and_more'),
('rank', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='dashoubiaoxian',
name='dingdan',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='biaoxian', to='dingdan.dingdan', to_field='dingdan_id', verbose_name='关联订单'),
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='biaoxian', to='orders.dingdan', to_field='dingdan_id', verbose_name='关联订单'),
),
]

View File

@@ -7,13 +7,13 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('dengji', '0002_alter_dashoubiaoxian_dingdan'),
('rank', '0002_alter_dashoubiaoxian_dingdan'),
]
operations = [
migrations.AlterField(
model_name='dashoubiaoxian',
name='bankuai',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='dengji.bankuai', verbose_name='所属板块'),
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='rank.bankuai', verbose_name='所属板块'),
),
]

View File

@@ -4,8 +4,8 @@ from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0026_fadanfenhonglilv_alter_fadan_shenqingren_shenfen_and_more'), # 保持你之前的依赖
('dengji', '0003_alter_dashoubiaoxian_bankuai'),
('orders', '0026_fadanfenhonglilv_alter_fadan_shenqingren_shenfen_and_more'), # 保持你之前的依赖
('rank', '0003_alter_dashoubiaoxian_bankuai'),
]
operations = [

View File

@@ -5,8 +5,8 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('dingdan', '0026_fadanfenhonglilv_alter_fadan_shenqingren_shenfen_and_more'), # 保持你之前的依赖
('dengji', '0004_dingdanbiaoqian'),
('orders', '0026_fadanfenhonglilv_alter_fadan_shenqingren_shenfen_and_more'), # 保持你之前的依赖
('rank', '0004_dingdanbiaoqian'),
]
operations = [
@@ -18,8 +18,8 @@ class Migration(migrations.Migration):
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('chenghao', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dengji.chenghao', verbose_name='标签')),
('dingdan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dingdan.dingdan', to_field='dingdan_id', verbose_name='订单')),
('chenghao', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rank.chenghao', verbose_name='标签')),
('dingdan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='orders.dingdan', to_field='dingdan_id', verbose_name='订单')),
],
options={
'verbose_name': '订单需求标签',

View File

@@ -7,7 +7,7 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('dengji', '0005_fix_state'),
('rank', '0005_fix_state'),
]
operations = [
@@ -22,8 +22,8 @@ class Migration(migrations.Migration):
('jiaofei_jine', 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='更新时间')),
('bankuai', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='dengji.bankuai', verbose_name='审核板块')),
('chenghao', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='dengji.chenghao', verbose_name='审核标签')),
('bankuai', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='rank.bankuai', verbose_name='审核板块')),
('chenghao', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='rank.chenghao', verbose_name='审核标签')),
],
options={
'verbose_name': '审核记录',

View File

@@ -7,7 +7,7 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('dengji', '0006_shenhejilu'),
('rank', '0006_shenhejilu'),
]
operations = [
@@ -16,7 +16,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('kaoheguan_id', models.CharField(db_index=True, max_length=7, verbose_name='考核官用户ID')),
('bankuai', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dengji.bankuai', verbose_name='所属板块')),
('bankuai', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rank.bankuai', verbose_name='所属板块')),
],
options={
'verbose_name': '考核官板块关联',

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dengji', '0007_kaoheguanbankuai'),
('rank', '0007_kaoheguanbankuai'),
]
operations = [

View File

@@ -7,7 +7,7 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('dengji', '0008_chenghao_kaohe_guize_shenhejilu_dashou_beizhu_and_more'),
('rank', '0008_chenghao_kaohe_guize_shenhejilu_dashou_beizhu_and_more'),
]
operations = [
@@ -30,7 +30,7 @@ class Migration(migrations.Migration):
('shenheguan_id', models.CharField(max_length=7, verbose_name='考核官用户ID')),
('yuanyin', models.TextField(verbose_name='拒绝原因')),
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('jilu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dengji.shenhejilu', to_field='jilu_id', verbose_name='审核记录')),
('jilu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rank.shenhejilu', to_field='jilu_id', verbose_name='审核记录')),
],
options={
'verbose_name': '拒绝原因记录',
@@ -45,7 +45,7 @@ class Migration(migrations.Migration):
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('cishu', models.IntegerField(verbose_name='第几次考核')),
('feiyong', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='需缴纳金额')),
('chenghao', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dengji.chenghao', verbose_name='标签')),
('chenghao', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rank.chenghao', verbose_name='标签')),
],
options={
'verbose_name': '考核次数费用',

View File

@@ -7,7 +7,7 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('dengji', '0009_chenghao_kaioi_jinpai_alter_shenhejilu_jilu_id_and_more'),
('rank', '0009_chenghao_kaioi_jinpai_alter_shenhejilu_jilu_id_and_more'),
]
operations = [
@@ -17,7 +17,7 @@ class Migration(migrations.Migration):
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('cishu', models.IntegerField(verbose_name='第几次考核')),
('jine', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='缴纳金额')),
('jilu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dengji.shenhejilu', to_field='jilu_id', verbose_name='考核记录')),
('jilu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rank.shenhejilu', to_field='jilu_id', verbose_name='考核记录')),
],
options={
'verbose_name': '考核记录费用',

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dengji', '0010_kaohejilufeiyong'),
('rank', '0010_kaohejilufeiyong'),
]
operations = [

View File

@@ -11,7 +11,7 @@ class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('shangpin', '0010_shangpinleixing_is_cross_enabled'),
('products', '0010_shangpinleixing_is_cross_enabled'),
]
operations = [
@@ -45,7 +45,7 @@ class Migration(migrations.Migration):
('erweima_url', 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='更新时间')),
('pingzheng', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='shangdian.yonghupingzheng', verbose_name='关联用户凭证')),
('pingzheng', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='shop.yonghupingzheng', verbose_name='关联用户凭证')),
],
options={
'verbose_name': '平台商家店铺',
@@ -59,7 +59,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='绑定自增ID')),
('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('dianpu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='shangdian.dianpu', verbose_name='关联店铺ID')),
('dianpu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='shop.dianpu', verbose_name='关联店铺ID')),
('yonghu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, to_field='yonghuid', verbose_name='用户ID')),
],
options={
@@ -79,8 +79,8 @@ class Migration(migrations.Migration):
('shangjia_zhuangtai', models.BooleanField(default=True, verbose_name='是否上架')),
('fengjin_zhuangtai', models.BooleanField(default=False, verbose_name='是否封禁')),
('shenhe_zhuangtai', models.BooleanField(default=False, help_text='True=审核通过False=未审核', verbose_name='平台审核状态')),
('dianpu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='shangdian.dianpu', verbose_name='所属店铺')),
('gonggong_leixing', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='shangpin.shangpinleixing', verbose_name='映射的公共商品类型')),
('dianpu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='shop.dianpu', verbose_name='所属店铺')),
('gonggong_leixing', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='products.shangpinleixing', verbose_name='映射的公共商品类型')),
],
options={
'verbose_name': '店铺商品类型映射',

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shangdian', '0001_initial'),
('shop', '0001_initial'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shangdian', '0002_alter_yonghupingzheng_yonghu'),
('shop', '0002_alter_yonghupingzheng_yonghu'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shangdian', '0003_dianpumorenpeizhi_dianpu_kaiqi_meiri_xiane_and_more'),
('shop', '0003_dianpumorenpeizhi_dianpu_kaiqi_meiri_xiane_and_more'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shangdian', '0004_dianpushangpinshenheshezhi'),
('shop', '0004_dianpushangpinshenheshezhi'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('shangdian', '0005_dianpu_fenhong_choucheng_feilv_and_more'),
('shop', '0005_dianpu_fenhong_choucheng_feilv_and_more'),
]
operations = [

View File

@@ -178,7 +178,7 @@ class ShangpinLeixingDianpu(models.Model):
)
# 🔥 强制映射到公共商品类型,不可为空
gonggong_leixing = models.ForeignKey(
'shop.ShangpinLeixing',
'products.ShangpinLeixing',
on_delete=models.CASCADE,
db_index=True,
verbose_name='映射的公共商品类型'

View File

@@ -49,12 +49,9 @@ from products.models import ShangpinLeixing, ShangpinZhuanqu, Shangpin, Huiyuan
from orders.models import (
Dingdan, DingdanPingtai, Dashoutupian, Tuikuanjilu,
OrderDashouHistory, CrossPlatformOrderData, Fadan
OrderDashouHistory, Fadan
)
from config.models import ClubConfig, Club
logger = logging.getLogger(__name__)
@@ -2021,8 +2018,6 @@ class SubShopModifyView(APIView):
"""
# 如果有 ClubConfig 模型用于获取存储桶域名,确保导入(如没有可忽略,使用 settings 中的 OSS 域名)
# ---------- 图片域名 ----------
"""
店铺订单管理接口
@@ -2192,22 +2187,9 @@ class ShopOrderStatisticsView(APIView):
def get_oss_domain():
"""
获取对象存储的域名,末尾包含 '/'
优先从跨平台配置表 ClubConfig 中获取本俱乐部的 storage_bucket_domain
如果获取失败或表不存在,则使用预设的 OSS 域名作为降级方案。
返回:字符串,如 'https://example.com/'
"""
try:
# 尝试从跨平台配置中读取
from kuaping.models import ClubConfig
config = ClubConfig.objects.filter(is_self=1).first()
if config and config.storage_bucket_domain:
# 确保域名末尾有 '/'
return config.storage_bucket_domain.rstrip('/') + '/'
except Exception:
# 表不存在或其它异常,忽略,使用下方默认域名
pass
# 默认 OSS 域名,请替换为你的实际域名
return 'https://xingque999qygwuyq-1404472910.cos.ap-shanghai.myqcloud.com/'
return getattr(settings, 'COS_DOMAIN', 'https://xingque999qygwuyq-1404472910.cos.ap-shanghai.myqcloud.com/').rstrip('/') + '/'
# ================================================================
@@ -2674,15 +2656,6 @@ class ShopRefundView(APIView):
logger.exception("退款事务执行失败")
return Response({'code': 500, 'msg': '退款处理失败,请稍后重试'})
# 7. 跨平台通知如果存在对方平台订单ID异步通知不影响主流程
partner_order_id = order.partner_order_id
partner_club_id = order.partner_club_id
if partner_order_id and partner_club_id:
try:
self._notify_partner_refund(dingdan_id, partner_club_id, partner_order_id, reason, order.jine)
except Exception as e:
logger.error(f"跨平台退款通知异常: {e}")
return Response({'code': 200, 'msg': '退款成功'})
# ========== 微信退款 ==========
@@ -2767,53 +2740,6 @@ class ShopRefundView(APIView):
except Exception as e:
logger.error(f"更新退款记录异常: {e}")
# ========== 跨平台通知 ==========
def _notify_partner_refund(self, dingdan_id, partner_club_id, partner_order_id, reason, amount):
"""
通知对方平台我方已退款。
此方法执行不影响主流程,任何异常仅记录日志。
"""
try:
my_config = ClubConfig.objects.filter(is_self=1).first()
if not my_config:
logger.error("未配置我方俱乐部信息,无法通知对方")
return
self_club_id = my_config.club_id
club_rel = Club.objects.get(club_id=self_club_id, partner_club_id=partner_club_id)
partner_domain = club_rel.partner_domain.rstrip('/')
notify_url = f"{partner_domain}/houtai/dfddtk"
payload = {
'order_id': partner_order_id,
'club_id': self_club_id,
'status': 5,
'reason': reason or '店铺退款'
}
resp = requests.post(notify_url, json=payload, timeout=3)
if resp.status_code == 200:
resp_json = resp.json()
if resp_json.get('code') == 0:
# 更新跨平台扩展表状态
cross_data, _ = CrossPlatformOrderData.objects.get_or_create(
dingdan_id=dingdan_id,
defaults={
'partner_order_id': partner_order_id,
'partner_club_id': partner_club_id,
'partner_order_status': resp_json.get('data', {}).get('partner_status', 0),
'partner_dashou_id': resp_json.get('data', {}).get('partner_dashou_id', ''),
'partner_amount': amount or 0,
}
)
if not _:
cross_data.partner_order_status = resp_json.get('data', {}).get('partner_status', 0)
cross_data.save()
else:
logger.warning(f"对方平台返回错误: {resp_json.get('msg')}")
else:
logger.warning(f"通知对方HTTP错误: {resp.status_code}")
except Exception as e:
logger.error(f"通知对方平台异常: {e}")
# ========== 工具方法 ==========
def _generate_nonce_str(self):
return ''.join(random.choices(string.ascii_letters + string.digits, k=32))
@@ -2887,8 +2813,6 @@ class ShopForceCompleteView(APIView):
logger.warning(f"订单 {dingdan_id} 当前状态为 {order.zhuangtai},不是结算中")
return Response({'code': 400, 'msg': f'订单状态不是结算中,当前状态: {order.zhuangtai}'})
# ========== 5. 判断是否为跨平台订单有对方订单ID就认为是跨平台 ==========
is_cross = order.is_cross and (order.partner_order_id or order.partner_club_id)
dashou_id = order.jiedan_dashou_id
dashou_fencheng = order.dashou_fencheng or Decimal('0.00')
jine = order.jine or Decimal('0.00')
@@ -2898,103 +2822,72 @@ class ShopForceCompleteView(APIView):
# 锁定订单行,防止并发
order = Dingdan.objects.select_for_update().get(dingdan_id=dingdan_id)
# ============================
# 情况1跨平台订单我方派单给对方平台打手
# ============================
if is_cross:
# 只需更新我方订单状态,打手在对方平台,不处理我方打手余额
order.zhuangtai = 3 # 已完成
order.clkf = str(shop_id) # 处理人记录为店铺ID
order.save()
if not dashou_id:
return Response({'code': 400, 'msg': '订单无接单打手,无法结算'})
if dashou_fencheng < 0:
return Response({'code': 400, 'msg': '打手分成金额无效'})
# 店铺结算时,若涉及跨平台收益,这里是否要更新店铺统计?
# 根据业务需求,可在此处调用 update_dianpu_daily_stat 等
# 但通常跨平台订单的资金已在对方平台流转,店铺仅作为发单方,
# 收益可能已在其他环节计算,此处可根据需要添加统计。
# ---------- 更新打手余额和统计 ----------
try:
dashou_user = UserMain.objects.get(yonghuid=dashou_id)
dashou_profile = dashou_user.dashou_profile
dashou_profile.chengjiaozongliang += 1
dashou_profile.yue += dashou_fencheng
dashou_profile.zonge += dashou_fencheng
dashou_profile.jinrishouyi += dashou_fencheng
dashou_profile.jinyueshouyi += dashou_fencheng
dashou_profile.zhuangtai = 1 # 空闲
dashou_profile.save()
except (UserMain.DoesNotExist, ObjectDoesNotExist):
logger.warning(f"本地订单结算:打手 {dashou_id} 不存在,跳过打手更新")
# 通知对方平台(异步,不影响主流程)
if order.partner_club_id and order.partner_order_id:
transaction.on_commit(
lambda: self._notify_partner_order_complete(
order.partner_club_id,
order.partner_order_id,
shop_id
# ---------- 更新订单状态 ----------
order.zhuangtai = 3
order.clkf = str(shop_id)
order.save()
# ---------- 打手每日统计(成交) ----------
try:
update_dashou_daily_by_action(
yonghuid=dashou_id,
amount=dashou_fencheng,
action=2 # 2 表示成交(结算)
)
except Exception as e:
logger.error(f"打手每日统计更新失败: {e}")
# ---------- 店铺收益统计(结算) ----------
if pingtai_ext.dianpu_shouyi:
try:
# 商品每日统计只要有商品ID就执行
if order.shangpin_id:
# 从扩展表获取已计算好的收益值(下单时已存储)
pingtai_shouyi = Decimal('0.00')
dianpu_shouyi = Decimal('0.00')
if hasattr(order, 'pingtai_kuozhan'):
pingtai_shouyi = order.pingtai_kuozhan.pingtai_shouyi or Decimal('0.00')
dianpu_shouyi = order.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
update_shangpin_daily_stat(
shangpin_id=order.shangpin_id,
caozuo_leixing=2, # 3 = 退款
dingdan_jiage=order.jine,
pingtai_shouyi=pingtai_shouyi,
dianpu_zongshouyi=dianpu_shouyi
)
)
logger.info(f"商品统计更新完成商品ID: {order.shangpin_id}")
# ============================
# 情况2本地订单我方打手接单
# ============================
else:
if not dashou_id:
return Response({'code': 400, 'msg': '订单无接单打手,无法结算'})
if dashou_fencheng < 0:
return Response({'code': 400, 'msg': '打手分成金额无效'})
# ---------- 更新打手余额和统计 ----------
try:
dashou_user = UserMain.objects.get(yonghuid=dashou_id)
dashou_profile = dashou_user.dashou_profile
dashou_profile.chengjiaozongliang += 1
dashou_profile.yue += dashou_fencheng
dashou_profile.zonge += dashou_fencheng
dashou_profile.jinrishouyi += dashou_fencheng
dashou_profile.jinyueshouyi += dashou_fencheng
dashou_profile.zhuangtai = 1 # 空闲
dashou_profile.save()
except (UserMain.DoesNotExist, ObjectDoesNotExist):
logger.warning(f"本地订单结算:打手 {dashou_id} 不存在,跳过打手更新")
# ---------- 更新订单状态 ----------
order.zhuangtai = 3
order.clkf = str(shop_id)
order.save()
# ---------- 打手每日统计(成交) ----------
try:
update_dashou_daily_by_action(
yonghuid=dashou_id,
amount=dashou_fencheng,
action=2 # 2 表示成交(结算)
update_dianpu_daily_stat(
dianpu_id=shop_id,
caozuo_leixing=2, # 结算操作
dingdan_jiage=jine,
dianpu_shouyi=pingtai_ext.dianpu_shouyi,
)
except Exception as e:
logger.error(f"打手每日统计更新失败: {e}")
logger.error(f"店铺每日统计更新失败: {e}")
# ---------- 店铺收益统计(结算) ----------
# 根据订单上的店铺收益 (从扩展表取) 更新店铺每日统计及余额
# 前提:订单创建时已存储了 dianpu_shouyi 到扩展表
if pingtai_ext.dianpu_shouyi:
try:
# 商品每日统计只要有商品ID就执行
if order.shangpin_id:
# 从扩展表获取已计算好的收益值(下单时已存储)
pingtai_shouyi = Decimal('0.00')
dianpu_shouyi = Decimal('0.00')
if hasattr(order, 'pingtai_kuozhan'):
pingtai_shouyi = order.pingtai_kuozhan.pingtai_shouyi or Decimal('0.00')
dianpu_shouyi = order.pingtai_kuozhan.dianpu_shouyi or Decimal('0.00')
update_shangpin_daily_stat(
shangpin_id=order.shangpin_id,
caozuo_leixing=2, # 3 = 退款
dingdan_jiage=order.jine,
pingtai_shouyi=pingtai_shouyi,
dianpu_zongshouyi=dianpu_shouyi
)
logger.info(f"商品统计更新完成商品ID: {order.shangpin_id}")
update_dianpu_daily_stat(
dianpu_id=shop_id,
caozuo_leixing=2, # 结算操作
dingdan_jiage=jine,
dianpu_shouyi=pingtai_ext.dianpu_shouyi,
# 如果涉及上级分红,可从扩展表取相应字段传入,此处略
)
except Exception as e:
logger.error(f"店铺每日统计更新失败: {e}")
# ========== 6. 记录操作日志 ==========
# ========== 5. 记录操作日志 ==========
logger.info(f"强制结单成功,订单 {dingdan_id},店铺 {shop_id}")
return Response({'code': 200, 'msg': '强制结单成功'})
@@ -3006,40 +2899,6 @@ class ShopForceCompleteView(APIView):
logger.error(f"强制结单接口异常: {str(e)}", exc_info=True)
return Response({'code': 500, 'msg': '服务器内部错误'})
# ==================== 通知对方平台(异步) ====================
def _notify_partner_order_complete(self, partner_club_id, partner_order_id, shop_id):
"""通知对方平台我方订单已完成状态3"""
try:
# 尝试获取对方域名等配置(与退款接口类似)
my_config = ClubConfig.objects.filter(is_self=1).first()
if not my_config:
logger.error("未配置我方俱乐部信息,无法通知对方")
return
self_club_id = my_config.club_id
club_rel = Club.objects.get(club_id=self_club_id, partner_club_id=partner_club_id)
partner_domain = club_rel.partner_domain.rstrip('/')
notify_url = f"{partner_domain}/houtai/dfddtk"
payload = {
'order_id': partner_order_id,
'club_id': self_club_id,
'status': 3
}
resp = requests.post(notify_url, json=payload, timeout=3)
if resp.status_code == 200:
resp_data = resp.json()
if resp_data.get('code') == 0:
logger.info(f"通知对方订单已完成: {partner_order_id}")
else:
logger.warning(f"对方平台返回错误: {resp_data.get('msg')}")
else:
logger.warning(f"通知对方HTTP错误: {resp.status_code}")
except Exception as e:
logger.error(f"通知对方平台异常: {e}")
@@ -3105,13 +2964,8 @@ class ShopTransferHallView(APIView):
# ---------- 5. 提取关键字段 ----------
current_dashou_id = order.jiedan_dashou_id
zhiding_id = order.zhiding_id
partner_club_id = order.partner_club_id
partner_order_id = order.partner_order_id
dashou_fencheng = order.dashou_fencheng or 0 # 用于退款统计
# 是否跨平台:只要有对方信息即认为是跨平台订单
is_cross = bool(partner_club_id or partner_order_id)
try:
with transaction.atomic():
# 锁定订单行
@@ -3130,8 +2984,8 @@ class ShopTransferHallView(APIView):
operator=str(shop_id)
)
# ---------- 7. 释放本地打手 + 退款统计(仅当非跨平台时处理) ----------
if not is_cross and current_dashou_id:
# ---------- 7. 释放本地打手 + 退款统计 ----------
if current_dashou_id:
try:
dashou_profile = UserDashou.objects.get(user__yonghuid=current_dashou_id)
dashou_profile.zhuangtai = 1 # 设为空闲
@@ -3150,9 +3004,7 @@ class ShopTransferHallView(APIView):
except Exception as e:
logger.error(f"打手每日统计失败: {e}")
# ---------- 8. 清空对方平台信息并重置订单 ----------
order.partner_club_id = None
order.partner_order_id = None
# ---------- 8. 重置订单 ----------
order.jiedan_dashou_id = None
order.clkf = str(shop_id)
@@ -3160,59 +3012,6 @@ class ShopTransferHallView(APIView):
order.zhuangtai = 7 if zhiding_id else 1
order.save()
# ---------- 9. 异步通知对方平台(如果有对方信息) ----------
if is_cross and partner_club_id and partner_order_id:
# 获取我方俱乐部ID
my_club_config = None
try:
my_club_config = ClubConfig.objects.filter(is_self=1).first()
except Exception as e:
logger.error(f"获取俱乐部配置失败: {e}")
if my_club_config:
self_club_id = my_club_config.club_id
def notify():
try:
club_rel = Club.objects.get(club_id=self_club_id, partner_club_id=partner_club_id)
partner_domain = club_rel.partner_domain.rstrip('/')
notify_url = f"{partner_domain}/houtai/kpttzzydt"
payload = {
'order_id': partner_order_id,
'club_id': self_club_id
}
resp = requests.post(notify_url, json=payload, timeout=3)
if resp.status_code == 200:
resp_json = resp.json()
if resp_json.get('code') == 0:
# 更新跨平台订单数据(原接口逻辑)
try:
cross_data, _ = CrossPlatformOrderData.objects.get_or_create(
dingdan_id=dingdan_id,
defaults={
'partner_order_id': partner_order_id,
'partner_club_id': partner_club_id,
'partner_order_status': resp_json.get('data', {}).get('partner_status', 0),
'partner_dashou_id': '',
'partner_amount': order.jine or 0,
}
)
if not _:
cross_data.partner_order_status = resp_json.get('data', {}).get('partner_status', 0)
cross_data.save(update_fields=['partner_order_status'])
logger.info(f"转移大厅通知对方成功: {dingdan_id}")
except Exception as e:
logger.error(f"更新跨平台订单数据失败: {e}")
else:
logger.warning(f"对方平台返回错误: {resp_json.get('msg')}")
else:
logger.warning(f"对方接口HTTP错误: {resp.status_code}")
except Club.DoesNotExist:
logger.error(f"未找到对方俱乐部配置: partner_club_id={partner_club_id}")
except Exception as e:
logger.error(f"转移大厅通知对方异常: {e}")
threading.Thread(target=notify).start()
logger.info(f"转移大厅成功,订单 {dingdan_id}")
return Response({'code': 200, 'msg': '转移大厅成功'})
@@ -3292,13 +3091,8 @@ class ShopFineApplyView(APIView):
if Fadan.objects.filter(beichufa_id=dashou_id, guanliandingdan_id=dingdan_id).exists():
return Response({'code': 400, 'msg': '该打手已被罚款过'})
# ---------- 6. 跨平台相关字段 ----------
partner_order_id = order.partner_order_id or ''
partner_club_id = order.partner_club_id or ''
dispatch_type = order.dispatch_type or 0 # 1=我方派单2=对方派单
# 本地创建罚单的通用函数
def create_local_fadan(partner_club=''):
# ---------- 6. 创建罚单 ----------
with transaction.atomic():
Fadan.objects.create(
beichufa_id=dashou_id,
shenqing_chufa=str(shop_id), # 申请人记为店铺ID
@@ -3309,64 +3103,9 @@ class ShopFineApplyView(APIView):
zhuangtai=1, # 待缴纳
yingxiang_qiangdan=yingxiang_qiangdan,
shenqingren_shenfen=4, # 申请人身份4 店铺管理员
partner_club_id=partner_club,
)
# ---------- 7. 判断处罚流向 ----------
# 情况A没有对方订单ID或对方派单 → 本地处罚
if not partner_order_id or dispatch_type == 2:
with transaction.atomic():
create_local_fadan()
logger.info(f"本地罚款成功: 订单 {dingdan_id}, 打手 {dashou_id}, 金额 {fakuanjine}")
return Response({'code': 200, 'msg': '罚款已生成'})
# ---------- 8. 情况B有对方订单ID且我方派单 → 跨平台通知对方 ----------
# 获取我方俱乐部ID
try:
my_club = ClubConfig.objects.filter(is_self=1).first()
if not my_club:
return Response({'code': 500, 'msg': '系统配置错误,缺少本俱乐部信息'})
self_club_id = my_club.club_id
club_rel = Club.objects.get(club_id=self_club_id, partner_club_id=partner_club_id)
partner_domain = club_rel.partner_domain
except Club.DoesNotExist:
return Response({'code': 500, 'msg': '未找到对方平台配置,无法通知'})
except Exception as e:
logger.error(f"获取对方平台信息失败: {e}")
return Response({'code': 500, 'msg': '获取对方平台信息失败'})
# 构造通知 payload
url = partner_domain.rstrip('/') + '/houtai/kffkdssq_notify'
payload = {
'order_id': partner_order_id, # 对方平台的订单ID
'club_id': self_club_id, # 我方俱乐部ID
'chufaliyou': chufaliyou,
'fakuanjine': fakuanjine,
'yingxiang_qiangdan': yingxiang_qiangdan,
'shenqingren_shenfen': 4, # 店铺管理员身份
'operator': str(shop_id),
}
# 带重试的通知
success = False
for _ in range(2):
try:
resp = requests.post(url, json=payload, timeout=3)
if resp.status_code == 200 and resp.json().get('code') == 0:
success = True
break
except Exception:
continue
if not success:
return Response({'code': 500, 'msg': '通知对方平台失败,请稍后重试'})
# 通知成功后,本地也记录一笔(标记为跨平台)
with transaction.atomic():
create_local_fadan(partner_club=partner_club_id)
logger.info(f"跨平台罚款通知成功: 订单 {dingdan_id}")
return Response({'code': 200, 'msg': '罚款已提交至对方平台'})
logger.info(f"本地罚款成功: 订单 {dingdan_id}, 打手 {dashou_id}, 金额 {fakuanjine}")
return Response({'code': 200, 'msg': '罚款已生成'})
except Exception as e:
logger.error(f"店铺罚款申请异常: {traceback.format_exc()}")

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('yonghu', '0001_initial'),
('users', '0001_initial'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('yonghu', '0002_adminprofile_yaoqingma'),
('users', '0002_adminprofile_yaoqingma'),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('yonghu', '0003_rankingrecord'),
('users', '0003_rankingrecord'),
]
operations = [

Some files were not shown because too many files have changed in this diff Show More