累死了,删除了所有跨平台逻辑,进行了表迁移
This commit is contained in:
@@ -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 = {
|
||||
|
||||
@@ -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="角色",
|
||||
),
|
||||
),
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("houtai", "0001_initial"),
|
||||
("backend", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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='角色'),
|
||||
),
|
||||
]
|
||||
@@ -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='跨平台脚本询问订单状态'),
|
||||
|
||||
|
||||
|
||||
]
|
||||
3900
backend/view.py
3900
backend/view.py
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('peizhi', '0001_initial'),
|
||||
('config', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('peizhi', '0002_shangjiamoban_shangjialianjie'),
|
||||
('config', '0002_shangjiamoban_shangjialianjie'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('peizhi', '0004_tixianquotadefault'),
|
||||
('config', '0004_tixianquotadefault'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('peizhi', '0006_clubconfig_accountpermission'),
|
||||
('config', '0006_clubconfig_accountpermission'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('peizhi', '0011_withdrawconfig'),
|
||||
('config', '0011_withdrawconfig'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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='用户类型'),
|
||||
),
|
||||
]
|
||||
152
config/models.py
152
config/models.py
@@ -270,112 +270,6 @@ class WithdrawConfig(models.Model):
|
||||
|
||||
|
||||
|
||||
class Club(models.Model):
|
||||
"""合作俱乐部/平台信息表"""
|
||||
# 自己的俱乐部ID(6位字符)
|
||||
club_id = models.CharField(max_length=6, db_index=True, verbose_name='本俱乐部ID')
|
||||
# 对方的俱乐部ID(6位字符)
|
||||
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密钥等
|
||||
"""
|
||||
# 俱乐部ID(6位字符,与 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):
|
||||
|
||||
@@ -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
35
fix_migration_history.py
Normal 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")
|
||||
@@ -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)
|
||||
@@ -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': '商家订单扩展',
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dingdan', '0001_initial'),
|
||||
('orders', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dingdan', '0006_chufatupian'),
|
||||
('orders', '0006_chufatupian'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dingdan', '0007_chufajilu_ssliyou'),
|
||||
('orders', '0007_chufajilu_ssliyou'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dingdan', '0011_dingdan_tkly'),
|
||||
('orders', '0011_dingdan_tkly'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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': '罚款申诉图片',
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dingdan', '0021_fadanshensutupian'),
|
||||
('orders', '0021_fadanshensutupian'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dingdan', '0023_fadanshensutupian_yongtu'),
|
||||
('orders', '0023_fadanshensutupian_yongtu'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dingdan', '0027_dingdanpeihu'),
|
||||
('orders', '0027_dingdanpeihu'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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',
|
||||
),
|
||||
]
|
||||
@@ -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):
|
||||
"""
|
||||
订单打手变更历史表
|
||||
|
||||
@@ -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时,提交定时任务
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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='前端聊天转发'), # 群聊消息代理发送
|
||||
|
||||
224
orders/utils.py
224
orders/utils.py
@@ -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)。
|
||||
|
||||
1061
orders/views.py
1061
orders/views.py
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shangpin', '0001_initial'),
|
||||
('products', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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': '多次分红配置',
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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': '商品每日统计',
|
||||
|
||||
@@ -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='所属板块'),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -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='所属板块'),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shangpin', '0014_huiyuan_bankuai'),
|
||||
('products', '0014_huiyuan_bankuai'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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',
|
||||
),
|
||||
]
|
||||
@@ -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(
|
||||
|
||||
@@ -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': '打手订单表现',
|
||||
|
||||
@@ -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='关联订单'),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -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='所属板块'),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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': '订单需求标签',
|
||||
|
||||
@@ -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': '审核记录',
|
||||
|
||||
@@ -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': '考核官板块关联',
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dengji', '0007_kaoheguanbankuai'),
|
||||
('rank', '0007_kaoheguanbankuai'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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': '考核次数费用',
|
||||
|
||||
@@ -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': '考核记录费用',
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dengji', '0010_kaohejilufeiyong'),
|
||||
('rank', '0010_kaohejilufeiyong'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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': '店铺商品类型映射',
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shangdian', '0001_initial'),
|
||||
('shop', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shangdian', '0004_dianpushangpinshenheshezhi'),
|
||||
('shop', '0004_dianpushangpinshenheshezhi'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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='映射的公共商品类型'
|
||||
|
||||
395
shop/views.py
395
shop/views.py
@@ -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()}")
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('yonghu', '0001_initial'),
|
||||
('users', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('yonghu', '0002_adminprofile_yaoqingma'),
|
||||
('users', '0002_adminprofile_yaoqingma'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user