1.基本设定(basic)模块
1.1.models.py 设定
1.1.1.单位
商品的单位种类,例如:瓶/盒/次…等。
class Unit(models.Model):
title = models.CharField(max_length=16, unique=True, verbose_name='名称')
def __str__(self):
return self.title
class Meta:
verbose_name = '单位'
verbose_name_plural = verbose_name
1.1.2.合作门店
class Store(models.Model):
title = models.CharField(max_length=16, unique=True, verbose_name='名称')
def __str__(self):
return '{}-{}'.format(self.pk, self.title)
class Meta:
verbose_name = '合作门店'
verbose_name_plural = verbose_name
1.1.3.员工
class Employee(models.Model):
title = models.CharField(max_length=16, verbose_name='姓名')
mobile = models.CharField(max_length=11, blank=True, verbose_name='手机电话')
store = models.ForeignKey(Store, verbose_name='所属门店', on_delete=models.PROTECT)
entry_date = models.DateField(verbose_name='入职日期')
departure_date = models.DateField(blank=True, null=True, verbose_name='离职日期')
basic_wage = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='底薪', default=0)
created = models.DateTimeField(auto_now_add=True, verbose_name='建立时间')
create_user = models.ForeignKey('auth.User', verbose_name='建立人员', on_delete=models.PROTECT,
related_name='employee_create_user')
updated = models.DateTimeField(verbose_name='异动时间', null=True)
update_user = models.ForeignKey('auth.User', verbose_name='异动人员', on_delete=models.PROTECT,
related_name='employee_update_user', null=True)
def __str__(self):
return '{}-{}'.format(self.pk, self.title)
class Meta:
verbose_name = '员工'
verbose_name_plural = verbose_name
1.1.4.顾客
class Customer(models.Model):
title = models.CharField(max_length=16, verbose_name='姓名')
mobile = models.CharField(max_length=11, blank=True, verbose_name='手机电话')
store = models.ForeignKey(Store, verbose_name='办卡门店', on_delete=models.PROTECT)
birthday = models.DateField(verbose_name='出生日期')
weight = models.DecimalField(max_digits=8, decimal_places=1, verbose_name='现在体重', help_text='单位:KG')
height = models.DecimalField(max_digits=8, decimal_places=1, verbose_name='身高', help_text='单位:CM')
allergic = models.CharField(max_length=64, blank=True, verbose_name='过敏史')
address = models.CharField(max_length=32, blank=True, verbose_name='家庭地址')
depart_address = models.CharField(max_length=32, blank=True, verbose_name='工作地址')
depart_name = models.CharField(max_length=16, blank=True, verbose_name='单位名称')
entry_date = models.DateField(verbose_name='到店日期')
birth_period = models.DecimalField(max_digits=8, decimal_places=1, default=0, verbose_name='产后', help_text='月')
notes = models.CharField(max_length=64, blank=True, verbose_name='其他说明')
created = models.DateTimeField(auto_now_add=True, verbose_name='建立时间')
create_user = models.ForeignKey('auth.User', verbose_name='建立人员', on_delete=models.PROTECT,
related_name='customer_create_user')
updated = models.DateTimeField(verbose_name='异动时间', null=True)
update_user = models.ForeignKey('auth.User', verbose_name='异动人员', on_delete=models.PROTECT,
related_name='customer_update_user', null=True)
def __str__(self):
return '{}-{}'.format(self.pk, self.title)
class Meta:
verbose_name = '顾客'
verbose_name_plural = verbose_name
1.1.5.宝宝
顾客的宝宝胎次,目前尚未使用。
DELIVERY_CHOICES = (
(1, '顺产'),
(2, '剖宫产'),
)
class Baby(models.Model):
customer = models.ForeignKey(Customer, verbose_name='母亲', on_delete=models.PROTECT)
serial = models.PositiveSmallIntegerField(verbose_name='胎次')
birthday = models.DateField(verbose_name='出生日期')
delivery = models.PositiveSmallIntegerField(verbose_name='出生方式', choices=DELIVERY_CHOICES)
gest_week = models.PositiveIntegerField(verbose_name='孕周(周)')
weight = models.DecimalField(max_digits=8, decimal_places=1, verbose_name='宝宝出生体重(KG)')
bef_weight = models.DecimalField(max_digits=8, decimal_places=1, verbose_name='妈妈孕前体重(KG)')
birth_weight = models.DecimalField(max_digits=8, decimal_places=1, verbose_name='妈妈临盆体重(KG)')
care = models.CharField(max_length=64, blank=True, verbose_name='42天产检情况')
def __str__(self):
return '{}的第{}个宝宝'.format(self.customer.title, self.pk)
class Meta:
verbose_name = '宝宝'
verbose_name_plural = verbose_name
1.1.6.商品
如先前所述,分产品/论次服务/有效期间服务/套盒共四类商品,[产品类]商品出售后交易即完成,[论次服务类]与[有效期间类]服务在完成交易后,自动生成论次服务记录或有效期间服务记录。
TYPE_CHOICES = (
('1', '产品'),
('2', '论次服务'),
('3', '有效期间服务'),
('4', '套盒'),
)
STATUS_CHOICES = (
('0', '停止使用'),
('1', '正常'),
)
class Good(models.Model):
title = models.CharField(max_length=32, verbose_name='名称')
type = models.CharField(max_length=1, verbose_name='类型', choices=TYPE_CHOICES,
help_text='当商品类型为时[论次服务/有效期间服务]时请添加理疗人员手工费'
',商品新增后不得修改[类型]')
period = models.PositiveIntegerField(verbose_name='有效期限', default=0,
help_text='单位:月;当商品类型为[有效期间服务]时才需要添加')
price = models.DecimalField(max_digits=16, decimal_places=2, verbose_name='建议售价')
unit = models.ForeignKey(Unit, verbose_name='单位', on_delete=models.PROTECT)
sale = models.BooleanField(verbose_name='是否直接销售', default=True)
status = models.CharField(max_length=1, verbose_name='状态', choices=STATUS_CHOICES, default='1')
notes = models.CharField(max_length=64, blank=True, verbose_name='其他说明')
created = models.DateTimeField(auto_now_add=True, verbose_name='建立时间')
create_user = models.ForeignKey('auth.User', verbose_name='建立人员', on_delete=models.PROTECT,
related_name='good_create_user')
updated = models.DateTimeField(verbose_name='异动时间', null=True)
update_user = models.ForeignKey('auth.User', verbose_name='异动人员', on_delete=models.PROTECT,
related_name='good_update_user', null=True)
def __str__(self):
return '{}-{}'.format(self.pk, self.title)
class Meta:
verbose_name = '商品'
verbose_name_plural = verbose_name
1.1.7.套盒内容商品
套盒类商品跟产品类商品一样,在门店要有库存(商品库存分布)才能贩售,而套盒内容商品记录套盒类商品有哪些商品。
class Compose(models.Model):
main = models.ForeignKey(Good, verbose_name='套盒商品', on_delete=models.PROTECT,
related_name='compose_main')
serial = models.PositiveIntegerField(verbose_name='序号', default=1)
content = models.ForeignKey(Good, verbose_name='套盒内容', on_delete=models.PROTECT,
related_name='compose_content')
quantity = models.PositiveIntegerField(verbose_name='数量')
def __str__(self):
return '{}-{}-{}'.format(self.main.title, self.serial, self.content.title)
class Meta:
verbose_name = '套盒内容商品'
verbose_name_plural = verbose_name
unique_together = ("main", "serial")
1.1.8.手工费
当客户购买论次服务记录或有效期间服务商品后,可以来门店享受对应的服务内容,替客户服务的员工在当月工资中就可以增加对应的手工费金额。
class Fee(models.Model):
good = models.ForeignKey(Good, verbose_name='商品', on_delete=models.PROTECT)
employee = models.ForeignKey(Employee, verbose_name='员工', on_delete=models.PROTECT)
price = models.DecimalField(max_digits=16, decimal_places=2, verbose_name='费用')
def __str__(self):
return '{}'.format(self.id)
class Meta:
verbose_name = '手工费'
verbose_name_plural = verbose_name
1.1.9.仓库
每个合作门店可以有多个仓库存放商品类与套盒类商品,在本版次系统中尚无实际作用。
class Storage(models.Model):
title = models.CharField(max_length=4, verbose_name='仓库名称', help_text='最多四码')
store = models.ForeignKey(Store, verbose_name='所属门店', on_delete=models.PROTECT, help_text='新增后则不可异动')
notes = models.CharField(max_length=64, verbose_name='描述', blank=True)
def __str__(self):
return '{}-{}'.format(self.id, self.title)
class Meta:
verbose_name = '仓库'
verbose_name_plural = verbose_name
1.2.admin.py 设定
1.2.1.UnitAdmin呈现画面
@admin.register(Unit)
class UnitAdmin(admin.ModelAdmin):
list_display = ['id', 'title']
view_on_site = False
def has_delete_permission(self, request, obj=None):
return False
1.2.2.StoreAdmin呈现画面
@admin.register(Store)
class StoreAdmin(admin.ModelAdmin):
list_display = ['id', 'title']
view_on_site = False
def has_delete_permission(self, request, obj=None):
return False
1.2.3.CustomerAdmin呈现画面
在顾客画面下方可以编辑宝宝胎次,并且能看到该顾客已来门店享受过的论次服务记录。
class CerviceInline(admin.TabularInline):
model = Cervice
fields = ['updated', 'good', 'store', 'employee', 'notes']
extra = 0
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.filter(updated__isnull=False).order_by('-updated')
def has_add_permission(self, request, obj=None):
return False
def has_change_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
return False
class BabyInline(admin.TabularInline):
model = Baby
fields = ['customer', 'serial', 'birthday', 'delivery', 'gest_week', 'weight',
'bef_weight', 'birth_weight', 'care']
extra = 0
def has_delete_permission(self, request, obj=None):
return False
@admin.register(Customer)
class CustomerAdmin(admin.ModelAdmin):
list_display = ['id', 'title', 'mobile', 'store', 'birthday', 'weight', 'height', 'allergic',
'address', 'depart_address', 'depart_name', 'entry_date', 'birth_period', 'notes']
fields = ['title', 'mobile', 'store', 'birthday', 'weight', 'height', 'allergic',
'address', 'depart_address', 'depart_name', 'entry_date', 'birth_period', 'notes',
'created', 'create_user', 'updated', 'update_user']
readonly_fields = ['created', 'create_user', 'updated', 'update_user']
inlines = [BabyInline, CerviceInline]
view_on_site = False
def save_model(self, request, obj, form, change):
if not change:
obj.create_user = request.user
else:
obj.update_user = request.user
obj.updated = datetime.now()
super().save_model(request, obj, form, change)
def has_delete_permission(self, request, obj=None):
return False
1.2.4.GoodAdmin呈现画面
员工的手工费可以在商品处设定,也可以在员工处设定,套盒类商品可以设定套盒内的商品与数量。
"""
手工费检查
1.商品类型为2(论次服务)与3(有效期间服务)时才需要设定手工费
"""
class FeeCheckInlineFormset(forms.models.BaseInlineFormSet):
def clean(self):
for form in self.forms:
if form.cleaned_data:
good = form.cleaned_data.get('good')
if good.type not in ('2', '3'):
raise forms.ValidationError("商品类型为[论次服务]与3[有效期间服务]时才需要设定手工费。")
class FeeInline(admin.TabularInline):
model = Fee
formset = FeeCheckInlineFormset
fields = ['good', 'employee', 'price']
extra = 0
def has_delete_permission(self, request, obj=None):
return False
"""
套盒内容商品
1.main的type必须是4[套盒]
2.content的type不能是4[套盒]
3.content的type是3[有效期间服务]时,数量只能是1
4.内容的[序号]不可重复
"""
class ComposeCheckInlineFormset(forms.models.BaseInlineFormSet):
def clean(self):
serial_list = []
for form in self.forms:
if form.cleaned_data:
main = form.cleaned_data.get('main')
serial = form.cleaned_data.get('serial')
content = form.cleaned_data.get('content')
quantity = form.cleaned_data.get('quantity')
if main.type != '4':
raise forms.ValidationError("套盒商品的类型必须为4[套盒]。")
if content.type == '4':
raise forms.ValidationError("套盒内容的类型必须不得为4[套盒]。")
if content.type == '3':
if quantity != 1:
raise forms.ValidationError("套盒内容的类型为3[有效期间服务]时,数量只能是1。")
if not serial in serial_list:
serial_list.append(serial)
else:
raise forms.ValidationError("套盒内容的[序号]不可重复。")
class ComposeInline(admin.TabularInline):
model = Compose
fk_name = "main"
formset = ComposeCheckInlineFormset
fields = ['main', 'serial', 'content', 'quantity']
extra = 0
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "content":
kwargs["queryset"] = Good.objects.filter(~Q(type=4), status='1')
return super().formfield_for_foreignkey(db_field, request, **kwargs)
def has_delete_permission(self, request, obj=None):
return False
"""
商品检查
1.类型是[3有效期间服务]时period(有效期限)必须大于0
2.商品新增后不可修改[类型]
3.[套盒]类型产品必须直接销售
"""
class GoodCheckForm(forms.ModelForm):
def clean(self):
super(GoodCheckForm, self).clean()
type = self.cleaned_data.get('type')
period = self.cleaned_data.get('period')
sale = self.cleaned_data.get('sale')
if type == '3':
if period <= 0:
raise forms.ValidationError('类型是[有效期间服务]时[有效期限]必须大于0。')
elif type == '4':
if sale != True:
raise forms.ValidationError('[套盒]类型产品必须直接销售。')
if self.instance.type != '' and self.instance.type != type:
raise forms.ValidationError('商品新增后不可修改[类型]。')
@admin.register(Good)
class GoodAdmin(admin.ModelAdmin):
list_display = ['id', 'title', 'type', 'period', 'price', 'unit', 'sale', 'status']
fields = ['title', 'type', 'period', 'price', 'unit', 'sale', 'status', 'notes',
'created', 'create_user', 'updated', 'update_user']
readonly_fields = ['status', 'created', 'create_user', 'updated', 'update_user']
form = GoodCheckForm
inlines = [FeeInline, ComposeInline]
view_on_site = False
def save_model(self, request, obj, form, change):
if not change:
obj.create_user = request.user
else:
obj.update_user = request.user
obj.updated = datetime.now()
#当商品类型为[3/有效期间服务]时才需要添加
if obj.type != '3':
obj.period = 0
super().save_model(request, obj, form, change)
def has_delete_permission(self, request, obj=None):
return False
1.2.5.EmployeeAdmin呈现画面
@admin.register(Employee)
class EmployeeAdmin(admin.ModelAdmin):
list_display = ['id', 'title', 'mobile', 'store', 'entry_date', 'departure_date']
fields = ['title', 'mobile', 'store', 'entry_date', 'departure_date', 'basic_wage',
'created', 'create_user', 'updated', 'update_user']
readonly_fields = ['created', 'create_user', 'updated', 'update_user']
inlines = [FeeInline]
view_on_site = False
def save_model(self, request, obj, form, change):
if not change:
obj.create_user = request.user
else:
obj.update_user = request.user
obj.updated = datetime.now()
super().save_model(request, obj, form, change)
def has_delete_permission(self, request, obj=None):
return False
1.2.6.StorageAdmin呈现画面
"""
储位检查
1.所属门店不可异动(save_model检查)
"""
@admin.register(Storage)
class StorageAdmin(admin.ModelAdmin):
list_display = ['id', 'title', 'store', 'notes']
fields = ['title', 'store', 'notes']
view_on_site = False
def save_model(self, request, obj, form, change):
if not change:
super().save_model(request, obj, form, change)
else:
if 'store' in form.changed_data:
messages.error(request, '储位新增后[所属门店]不可异动。')
messages.set_level(request, messages.ERROR)
else:
super().save_model(request, obj, form, change)
def has_delete_permission(self, request, obj=None):
return False