135 lines
4.9 KiB
Python
135 lines
4.9 KiB
Python
"""全渠道与电商对接模型:
|
||
1. ChannelAccount 电商平台授权店铺配置(抖店、拼多多、1688 等)
|
||
2. ChannelOrder 外部拉取订单及本地销售订单映射
|
||
3. WebhookEvent 外部回调与事件分发日志
|
||
"""
|
||
|
||
from django.db import models
|
||
from apps.core.base_models import TenantScopedModel
|
||
|
||
|
||
class ChannelAccount(TenantScopedModel):
|
||
"""渠道授权店铺配置。"""
|
||
|
||
PLATFORM_CHOICES = [
|
||
("douyin", "抖音电商 / 抖店"),
|
||
("pinduoduo", "拼多多"),
|
||
("1688", "1688 阿里分销"),
|
||
("kuaishou", "快手小店"),
|
||
("custom", "自定义开放接口"),
|
||
]
|
||
|
||
platform = models.CharField(max_length=32, choices=PLATFORM_CHOICES, default="douyin")
|
||
shop_id = models.CharField(max_length=64, help_text="外部平台店铺ID")
|
||
shop_name = models.CharField(max_length=128, help_text="店铺名称")
|
||
app_key = models.CharField(max_length=128, blank=True, default="")
|
||
app_secret = models.CharField(max_length=255, blank=True, default="")
|
||
access_token = models.TextField(blank=True, default="")
|
||
refresh_token = models.TextField(blank=True, default="")
|
||
token_expires_at = models.DateTimeField(null=True, blank=True)
|
||
is_active = models.BooleanField(default=True)
|
||
|
||
# 业务映射默认值
|
||
default_warehouse = models.ForeignKey(
|
||
"inventory.Warehouse",
|
||
null=True,
|
||
blank=True,
|
||
on_delete=models.SET_NULL,
|
||
related_name="+",
|
||
help_text="该店铺订单默认出库仓库",
|
||
)
|
||
default_customer = models.ForeignKey(
|
||
"partner.Customer",
|
||
null=True,
|
||
blank=True,
|
||
on_delete=models.SET_NULL,
|
||
related_name="+",
|
||
help_text="该店铺归属的客户(挂账往来)",
|
||
)
|
||
|
||
class Meta:
|
||
db_table = "channel_account"
|
||
unique_together = [("tenant", "platform", "shop_id")]
|
||
verbose_name_plural = "电商店铺配置"
|
||
ordering = ["platform", "shop_name"]
|
||
|
||
def __str__(self):
|
||
return f"[{self.get_platform_display()}] {self.shop_name} ({self.shop_id})"
|
||
|
||
|
||
class ChannelOrder(TenantScopedModel):
|
||
"""外部渠道拉取的订单。"""
|
||
|
||
SYNC_STATUS_CHOICES = [
|
||
("pending", "待转单"),
|
||
("converted", "已转销售单"),
|
||
("failed", "转单失败"),
|
||
("ignored", "已忽略"),
|
||
]
|
||
|
||
channel_account = models.ForeignKey(
|
||
ChannelAccount,
|
||
on_delete=models.CASCADE,
|
||
related_name="orders",
|
||
)
|
||
external_order_id = models.CharField(max_length=128, help_text="外部平台订单号")
|
||
order_status = models.CharField(max_length=64, default="", help_text="外部平台订单状态(如 PAID, SHIPPED)")
|
||
order_amount = models.DecimalField(max_digits=18, decimal_places=4, default=0)
|
||
buyer_name = models.CharField(max_length=64, blank=True, default="")
|
||
buyer_phone = models.CharField(max_length=32, blank=True, default="")
|
||
receiver_address = models.CharField(max_length=255, blank=True, default="")
|
||
|
||
sync_status = models.CharField(max_length=16, choices=SYNC_STATUS_CHOICES, default="pending")
|
||
sync_error = models.TextField(blank=True, default="")
|
||
|
||
# 关联生成的本地销售单
|
||
sales_order = models.ForeignKey(
|
||
"sales.SalesOrder",
|
||
null=True,
|
||
blank=True,
|
||
on_delete=models.SET_NULL,
|
||
related_name="channel_orders",
|
||
help_text="关联的内部销售订单",
|
||
)
|
||
|
||
raw_payload = models.JSONField(default=dict, blank=True, help_text="外部原始订单 JSON")
|
||
|
||
class Meta:
|
||
db_table = "channel_order"
|
||
unique_together = [("tenant", "channel_account", "external_order_id")]
|
||
verbose_name_plural = "渠道订单"
|
||
indexes = [
|
||
models.Index(fields=["tenant", "sync_status"]),
|
||
models.Index(fields=["tenant", "external_order_id"]),
|
||
]
|
||
ordering = ["-created_at"]
|
||
|
||
def __str__(self):
|
||
return f"{self.channel_account.shop_name} 订单: {self.external_order_id} [{self.sync_status}]"
|
||
|
||
|
||
class WebhookEvent(TenantScopedModel):
|
||
"""Webhook 回调与事件分发日志。"""
|
||
|
||
DIRECTION_CHOICES = [
|
||
("inbound", "外部推送回调"),
|
||
("outbound", "本系统向外推送"),
|
||
]
|
||
STATUS_CHOICES = [
|
||
("received", "已接收"),
|
||
("processed", "处理成功"),
|
||
("failed", "处理失败"),
|
||
]
|
||
|
||
direction = models.CharField(max_length=16, choices=DIRECTION_CHOICES, default="inbound")
|
||
event_type = models.CharField(max_length=64, help_text="事件类型,如 order.paid, stock.changed")
|
||
source = models.CharField(max_length=32, default="douyin", help_text="来源系统或平台")
|
||
payload = models.JSONField(default=dict, blank=True)
|
||
status = models.CharField(max_length=16, choices=STATUS_CHOICES, default="received")
|
||
error_message = models.TextField(blank=True, default="")
|
||
|
||
class Meta:
|
||
db_table = "channel_webhook_event"
|
||
verbose_name_plural = "Webhook事件日志"
|
||
ordering = ["-created_at"]
|