Django用admin开发的产康中心进销存系统-3

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

Django用admin开发的产康中心进销存系统-3

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

Django用admin开发的产康中心进销存系统-3

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

Django用admin开发的产康中心进销存系统-3
Django用admin开发的产康中心进销存系统-3

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

Django用admin开发的产康中心进销存系统-3
Django用admin开发的产康中心进销存系统-3

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

Django用admin开发的产康中心进销存系统-3
Django用admin开发的产康中心进销存系统-3

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

Django用admin开发的产康中心进销存系统-3

上一篇:python模块-optparse(解析命令行参数)


下一篇:【1120 | Day63】序列化器的创建及声明