forked from erp-dev/erp
feat: auto complete stock change
This commit is contained in:
@@ -1,21 +1,63 @@
|
||||
from django.contrib import admin
|
||||
from basic_info.services import CustomerVisibilityService
|
||||
from . import models
|
||||
|
||||
|
||||
class AdminBase(admin.ModelAdmin):
|
||||
"""管理员基础类,定义通用配置"""
|
||||
|
||||
def get_readonly_fields(self, request, obj = ...):
|
||||
readonly_fields = list(super().get_readonly_fields(request, obj))
|
||||
if request.user.is_superuser:
|
||||
readonly_fields.append('merchant')
|
||||
return readonly_fields
|
||||
|
||||
def get_list_display(self, request):
|
||||
result = super().get_list_display(request)
|
||||
result = list(result)
|
||||
|
||||
if 'id' not in result:
|
||||
result = ['id'] + result
|
||||
|
||||
if request.user.is_superuser and 'merchant' not in result:
|
||||
result = result + ['merchant']
|
||||
|
||||
return result
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
if not change:
|
||||
if not obj.merchant_id:
|
||||
obj.merchant_id = request.user.employee.merchant.id
|
||||
return super().save_model(request, obj, form, change)
|
||||
|
||||
|
||||
@admin.register(models.QuickInput)
|
||||
class QuickInputAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'value', 'group')
|
||||
list_filter = ('group',)
|
||||
|
||||
|
||||
@admin.register(models.Merchant)
|
||||
class MerchantAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'type', 'email', 'mobile', 'auto_complete_stock_change')
|
||||
search_fields = ('name', 'mobile')
|
||||
list_filter = ('type', 'auto_complete_stock_change')
|
||||
|
||||
|
||||
@admin.register(models.Supplier)
|
||||
class SupplierAdmin(admin.ModelAdmin):
|
||||
class SupplierAdmin(AdminBase):
|
||||
list_display = ('name', 'area', 'email', 'mobile')
|
||||
search_fields = ('name', 'area', 'email', 'mobile')
|
||||
|
||||
|
||||
@admin.register(models.ProductCategory)
|
||||
class ProductCategoryAdmin(admin.ModelAdmin):
|
||||
class ProductCategoryAdmin(AdminBase):
|
||||
list_display = ('name', 'product_prefix', 'description')
|
||||
search_fields = ('name',)
|
||||
|
||||
|
||||
@admin.register(models.Product)
|
||||
class ProductAdmin(admin.ModelAdmin):
|
||||
class ProductAdmin(AdminBase):
|
||||
list_display = (
|
||||
'name',
|
||||
'category',
|
||||
@@ -31,29 +73,35 @@ class ProductAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
@admin.register(models.BankAccount)
|
||||
class BankAccountAdmin(admin.ModelAdmin):
|
||||
class BankAccountAdmin(AdminBase):
|
||||
list_display = ('name', 'auto_number')
|
||||
search_fields = ('name', 'auto_number')
|
||||
|
||||
|
||||
@admin.register(models.WareHouse)
|
||||
class WareHouseAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'location', 'area', 'mobile')
|
||||
search_fields = ('name', 'area')
|
||||
class WareHouseAdmin(AdminBase):
|
||||
list_display = ('name', 'location', 'area', 'mobile', 'mode')
|
||||
list_filter = ('area', 'mode')
|
||||
search_fields = ('name', 'location', 'mobile')
|
||||
|
||||
|
||||
@admin.register(models.Customer)
|
||||
class CustomerAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'area', 'email', 'mobile', 'total_debt')
|
||||
class CustomerAdmin(AdminBase):
|
||||
list_display = ('name', 'area', 'email', 'mobile', 'created_by', 'total_debt')
|
||||
search_fields = ('name', 'area', 'email', 'mobile')
|
||||
|
||||
def get_queryset(self, request):
|
||||
qs = super().get_queryset(request)
|
||||
qs = CustomerVisibilityService.filter_customers_for_employee(qs, request.user)
|
||||
return qs
|
||||
|
||||
@admin.display(boolean=False, description='累欠金额')
|
||||
def total_debt(self, obj):
|
||||
return '0 (动态逻辑字段待实现)'
|
||||
|
||||
|
||||
@admin.register(models.Employee)
|
||||
class EmployeeAdmin(admin.ModelAdmin):
|
||||
class EmployeeAdmin(AdminBase):
|
||||
list_display = ('name', 'mobile', 'status', 'job_type', 'sys_user')
|
||||
search_fields = ('name', 'mobile')
|
||||
list_filter = (
|
||||
@@ -63,20 +111,20 @@ class EmployeeAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
@admin.register(models.DeviceInfo)
|
||||
class DeviceInfoAdmin(admin.ModelAdmin):
|
||||
class DeviceInfoAdmin(AdminBase):
|
||||
list_display = ('name', 'type', 'is_occupied', 'status')
|
||||
search_fields = ('name', 'start_working_at', 'stop_working_at')
|
||||
list_filter = ('type', 'status')
|
||||
|
||||
|
||||
@admin.register(models.VehicleType)
|
||||
class VehicleTypeAdmin(admin.ModelAdmin):
|
||||
class VehicleTypeAdmin(AdminBase):
|
||||
list_display = ('name', 'description')
|
||||
search_fields = ('name',)
|
||||
|
||||
|
||||
@admin.register(models.VehicleTransportRecord)
|
||||
class VehicleTransportRecordAdmin(admin.ModelAdmin):
|
||||
class VehicleTransportRecordAdmin(AdminBase):
|
||||
list_display = ('driver_name', 'contact_number', 'delivery_date')
|
||||
search_fields = ('driver_name', 'contact_number')
|
||||
list_filter = ('vehicle_type',)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:06
|
||||
# Generated by Django 5.2.7 on 2025-11-06 05:33
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
@@ -9,9 +10,88 @@ class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Merchant',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='商户名称')),
|
||||
('type', models.IntegerField(choices=[(1, '布行'), (2, '印花厂')], verbose_name='商户类型')),
|
||||
('area', models.CharField(blank=True, max_length=100, null=True, verbose_name='地区')),
|
||||
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='电子邮箱')),
|
||||
('mobile', models.CharField(blank=True, max_length=20, null=True, verbose_name='手机')),
|
||||
('contact', models.TextField(blank=True, null=True, verbose_name='联系人')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '商户资料',
|
||||
'verbose_name_plural': '商户资料',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Employee',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='员工姓名')),
|
||||
('job_type', models.CharField(choices=[('打纸', '打纸'), ('滚筒', '滚筒'), ('仓库', '仓库'), ('送货', '送货')], default='打纸', max_length=20, verbose_name='职位')),
|
||||
('mobile', models.CharField(blank=True, max_length=20, null=True, verbose_name='手机')),
|
||||
('area', models.CharField(blank=True, max_length=100, null=True, verbose_name='地区')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('status', models.CharField(choices=[('在职', '在职'), ('离职', '离职')], default='在职', max_length=20, verbose_name='员工状态')),
|
||||
('sys_user', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='employee', to=settings.AUTH_USER_MODEL, verbose_name='系统用户')),
|
||||
('merchant', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='employees', to='basic_info.merchant', verbose_name='所属商户')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '员工资料',
|
||||
'verbose_name_plural': '员工资料',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='DeviceInfo',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='设备名称')),
|
||||
('type', models.CharField(choices=[('滚筒', '滚筒'), ('打印', '打印')], default='滚筒', max_length=20, verbose_name='设备类型')),
|
||||
('status', models.CharField(choices=[('使用中', '使用中'), ('停用', '停用'), ('维修中', '维修中')], default='使用中', max_length=20, verbose_name='设备状态')),
|
||||
('start_working_at', models.DateField(blank=True, null=True, verbose_name='开始服役日期')),
|
||||
('stop_working_at', models.DateField(blank=True, null=True, verbose_name='停止服役日期')),
|
||||
('is_occupied', models.BooleanField(default=False, verbose_name='是否被占用')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('merchant', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='devices', to='basic_info.merchant', verbose_name='所属商户')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '设备资料',
|
||||
'verbose_name_plural': '设备资料',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Customer',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='客户名称')),
|
||||
('mobile', models.CharField(max_length=20, verbose_name='手机')),
|
||||
('area', models.CharField(blank=True, max_length=100, null=True, verbose_name='地区')),
|
||||
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='电子邮箱')),
|
||||
('contact', models.CharField(blank=True, null=True, verbose_name='联系人')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('merchant', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='customers', to='basic_info.merchant', verbose_name='所属商户')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '客户资料',
|
||||
'verbose_name_plural': '客户资料',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='BankAccount',
|
||||
fields=[
|
||||
@@ -22,6 +102,7 @@ class Migration(migrations.Migration):
|
||||
('auto_number', models.CharField(max_length=50, verbose_name='自动编号')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('attachment', models.FileField(blank=True, null=True, upload_to='bank_accounts/', verbose_name='附件')),
|
||||
('merchant', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='bank_accounts', to='basic_info.merchant', verbose_name='所属商户')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '银行账户',
|
||||
@@ -37,6 +118,7 @@ class Migration(migrations.Migration):
|
||||
('name', models.CharField(max_length=100, verbose_name='类别名称')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='类别描述')),
|
||||
('product_prefix', models.CharField(max_length=5, verbose_name='产品编号前缀')),
|
||||
('merchant', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='product_categories', to='basic_info.merchant', verbose_name='所属商户')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '产品类别',
|
||||
@@ -44,17 +126,28 @@ class Migration(migrations.Migration):
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ProductUnit',
|
||||
name='Product',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=20, verbose_name='单位名称')),
|
||||
('name', models.CharField(max_length=100, verbose_name='产品名')),
|
||||
('human_id', models.CharField(blank=True, max_length=100, verbose_name='产品编号')),
|
||||
('color', models.CharField(blank=True, max_length=50, null=True, verbose_name='颜色')),
|
||||
('width_size', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='宽幅')),
|
||||
('single_price_in', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='参考进价')),
|
||||
('single_price_out', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='参考售价')),
|
||||
('unit', models.IntegerField(choices=[(1, '米'), (2, '码'), (3, '公斤')], default=1, verbose_name='单位')),
|
||||
('spec', models.CharField(blank=True, max_length=100, null=True, verbose_name='规格')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('image', models.ImageField(blank=True, null=True, upload_to='product_images/', verbose_name='产品图片')),
|
||||
('transform_rate', models.DecimalField(blank=True, decimal_places=4, max_digits=10, null=True, verbose_name='公斤转换率')),
|
||||
('merchant', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='products', to='basic_info.merchant', verbose_name='所属商户')),
|
||||
('category', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='products', to='basic_info.productcategory', verbose_name='产品类别')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '产品单位',
|
||||
'verbose_name_plural': '产品单位',
|
||||
'verbose_name': '产品资料',
|
||||
'verbose_name_plural': '产品资料',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
@@ -69,12 +162,46 @@ class Migration(migrations.Migration):
|
||||
('mobile', models.CharField(blank=True, max_length=20, null=True, verbose_name='手机')),
|
||||
('contact', models.TextField(blank=True, null=True, verbose_name='联系人')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('merchant', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='suppliers', to='basic_info.merchant', verbose_name='所属商户')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '供应商',
|
||||
'verbose_name_plural': '供应商',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='VehicleType',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=50, verbose_name='车辆类型名称')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('merchant', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='vehicle_types', to='basic_info.merchant', verbose_name='所属商户')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '车辆类型',
|
||||
'verbose_name_plural': '车辆类型',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='VehicleTransportRecord',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('driver_name', models.CharField(max_length=100, verbose_name='司机姓名')),
|
||||
('contact_number', models.CharField(blank=True, max_length=20, null=True, verbose_name='联系电话')),
|
||||
('license_plate', models.CharField(blank=True, max_length=20, null=True, verbose_name='车牌号码')),
|
||||
('delivery_date', models.DateField(verbose_name='送货日期')),
|
||||
('merchant', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='vehicle_transport_records', to='basic_info.merchant', verbose_name='所属商户')),
|
||||
('vehicle_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='vehicles', to='basic_info.vehicletype', verbose_name='车次')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '司机车次',
|
||||
'verbose_name_plural': '司机车次',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='WareHouse',
|
||||
fields=[
|
||||
@@ -87,47 +214,11 @@ class Migration(migrations.Migration):
|
||||
('mobile', models.CharField(blank=True, max_length=20, null=True, verbose_name='手机')),
|
||||
('area', models.CharField(blank=True, max_length=100, null=True, verbose_name='地区')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('merchant', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='warehouses', to='basic_info.merchant', verbose_name='所属商户')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '仓库资料',
|
||||
'verbose_name_plural': '仓库资料',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Product',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='产品名')),
|
||||
('human_id', models.CharField(blank=True, max_length=100, verbose_name='产品编号')),
|
||||
('color', models.CharField(blank=True, max_length=50, null=True, verbose_name='颜色')),
|
||||
('width_size', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='宽幅')),
|
||||
('single_price', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='单价')),
|
||||
('spec', models.CharField(blank=True, max_length=100, null=True, verbose_name='规格')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('category', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='products', to='basic_info.productcategory', verbose_name='产品类别')),
|
||||
('unit', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='products', to='basic_info.productunit', verbose_name='单位')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '产品资料',
|
||||
'verbose_name_plural': '产品资料',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PurchaseOrder',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('order_date', models.DateField(verbose_name='订单日期')),
|
||||
('total_amount', models.DecimalField(decimal_places=2, max_digits=15, verbose_name='总金额')),
|
||||
('remarks', models.TextField(blank=True, null=True, verbose_name='备注')),
|
||||
('supplier', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='purchase_orders', to='basic_info.supplier', verbose_name='供应商')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '采购单',
|
||||
'verbose_name_plural': '采购单',
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:11
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name='PurchaseOrder',
|
||||
),
|
||||
]
|
||||
28
basic_info/migrations/0002_quickinput.py
Normal file
28
basic_info/migrations/0002_quickinput.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-06 07:48
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='QuickInput',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='名')),
|
||||
('value', models.CharField(max_length=200, verbose_name='值')),
|
||||
('group', models.CharField(verbose_name='组')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '快捷输入',
|
||||
'verbose_name_plural': '快捷输入',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,17 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-06 07:55
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0002_quickinput'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='quickinput',
|
||||
unique_together={('name', 'group')},
|
||||
),
|
||||
]
|
||||
@@ -1,31 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:14
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0002_delete_purchaseorder'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Customer',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='客户名称')),
|
||||
('area', models.CharField(blank=True, max_length=100, null=True, verbose_name='地区')),
|
||||
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='电子邮箱')),
|
||||
('mobile', models.CharField(blank=True, max_length=20, null=True, verbose_name='手机')),
|
||||
('contact', models.TextField(blank=True, null=True, verbose_name='联系人')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '客户资料',
|
||||
'verbose_name_plural': '客户资料',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:15
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0003_customer'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='customer',
|
||||
name='contact',
|
||||
field=models.CharField(blank=True, null=True, verbose_name='联系人'),
|
||||
),
|
||||
]
|
||||
18
basic_info/migrations/0004_customer_visible_employees.py
Normal file
18
basic_info/migrations/0004_customer_visible_employees.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-06 09:31
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0003_alter_quickinput_unique_together'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='customer',
|
||||
name='visible_employees',
|
||||
field=models.ManyToManyField(blank=True, related_name='visible_customers', to='basic_info.employee', verbose_name='可见该客户的员工'),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:16
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0004_alter_customer_contact'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='customer',
|
||||
name='mobile',
|
||||
field=models.CharField(max_length=20, verbose_name='手机'),
|
||||
),
|
||||
]
|
||||
19
basic_info/migrations/0005_customer_created_by.py
Normal file
19
basic_info/migrations/0005_customer_created_by.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-06 09:36
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0004_customer_visible_employees'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='customer',
|
||||
name='created_by',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='created_customers', to='basic_info.employee', verbose_name='创建者'),
|
||||
),
|
||||
]
|
||||
19
basic_info/migrations/0006_alter_product_merchant.py
Normal file
19
basic_info/migrations/0006_alter_product_merchant.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-07 06:03
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0005_customer_created_by'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='merchant',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='basic_info.merchant', verbose_name='所属商户'),
|
||||
),
|
||||
]
|
||||
@@ -1,33 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0005_alter_customer_mobile'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Employee',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='员工姓名')),
|
||||
('job_type', models.CharField(choices=[('打纸', '打纸'), ('滚筒', '滚筒'), ('仓库', '仓库'), ('送货', '送货')], default='打纸', max_length=20, verbose_name='职位')),
|
||||
('mobile', models.CharField(blank=True, max_length=20, null=True, verbose_name='手机')),
|
||||
('area', models.CharField(blank=True, max_length=100, null=True, verbose_name='地区')),
|
||||
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='电子邮箱')),
|
||||
('contact', models.CharField(blank=True, null=True, verbose_name='联系人')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('status', models.CharField(choices=[('在职', '在职'), ('离职', '离职')], default='在职', max_length=20, verbose_name='员工状态')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '员工资料',
|
||||
'verbose_name_plural': '员工资料',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -1,17 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:27
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0006_employee'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='employee',
|
||||
name='contact',
|
||||
),
|
||||
]
|
||||
18
basic_info/migrations/0007_warehouse_mode.py
Normal file
18
basic_info/migrations/0007_warehouse_mode.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-07 08:36
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0006_alter_product_merchant'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='warehouse',
|
||||
name='mode',
|
||||
field=models.IntegerField(choices=[(1, '严进宽出'), (2, '严进严出'), (3, '宽进宽出')], default=1, verbose_name='出入库模式'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-07 08:38
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0007_warehouse_mode'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='merchant',
|
||||
name='auto_complete_stock_change',
|
||||
field=models.BooleanField(default=False, verbose_name='自动确认库存变动'),
|
||||
),
|
||||
]
|
||||
@@ -1,17 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:29
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0007_remove_employee_contact'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='employee',
|
||||
name='email',
|
||||
),
|
||||
]
|
||||
@@ -1,21 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 07:05
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0008_remove_employee_email'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='employee',
|
||||
name='sys_user',
|
||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='employee', to=settings.AUTH_USER_MODEL, verbose_name='系统用户'),
|
||||
),
|
||||
]
|
||||
@@ -1,32 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 07:14
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0009_employee_sys_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='DeviceInfo',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='设备名称')),
|
||||
('type', models.CharField(choices=[('滚筒', '滚筒'), ('打印', '打印')], default='滚筒', max_length=20, verbose_name='设备类型')),
|
||||
('status', models.CharField(choices=[('使用中', '使用中'), ('停用', '停用'), ('维修中', '维修中')], default='使用中', max_length=20, verbose_name='设备状态')),
|
||||
('start_working_at', models.DateField(blank=True, null=True, verbose_name='开始服役日期')),
|
||||
('stop_working_at', models.DateField(blank=True, null=True, verbose_name='停止服役日期')),
|
||||
('is_occupied', models.BooleanField(default=False, verbose_name='是否被占用')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '设备信息',
|
||||
'verbose_name_plural': '设备信息',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -1,49 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 07:26
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0010_deviceinfo'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='VehicleType',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=50, verbose_name='车辆类型名称')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '车辆类型',
|
||||
'verbose_name_plural': '车辆类型',
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='deviceinfo',
|
||||
options={'verbose_name': '设备资料', 'verbose_name_plural': '设备资料'},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='VehicleTransportRecord',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('driver_name', models.CharField(max_length=100, verbose_name='司机姓名')),
|
||||
('contact_number', models.CharField(blank=True, max_length=20, null=True, verbose_name='联系电话')),
|
||||
('license_plate', models.CharField(blank=True, max_length=20, null=True, verbose_name='车牌号码')),
|
||||
('delivery_date', models.DateField(verbose_name='送货日期')),
|
||||
('vehicle_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='vehicles', to='basic_info.vehicletype', verbose_name='车次')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '司机车次',
|
||||
'verbose_name_plural': '司机车次',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 08:58
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0011_vehicletype_alter_deviceinfo_options_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='unit',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='products', to='basic_info.productunit', verbose_name='主单位'),
|
||||
),
|
||||
]
|
||||
@@ -1,36 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 09:10
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0012_alter_product_unit'),
|
||||
('stock', '0018_remove_inventory_unit'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='product',
|
||||
name='unit',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='main_unit',
|
||||
field=models.IntegerField(choices=[(1, '米'), (2, '码'), (3, '公斤')], default=1, verbose_name='主单位'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='sub_unit',
|
||||
field=models.IntegerField(blank=True, choices=[(1, '米'), (2, '码'), (3, '公斤')], null=True, verbose_name='辅单位'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='transform_rate',
|
||||
field=models.DecimalField(blank=True, decimal_places=4, max_digits=10, null=True, verbose_name='转换率(主单位->辅单位)'),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='ProductUnit',
|
||||
),
|
||||
]
|
||||
@@ -1,31 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 09:30
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0013_remove_product_unit_product_main_unit_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='product',
|
||||
name='main_unit',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='product',
|
||||
name='sub_unit',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='single_price',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='单价(米)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='transform_rate',
|
||||
field=models.DecimalField(blank=True, decimal_places=4, max_digits=10, null=True, verbose_name='公斤转换率'),
|
||||
),
|
||||
]
|
||||
@@ -1,27 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 09:47
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0014_remove_product_main_unit_remove_product_sub_unit_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='product',
|
||||
name='single_price',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='single_price_in',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='参考进价'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='single_price_out',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='参考售价'),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-04 02:12
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0015_remove_product_single_price_product_single_price_in_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='unit',
|
||||
field=models.IntegerField(choices=[(1, '米'), (2, '码'), (3, '公斤')], default=1, verbose_name='单位'),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-04 05:07
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0016_product_unit'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='image',
|
||||
field=models.ImageField(blank=True, null=True, upload_to='product_images/', verbose_name='产品图片'),
|
||||
),
|
||||
]
|
||||
@@ -12,11 +12,19 @@ YARD_TO_METER_RATE = 1.09361
|
||||
|
||||
# ==================== 枚举类定义 ====================
|
||||
|
||||
class WareHouseModeEnum(models.IntegerChoices):
|
||||
"""仓库出入库模式枚举"""
|
||||
RESTRICT_IN = 1, '严进宽出'
|
||||
RESTRICT_IN_OUT = 2, '严进严出'
|
||||
UNRESTRICTED = 3, '宽进宽出'
|
||||
|
||||
|
||||
class MerchantTypeEnum(models.IntegerChoices):
|
||||
"""商户类型枚举"""
|
||||
STORE = 1, '布行'
|
||||
FACTORY = 2, '印花厂'
|
||||
|
||||
|
||||
class ProductUnitEnum(models.IntegerChoices):
|
||||
"""产品单位枚举"""
|
||||
METER = 1, '米'
|
||||
@@ -54,6 +62,21 @@ class DeviceTypeEnum(models.TextChoices):
|
||||
# ==================== 模型定义 ====================
|
||||
|
||||
|
||||
class QuickInput(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=100, verbose_name='名')
|
||||
value = models.CharField(max_length=200, verbose_name='值')
|
||||
group = models.CharField(verbose_name='组')
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.group}-{self.name}'
|
||||
|
||||
class Meta:
|
||||
verbose_name = '快捷输入'
|
||||
verbose_name_plural = '快捷输入'
|
||||
unique_together = ('name', 'group')
|
||||
|
||||
|
||||
class Merchant(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=100, verbose_name='商户名称')
|
||||
@@ -62,6 +85,10 @@ class Merchant(ModelBase):
|
||||
email = models.EmailField(blank=True, null=True, verbose_name='电子邮箱')
|
||||
mobile = models.CharField(max_length=20, blank=True, null=True, verbose_name='手机')
|
||||
contact = models.TextField(blank=True, null=True, verbose_name='联系人')
|
||||
auto_complete_stock_change = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name='自动确认库存变动',
|
||||
)
|
||||
description = models.TextField(blank=True, null=True, verbose_name='备注描述')
|
||||
|
||||
def __str__(self):
|
||||
@@ -74,6 +101,7 @@ class Merchant(ModelBase):
|
||||
|
||||
class VehicleType(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='vehicle_types', verbose_name='所属商户')
|
||||
name = models.CharField(max_length=50, verbose_name='车辆类型名称')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='备注描述')
|
||||
|
||||
@@ -87,8 +115,14 @@ class VehicleType(ModelBase):
|
||||
|
||||
class WareHouse(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='warehouses', verbose_name='所属商户')
|
||||
name = models.CharField(max_length=100, verbose_name='仓库名称')
|
||||
location = models.CharField(max_length=200, blank=True, null=True, verbose_name='仓库地址')
|
||||
mode = models.IntegerField(
|
||||
choices=WareHouseModeEnum.choices,
|
||||
default=WareHouseModeEnum.RESTRICT_IN,
|
||||
verbose_name='出入库模式',
|
||||
)
|
||||
contact = models.CharField(max_length=100, blank=True, null=True, verbose_name='联系人')
|
||||
mobile = models.CharField(max_length=20, blank=True, null=True, verbose_name='手机')
|
||||
area = models.CharField(max_length=100, blank=True, null=True, verbose_name='地区')
|
||||
@@ -104,6 +138,7 @@ class WareHouse(ModelBase):
|
||||
|
||||
class Supplier(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='suppliers', verbose_name='所属商户')
|
||||
name = models.CharField(max_length=100, verbose_name='供应商名称')
|
||||
area = models.CharField(max_length=100, blank=True, null=True, verbose_name='地区')
|
||||
email = models.EmailField(blank=True, null=True, verbose_name='电子邮箱')
|
||||
@@ -121,6 +156,7 @@ class Supplier(ModelBase):
|
||||
|
||||
class BankAccount(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='bank_accounts', verbose_name='所属商户')
|
||||
name = models.CharField(max_length=100, verbose_name='名称')
|
||||
auto_number = models.CharField(max_length=50, verbose_name='自动编号')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='备注描述')
|
||||
@@ -136,6 +172,7 @@ class BankAccount(ModelBase):
|
||||
|
||||
class ProductCategory(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='product_categories', verbose_name='所属商户')
|
||||
name = models.CharField(max_length=100, verbose_name='类别名称')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='类别描述')
|
||||
product_prefix = models.CharField(max_length=5, verbose_name='产品编号前缀')
|
||||
@@ -150,6 +187,7 @@ class ProductCategory(ModelBase):
|
||||
|
||||
class Product(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, verbose_name='所属商户')
|
||||
category = models.ForeignKey(
|
||||
ProductCategory,
|
||||
on_delete=models.PROTECT,
|
||||
@@ -231,7 +269,21 @@ class Product(ModelBase):
|
||||
|
||||
class Customer(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='customers', verbose_name='所属商户')
|
||||
name = models.CharField(max_length=100, verbose_name='客户名称')
|
||||
visible_employees = models.ManyToManyField(
|
||||
'Employee',
|
||||
blank=True,
|
||||
related_name='visible_customers',
|
||||
verbose_name='可见该客户的员工',
|
||||
)
|
||||
created_by = models.ForeignKey(
|
||||
'Employee',
|
||||
on_delete=models.PROTECT,
|
||||
related_name='created_customers',
|
||||
null=True,
|
||||
verbose_name='创建者',
|
||||
)
|
||||
mobile = models.CharField(max_length=20, verbose_name='手机')
|
||||
area = models.CharField(max_length=100, blank=True, null=True, verbose_name='地区')
|
||||
email = models.EmailField(blank=True, null=True, verbose_name='电子邮箱')
|
||||
@@ -248,6 +300,7 @@ class Customer(ModelBase):
|
||||
|
||||
class Employee(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='employees', verbose_name='所属商户')
|
||||
sys_user = models.OneToOneField(
|
||||
User,
|
||||
on_delete=models.PROTECT,
|
||||
@@ -283,6 +336,7 @@ class Employee(ModelBase):
|
||||
|
||||
class DeviceInfo(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='devices', verbose_name='所属商户')
|
||||
name = models.CharField(max_length=100, verbose_name='设备名称')
|
||||
type = models.CharField(
|
||||
max_length=20,
|
||||
@@ -311,6 +365,7 @@ class DeviceInfo(ModelBase):
|
||||
|
||||
class VehicleTransportRecord(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
merchant = models.ForeignKey('Merchant', on_delete=models.PROTECT, related_name='vehicle_transport_records', verbose_name='所属商户')
|
||||
vehicle_type = models.ForeignKey(
|
||||
VehicleType,
|
||||
on_delete=models.PROTECT,
|
||||
|
||||
75
basic_info/services.py
Normal file
75
basic_info/services.py
Normal file
@@ -0,0 +1,75 @@
|
||||
from django.db.models import Q
|
||||
from . import models as basic_models
|
||||
|
||||
|
||||
class CustomerVisibilityService:
|
||||
@staticmethod
|
||||
def filter_customers_for_employee(customer_queryset, user):
|
||||
"""
|
||||
过滤客户查询集,使其仅包含对指定员工可见的客户。
|
||||
"""
|
||||
|
||||
if user.is_superuser:
|
||||
return customer_queryset
|
||||
|
||||
emp = getattr(user, 'employee', None)
|
||||
if emp is None:
|
||||
return customer_queryset.none()
|
||||
|
||||
print(f'Filtering customers for employee: {emp.id}')
|
||||
# 员工创建的客户可见 + 员工被设置为可见员工的客户可见
|
||||
visibility_filter = Q(created_by=emp) | Q(visible_employees=emp)
|
||||
return customer_queryset.filter(visibility_filter).distinct()
|
||||
|
||||
@staticmethod
|
||||
def is_customer_visible_to_employee(customer, user):
|
||||
"""
|
||||
检查特定客户是否对指定员工可见。
|
||||
"""
|
||||
|
||||
if user.is_superuser:
|
||||
return True
|
||||
|
||||
emp = getattr(user, 'employee', None)
|
||||
if emp is None:
|
||||
return False
|
||||
|
||||
if customer.created_by == emp:
|
||||
return True
|
||||
|
||||
if emp in customer.visible_employees.all():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class DataVisibilityService:
|
||||
@staticmethod
|
||||
def is_product_visible_to_employee(product_id: int, user):
|
||||
"""
|
||||
检查特定产品是否对指定员工可见。
|
||||
"""
|
||||
|
||||
if user.is_superuser:
|
||||
return True
|
||||
|
||||
emp: basic_models.Employee = getattr(user, 'employee', None)
|
||||
if emp is None:
|
||||
return False
|
||||
|
||||
return basic_models.Product.objects.filter(id=product_id).filter(merchant=emp.merchant).exists()
|
||||
|
||||
@staticmethod
|
||||
def is_warehouse_visible_to_employee(warehouse_id: int, user):
|
||||
"""
|
||||
检查特定仓库是否对指定员工可见。
|
||||
"""
|
||||
|
||||
if user.is_superuser:
|
||||
return True
|
||||
|
||||
emp: basic_models.Employee = getattr(user, 'employee', None)
|
||||
if emp is None:
|
||||
return False
|
||||
|
||||
return basic_models.WareHouse.objects.filter(id=warehouse_id).filter(merchant=emp.merchant).exists()
|
||||
Reference in New Issue
Block a user