加入了 GVSDSDK 模块,进行了 QModel 兼容层的尝试,生产环境可用
This commit is contained in:
28
gvsdsdk/order/__init__.py
Normal file
28
gvsdsdk/order/__init__.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""GVS-DSDK 订单模块
|
||||
|
||||
提供订单模板(OrderTemplate)和订单(Order)的 SAAS 级数据模型。
|
||||
子服务可基于模板快速创建订单,可选绑定支付网关和等级设置。
|
||||
|
||||
模型:
|
||||
OrderTemplate — 订单模板(定义订单结构、等级、支付配置)
|
||||
OrderTemplateItem — 订单模板项(模板中的行项目定义)
|
||||
OrderLevel — 订单等级(如 VIP、SVIP 等定价阶梯)
|
||||
Order — 订单实例
|
||||
OrderItem — 订单行项目
|
||||
"""
|
||||
|
||||
from gvsdsdk.order.models import (
|
||||
OrderLevel,
|
||||
OrderTemplate,
|
||||
OrderTemplateItem,
|
||||
Order,
|
||||
OrderItem,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'OrderLevel',
|
||||
'OrderTemplate',
|
||||
'OrderTemplateItem',
|
||||
'Order',
|
||||
'OrderItem',
|
||||
]
|
||||
448
gvsdsdk/order/models.py
Normal file
448
gvsdsdk/order/models.py
Normal file
@@ -0,0 +1,448 @@
|
||||
"""模块:订单 SAAS 数据模型
|
||||
SAAS 级订单模板与订单实例——支持等级定价、可选绑定支付网关。
|
||||
|
||||
设计原则:
|
||||
1. 模板驱动:通过 OrderTemplate 定义订单结构,子服务基于模板快速创建订单
|
||||
2. 等级定价:OrderLevel 定义不同等级的价格/权益,订单可关联等级
|
||||
3. 支付可选:订单可选绑定 PaymentGatewayConfig,不绑定则不涉及支付
|
||||
4. 不可变快照:订单创建后,模板变更不影响已有订单
|
||||
"""
|
||||
|
||||
import datetime
|
||||
from django.db import models
|
||||
from gvsdsdk.model_base import QModel
|
||||
from gvsdsdk.models import UUIDField
|
||||
|
||||
|
||||
# === 订单等级表 ===
|
||||
|
||||
class OrderLevel(QModel):
|
||||
"""订单等级表——定义订单模板的定价阶梯
|
||||
|
||||
例如:VIP 月卡、VIP 季卡、SVIP 年卡等。
|
||||
每个等级属于一个订单模板,有独立的价格和有效期。
|
||||
"""
|
||||
|
||||
LevelUUID = UUIDField(primary_key=True, verbose_name='等级UUID')
|
||||
Template = models.ForeignKey(
|
||||
'OrderTemplate', on_delete=models.CASCADE,
|
||||
related_name='Levels',
|
||||
verbose_name='订单模板',
|
||||
)
|
||||
LevelCode = models.CharField(max_length=64, verbose_name='等级编码')
|
||||
LevelName = models.CharField(max_length=128, verbose_name='等级名称')
|
||||
LevelDescription = models.CharField(max_length=512, default='', verbose_name='等级描述')
|
||||
Price = models.DecimalField(max_digits=18, decimal_places=4, default=0, verbose_name='价格')
|
||||
OriginalPrice = models.DecimalField(max_digits=18, decimal_places=4, default=0, verbose_name='原价')
|
||||
Currency = models.CharField(max_length=10, default='CNY', verbose_name='币种')
|
||||
DurationDays = models.IntegerField(default=0, verbose_name='有效天数')
|
||||
DurationMonths = models.IntegerField(default=0, verbose_name='有效月数')
|
||||
LevelSort = models.SmallIntegerField(default=0, verbose_name='排序')
|
||||
LevelStatus = models.SmallIntegerField(default=1, verbose_name='等级状态')
|
||||
LevelMetadata = models.JSONField(default=dict, verbose_name='等级元数据')
|
||||
CreateTime = models.DateTimeField(default=datetime.datetime.utcnow, verbose_name='创建时间')
|
||||
UpdateTime = models.DateTimeField(null=True, blank=True, verbose_name='更新时间')
|
||||
|
||||
class Meta:
|
||||
db_table = 'OrderLevel'
|
||||
app_label = 'gvsdsdk'
|
||||
verbose_name = '订单等级'
|
||||
verbose_name_plural = '订单等级'
|
||||
managed = False
|
||||
unique_together = [('Template', 'LevelCode')]
|
||||
ordering = ['LevelSort']
|
||||
indexes = [
|
||||
models.Index(fields=['Template', 'LevelStatus'], name='idx_ordlvl_template_status'),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.LevelName}({self.LevelCode})'
|
||||
|
||||
@property
|
||||
def IsActive(self):
|
||||
return self.LevelStatus == 1
|
||||
|
||||
def GetDuration(self):
|
||||
"""获取有效时长(天)"""
|
||||
return self.DurationDays + self.DurationMonths * 30
|
||||
|
||||
|
||||
# === 订单模板表 ===
|
||||
|
||||
class OrderTemplate(QModel):
|
||||
"""订单模板表——定义订单的结构与配置
|
||||
|
||||
每个模板属于一个租户(TenantUUID),可选关联一个公司(CompanyUUID)。
|
||||
模板定义了订单的基本信息、支付配置、等级设置等。
|
||||
子服务通过模板快速创建标准化的订单。
|
||||
"""
|
||||
|
||||
TPL_SERVICE = 'service'
|
||||
TPL_GOODS = 'goods'
|
||||
TPL_MEMBERSHIP = 'membership'
|
||||
TPL_RECHARGE = 'recharge'
|
||||
TPL_CUSTOM = 'custom'
|
||||
|
||||
TPL_TYPE_CHOICES = [
|
||||
(TPL_SERVICE, '服务'),
|
||||
(TPL_GOODS, '商品'),
|
||||
(TPL_MEMBERSHIP, '会员'),
|
||||
(TPL_RECHARGE, '充值'),
|
||||
(TPL_CUSTOM, '自定义'),
|
||||
]
|
||||
|
||||
TPL_DRAFT = 0
|
||||
TPL_ACTIVE = 1
|
||||
TPL_ARCHIVED = 2
|
||||
|
||||
TPL_STATUS_CHOICES = [
|
||||
(TPL_DRAFT, '草稿'),
|
||||
(TPL_ACTIVE, '启用'),
|
||||
(TPL_ARCHIVED, '归档'),
|
||||
]
|
||||
|
||||
TemplateUUID = UUIDField(primary_key=True, verbose_name='模板UUID')
|
||||
TenantUUID = UUIDField(verbose_name='租户UUID')
|
||||
CompanyUUID = UUIDField(null=True, blank=True, verbose_name='公司UUID')
|
||||
TemplateCode = models.CharField(max_length=64, verbose_name='模板编码')
|
||||
TemplateName = models.CharField(max_length=256, verbose_name='模板名称')
|
||||
TemplateDescription = models.CharField(max_length=512, default='', verbose_name='模板描述')
|
||||
TemplateType = models.CharField(max_length=32, choices=TPL_TYPE_CHOICES, verbose_name='模板类型')
|
||||
TemplateStatus = models.SmallIntegerField(
|
||||
default=TPL_DRAFT, choices=TPL_STATUS_CHOICES,
|
||||
verbose_name='模板状态',
|
||||
)
|
||||
# 可选绑定支付网关
|
||||
PaymentConfig = models.ForeignKey(
|
||||
'payment.PaymentGatewayConfig', on_delete=models.SET_NULL,
|
||||
null=True, blank=True, related_name='order_templates',
|
||||
verbose_name='支付网关配置',
|
||||
)
|
||||
# 订单级配置
|
||||
RequirePayment = models.BooleanField(default=True, verbose_name='需要支付')
|
||||
AllowRefund = models.BooleanField(default=False, verbose_name='允许退款')
|
||||
RefundPolicy = models.JSONField(default=dict, verbose_name='退款策略')
|
||||
AutoConfirm = models.BooleanField(default=False, verbose_name='自动确认')
|
||||
ConfirmTimeoutSeconds = models.IntegerField(default=0, verbose_name='确认超时秒数')
|
||||
# 模板元数据(扩展字段)
|
||||
TemplateMetadata = models.JSONField(default=dict, verbose_name='模板元数据')
|
||||
TemplateSort = models.SmallIntegerField(default=0, verbose_name='排序')
|
||||
CreateTime = models.DateTimeField(default=datetime.datetime.utcnow, verbose_name='创建时间')
|
||||
UpdateTime = models.DateTimeField(null=True, blank=True, verbose_name='更新时间')
|
||||
|
||||
class Meta:
|
||||
db_table = 'OrderTemplate'
|
||||
app_label = 'gvsdsdk'
|
||||
verbose_name = '订单模板'
|
||||
verbose_name_plural = '订单模板'
|
||||
managed = False
|
||||
unique_together = [('TenantUUID', 'TemplateCode')]
|
||||
ordering = ['TemplateSort', '-CreateTime']
|
||||
indexes = [
|
||||
models.Index(fields=['TenantUUID', 'TemplateStatus'], name='idx_ordtpl_tenant_status'),
|
||||
models.Index(fields=['TemplateType'], name='idx_ordtpl_type'),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.TemplateName}({self.TemplateCode})'
|
||||
|
||||
@property
|
||||
def IsActive(self):
|
||||
return self.TemplateStatus == self.TPL_ACTIVE
|
||||
|
||||
def GetLevels(self):
|
||||
"""获取模板的所有等级"""
|
||||
return self.Levels.filter(LevelStatus=1).order_by('LevelSort')
|
||||
|
||||
def GetItems(self):
|
||||
"""获取模板的所有行项目定义"""
|
||||
return self.Items.filter(ItemStatus=1).order_by('ItemSort')
|
||||
|
||||
|
||||
# === 订单模板项表 ===
|
||||
|
||||
class OrderTemplateItem(QModel):
|
||||
"""订单模板项表——定义模板中的行项目
|
||||
|
||||
每个行项目代表订单中的一个条目,如商品、服务项等。
|
||||
创建订单时,模板项会被复制到订单项中。
|
||||
"""
|
||||
|
||||
ITEM_MANDATORY = 0
|
||||
ITEM_OPTIONAL = 1
|
||||
|
||||
ITEM_OPTIONALITY_CHOICES = [
|
||||
(ITEM_MANDATORY, '必选'),
|
||||
(ITEM_OPTIONAL, '可选'),
|
||||
]
|
||||
|
||||
ItemUUID = UUIDField(primary_key=True, verbose_name='模板项UUID')
|
||||
Template = models.ForeignKey(
|
||||
OrderTemplate, on_delete=models.CASCADE,
|
||||
related_name='Items',
|
||||
verbose_name='订单模板',
|
||||
)
|
||||
ItemCode = models.CharField(max_length=64, verbose_name='项目编码')
|
||||
ItemName = models.CharField(max_length=256, verbose_name='项目名称')
|
||||
ItemDescription = models.CharField(max_length=512, default='', verbose_name='项目描述')
|
||||
ItemType = models.CharField(max_length=32, default='default', verbose_name='项目类型')
|
||||
UnitPrice = models.DecimalField(max_digits=18, decimal_places=4, default=0, verbose_name='单价')
|
||||
Currency = models.CharField(max_length=10, default='CNY', verbose_name='币种')
|
||||
DefaultQuantity = models.IntegerField(default=1, verbose_name='默认数量')
|
||||
MinQuantity = models.IntegerField(default=1, verbose_name='最小数量')
|
||||
MaxQuantity = models.IntegerField(default=999, verbose_name='最大数量')
|
||||
Optionality = models.SmallIntegerField(
|
||||
default=ITEM_MANDATORY, choices=ITEM_OPTIONALITY_CHOICES,
|
||||
verbose_name='是否可选',
|
||||
)
|
||||
ItemSort = models.SmallIntegerField(default=0, verbose_name='排序')
|
||||
ItemStatus = models.SmallIntegerField(default=1, verbose_name='项目状态')
|
||||
ItemMetadata = models.JSONField(default=dict, verbose_name='项目元数据')
|
||||
CreateTime = models.DateTimeField(default=datetime.datetime.utcnow, verbose_name='创建时间')
|
||||
|
||||
class Meta:
|
||||
db_table = 'OrderTemplateItem'
|
||||
app_label = 'gvsdsdk'
|
||||
verbose_name = '订单模板项'
|
||||
verbose_name_plural = '订单模板项'
|
||||
managed = False
|
||||
unique_together = [('Template', 'ItemCode')]
|
||||
ordering = ['ItemSort']
|
||||
indexes = [
|
||||
models.Index(fields=['Template', 'ItemStatus'], name='idx_ordtplitem_template_status'),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.ItemName}({self.ItemCode})'
|
||||
|
||||
|
||||
# === 订单表 ===
|
||||
|
||||
class Order(QModel):
|
||||
"""订单表——SAAS 级统一订单记录
|
||||
|
||||
每个订单基于一个模板创建,包含订单基本信息、等级、支付状态等。
|
||||
子服务通过此表管理业务订单生命周期。
|
||||
"""
|
||||
|
||||
ORD_PENDING = 0
|
||||
ORD_CONFIRMED = 1
|
||||
ORD_PAID = 2
|
||||
ORD_PROCESSING = 3
|
||||
ORD_COMPLETED = 4
|
||||
ORD_CANCELLED = 5
|
||||
ORD_REFUNDING = 6
|
||||
ORD_REFUNDED = 7
|
||||
ORD_CLOSED = 8
|
||||
|
||||
ORD_STATUS_CHOICES = [
|
||||
(ORD_PENDING, '待确认'),
|
||||
(ORD_CONFIRMED, '已确认'),
|
||||
(ORD_PAID, '已支付'),
|
||||
(ORD_PROCESSING, '处理中'),
|
||||
(ORD_COMPLETED, '已完成'),
|
||||
(ORD_CANCELLED, '已取消'),
|
||||
(ORD_REFUNDING, '退款中'),
|
||||
(ORD_REFUNDED, '已退款'),
|
||||
(ORD_CLOSED, '已关闭'),
|
||||
]
|
||||
|
||||
OrderUUID = UUIDField(primary_key=True, verbose_name='订单UUID')
|
||||
TenantUUID = UUIDField(verbose_name='租户UUID')
|
||||
CompanyUUID = UUIDField(null=True, blank=True, verbose_name='公司UUID')
|
||||
OrderNO = models.CharField(max_length=64, unique=True, verbose_name='订单编号')
|
||||
# 来源模板
|
||||
Template = models.ForeignKey(
|
||||
OrderTemplate, on_delete=models.SET_NULL,
|
||||
null=True, related_name='orders',
|
||||
verbose_name='订单模板',
|
||||
)
|
||||
# 等级
|
||||
Level = models.ForeignKey(
|
||||
OrderLevel, on_delete=models.SET_NULL,
|
||||
null=True, blank=True, related_name='orders',
|
||||
verbose_name='订单等级',
|
||||
)
|
||||
# 订单主体
|
||||
OrderTitle = models.CharField(max_length=256, verbose_name='订单标题')
|
||||
OrderDescription = models.CharField(max_length=1024, default='', verbose_name='订单描述')
|
||||
OrderType = models.CharField(max_length=32, verbose_name='订单类型')
|
||||
# 用户
|
||||
BuyerUserUUID = UUIDField(verbose_name='买家用户UUID')
|
||||
SellerUserUUID = UUIDField(null=True, blank=True, verbose_name='卖家用户UUID')
|
||||
# 金额
|
||||
TotalAmount = models.DecimalField(max_digits=18, decimal_places=4, default=0, verbose_name='总金额')
|
||||
DiscountAmount = models.DecimalField(max_digits=18, decimal_places=4, default=0, verbose_name='优惠金额')
|
||||
PayAmount = models.DecimalField(max_digits=18, decimal_places=4, default=0, verbose_name='实付金额')
|
||||
Currency = models.CharField(max_length=10, default='CNY', verbose_name='币种')
|
||||
# 状态
|
||||
OrderStatus = models.SmallIntegerField(
|
||||
default=ORD_PENDING, choices=ORD_STATUS_CHOICES,
|
||||
verbose_name='订单状态',
|
||||
)
|
||||
# 支付关联(可选)
|
||||
PaymentTransaction = models.ForeignKey(
|
||||
'payment.PaymentTransaction', on_delete=models.SET_NULL,
|
||||
null=True, blank=True, related_name='orders',
|
||||
verbose_name='支付交易',
|
||||
)
|
||||
PaymentConfig = models.ForeignKey(
|
||||
'payment.PaymentGatewayConfig', on_delete=models.SET_NULL,
|
||||
null=True, blank=True, related_name='paid_orders',
|
||||
verbose_name='支付网关配置',
|
||||
)
|
||||
# 时间
|
||||
ConfirmTime = models.DateTimeField(null=True, blank=True, verbose_name='确认时间')
|
||||
PayTime = models.DateTimeField(null=True, blank=True, verbose_name='支付时间')
|
||||
CompleteTime = models.DateTimeField(null=True, blank=True, verbose_name='完成时间')
|
||||
CancelTime = models.DateTimeField(null=True, blank=True, verbose_name='取消时间')
|
||||
ExpireTime = models.DateTimeField(null=True, blank=True, verbose_name='过期时间')
|
||||
# 快照(创建时冻结模板信息)
|
||||
TemplateSnapshot = models.JSONField(default=dict, verbose_name='模板快照')
|
||||
LevelSnapshot = models.JSONField(default=dict, verbose_name='等级快照')
|
||||
# 扩展
|
||||
OrderMetadata = models.JSONField(default=dict, verbose_name='订单元数据')
|
||||
Remark = models.CharField(max_length=512, default='', verbose_name='备注')
|
||||
CreateTime = models.DateTimeField(default=datetime.datetime.utcnow, verbose_name='创建时间')
|
||||
UpdateTime = models.DateTimeField(null=True, blank=True, verbose_name='更新时间')
|
||||
|
||||
class Meta:
|
||||
db_table = 'Order'
|
||||
app_label = 'gvsdsdk'
|
||||
verbose_name = '订单'
|
||||
verbose_name_plural = '订单'
|
||||
managed = False
|
||||
ordering = ['-CreateTime']
|
||||
indexes = [
|
||||
models.Index(fields=['TenantUUID', 'OrderStatus', 'CreateTime'], name='idx_order_tenant_status_time'),
|
||||
models.Index(fields=['BuyerUserUUID'], name='idx_order_buyer'),
|
||||
models.Index(fields=['OrderNO'], name='idx_order_no'),
|
||||
models.Index(fields=['OrderType'], name='idx_order_type'),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return self.OrderNO
|
||||
|
||||
@property
|
||||
def IsPaid(self):
|
||||
return self.OrderStatus >= self.ORD_PAID
|
||||
|
||||
@property
|
||||
def IsCompleted(self):
|
||||
return self.OrderStatus == self.ORD_COMPLETED
|
||||
|
||||
@property
|
||||
def IsCancelled(self):
|
||||
return self.OrderStatus == self.ORD_CANCELLED
|
||||
|
||||
@property
|
||||
def IsTerminal(self):
|
||||
return self.OrderStatus in (
|
||||
self.ORD_COMPLETED, self.ORD_CANCELLED,
|
||||
self.ORD_REFUNDED, self.ORD_CLOSED,
|
||||
)
|
||||
|
||||
def Confirm(self):
|
||||
"""确认订单"""
|
||||
self.OrderStatus = self.ORD_CONFIRMED
|
||||
self.ConfirmTime = datetime.datetime.utcnow()
|
||||
self.save(update_fields=['OrderStatus', 'ConfirmTime', 'UpdateTime'])
|
||||
|
||||
def MarkPaid(self, payment_transaction=None):
|
||||
"""标记为已支付"""
|
||||
self.OrderStatus = self.ORD_PAID
|
||||
self.PayTime = datetime.datetime.utcnow()
|
||||
if payment_transaction:
|
||||
self.PaymentTransaction = payment_transaction
|
||||
self.save(update_fields=['OrderStatus', 'PayTime', 'PaymentTransaction', 'UpdateTime'])
|
||||
|
||||
def StartProcessing(self):
|
||||
"""开始处理"""
|
||||
self.OrderStatus = self.ORD_PROCESSING
|
||||
self.save(update_fields=['OrderStatus', 'UpdateTime'])
|
||||
|
||||
def Complete(self):
|
||||
"""完成订单"""
|
||||
self.OrderStatus = self.ORD_COMPLETED
|
||||
self.CompleteTime = datetime.datetime.utcnow()
|
||||
self.save(update_fields=['OrderStatus', 'CompleteTime', 'UpdateTime'])
|
||||
|
||||
def Cancel(self, reason=''):
|
||||
"""取消订单"""
|
||||
self.OrderStatus = self.ORD_CANCELLED
|
||||
self.CancelTime = datetime.datetime.utcnow()
|
||||
if reason:
|
||||
self.Remark = reason
|
||||
self.save(update_fields=['OrderStatus', 'CancelTime', 'Remark', 'UpdateTime'])
|
||||
|
||||
def StartRefund(self):
|
||||
"""开始退款"""
|
||||
self.OrderStatus = self.ORD_REFUNDING
|
||||
self.save(update_fields=['OrderStatus', 'UpdateTime'])
|
||||
|
||||
def RefundDone(self):
|
||||
"""退款完成"""
|
||||
self.OrderStatus = self.ORD_REFUNDED
|
||||
self.save(update_fields=['OrderStatus', 'UpdateTime'])
|
||||
|
||||
def Close(self):
|
||||
"""关闭订单"""
|
||||
self.OrderStatus = self.ORD_CLOSED
|
||||
self.save(update_fields=['OrderStatus', 'UpdateTime'])
|
||||
|
||||
def GetItems(self):
|
||||
"""获取订单所有行项目"""
|
||||
return self.Items.all().order_by('ItemSort')
|
||||
|
||||
|
||||
# === 订单项表 ===
|
||||
|
||||
class OrderItem(QModel):
|
||||
"""订单项表——订单中的行项目
|
||||
|
||||
创建订单时从模板项复制生成,记录实际购买的商品/服务。
|
||||
"""
|
||||
|
||||
ItemUUID = UUIDField(primary_key=True, verbose_name='订单项UUID')
|
||||
Order = models.ForeignKey(
|
||||
Order, on_delete=models.CASCADE,
|
||||
related_name='Items',
|
||||
verbose_name='订单',
|
||||
)
|
||||
# 来源模板项(可选,手动创建的订单可能没有模板项)
|
||||
TemplateItem = models.ForeignKey(
|
||||
OrderTemplateItem, on_delete=models.SET_NULL,
|
||||
null=True, blank=True, related_name='order_items',
|
||||
verbose_name='模板项',
|
||||
)
|
||||
ItemCode = models.CharField(max_length=64, verbose_name='项目编码')
|
||||
ItemName = models.CharField(max_length=256, verbose_name='项目名称')
|
||||
ItemDescription = models.CharField(max_length=512, default='', verbose_name='项目描述')
|
||||
ItemType = models.CharField(max_length=32, default='default', verbose_name='项目类型')
|
||||
UnitPrice = models.DecimalField(max_digits=18, decimal_places=4, default=0, verbose_name='单价')
|
||||
Quantity = models.IntegerField(default=1, verbose_name='数量')
|
||||
Subtotal = models.DecimalField(max_digits=18, decimal_places=4, default=0, verbose_name='小计')
|
||||
Currency = models.CharField(max_length=10, default='CNY', verbose_name='币种')
|
||||
ItemSort = models.SmallIntegerField(default=0, verbose_name='排序')
|
||||
ItemStatus = models.SmallIntegerField(default=1, verbose_name='项目状态')
|
||||
ItemMetadata = models.JSONField(default=dict, verbose_name='项目元数据')
|
||||
CreateTime = models.DateTimeField(default=datetime.datetime.utcnow, verbose_name='创建时间')
|
||||
|
||||
class Meta:
|
||||
db_table = 'OrderItem'
|
||||
app_label = 'gvsdsdk'
|
||||
verbose_name = '订单项'
|
||||
verbose_name_plural = '订单项'
|
||||
managed = False
|
||||
ordering = ['ItemSort']
|
||||
indexes = [
|
||||
models.Index(fields=['Order'], name='idx_orditem_order'),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.ItemName}x{self.Quantity}'
|
||||
|
||||
def CalcSubtotal(self):
|
||||
"""计算小计"""
|
||||
self.Subtotal = self.UnitPrice * self.Quantity
|
||||
return self.Subtotal
|
||||
Reference in New Issue
Block a user