This commit is contained in:
caoqianming 2023-12-16 09:56:48 +08:00
commit e5d2d5ef84
42 changed files with 614 additions and 104 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2023-11-28 07:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('em', '0008_equipment_accuracy_level'),
]
operations = [
migrations.AlterField(
model_name='equipment',
name='description',
field=models.CharField(blank=True, default='', max_length=200, verbose_name='描述'),
),
]

View File

@ -62,7 +62,8 @@ class Equipment(CommonBModel):
count = models.PositiveIntegerField('数量', default=1)
keeper = models.ForeignKey(
User, verbose_name='责任人', on_delete=models.CASCADE, null=True, blank=True)
description = models.CharField('描述', max_length=200, default='', null=True)
description = models.CharField(
'描述', max_length=200, default='', blank=True)
# 以下是计量检测设备单独字段
# mgmtype = models.IntegerField('管理类别', choices=mgmtype_choices, default=1)

View File

@ -9,5 +9,7 @@ class MaterialBatchFilter(filters.FilterSet):
fields = {
"warehouse": ["exact"],
"material": ["exact"],
"material__type": ["exact", "in"],
"material__process": ["exact", "in"],
"count": ["exact", "gte", "lte"]
}

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2023-12-15 11:38
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inm', '0010_auto_20231116_1904'),
]
operations = [
migrations.RenameField(
model_name='mioitem',
old_name='is_bgtest_ok',
new_name='is_testok',
),
]

View File

@ -121,7 +121,7 @@ class MIOItem(BaseModel):
count_n_jsqx = models.PositiveIntegerField('结石气线', default=0)
count_n_qt = models.PositiveIntegerField('其他', default=0)
is_bgtest_ok = models.BooleanField('配套件是否合格', default=True)
is_testok = models.BooleanField('配套件是否合格', default=True)
class MIOItemA(BaseModel):

View File

@ -94,7 +94,7 @@ class MIOItemCreateSerializer(CustomModelSerializer):
class Meta:
model = MIOItem
fields = ['mio', 'warehouse', 'material',
'batch', 'count', 'assemb', 'is_bgtest_ok']
'batch', 'count', 'assemb', 'is_testok']
def create(self, validated_data):
mio = validated_data['mio']

View File

@ -49,7 +49,8 @@ class MaterialBatchViewSet(ListModelMixin, CustomGenericViewSet):
retrieve_serializer_class = MaterialBatchDetailSerializer
select_related_fields = ['warehouse', 'material']
filterset_class = MaterialBatchFilter
search_fields = ['material__name']
search_fields = ['material__name', 'material__number',
'material__model', 'material__specification', 'batch']
class MioDoViewSet(BulkCreateModelMixin, BulkUpdateModelMixin, CustomGenericViewSet):
@ -123,7 +124,12 @@ class MIOViewSet(CustomModelViewSet):
'submit_user', 'supplier', 'order', 'customer', 'pu_order']
serializer_class = MIOListSerializer
retrieve_serializer_class = MIODetailSerializer
filterset_fields = ['state', 'type', 'pu_order', 'order']
filterset_fields = {
'state': ["exact", "in"],
"type": ["exact", "in"],
"pu_order": ["exact"],
"order": ["exact"]
}
search_fields = ['number']
data_filter = True

View File

@ -0,0 +1,31 @@
# Generated by Django 3.2.12 on 2023-12-07 01:35
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('monitor', '0003_alter_drfrequestlog_view_method'),
]
operations = [
migrations.CreateModel(
name='AuditLog',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('action', models.CharField(max_length=20, verbose_name='动作')),
('model_name', models.CharField(max_length=20, verbose_name='模型名')),
('instance_id', models.CharField(editable=False, max_length=20, verbose_name='记录ID')),
('change_reason', models.CharField(default='', max_length=50, verbose_name='变更原因')),
('change_time', models.DateTimeField(verbose_name='变更时间')),
('val_new', models.JSONField(default=dict, verbose_name='变更后完整数据')),
('difference', models.JSONField(default=list, verbose_name='变更情况')),
('change_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='操作人')),
],
),
]

View File

@ -4,6 +4,19 @@ from django.db import models
from apps.utils.models import BaseModel
class AuditLog(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
action = models.CharField('动作', max_length=20)
model_name = models.CharField('模型名', max_length=20)
instance_id = models.CharField('记录ID', max_length=20, editable=False)
change_reason = models.CharField('变更原因', default='', max_length=50)
change_user = models.ForeignKey(
'system.user', on_delete=models.SET_NULL, verbose_name='操作人', null=True, blank=True)
change_time = models.DateTimeField('变更时间')
val_new = models.JSONField('变更后完整数据', default=dict)
difference = models.JSONField('变更情况', default=list)
class DrfRequestLog(BaseModel):
"""Logs Django rest framework API requests"""
@ -42,7 +55,8 @@ class DrfRequestLog(BaseModel):
response = models.TextField(null=True, blank=True)
errors = models.TextField(null=True, blank=True)
agent = models.TextField(null=True, blank=True)
status_code = models.PositiveIntegerField(null=True, blank=True, db_index=True)
status_code = models.PositiveIntegerField(
null=True, blank=True, db_index=True)
class Meta:
verbose_name = "DRF请求日志"

View File

@ -1,4 +1,17 @@
from rest_framework import serializers
from apps.utils.serializers import CustomModelSerializer
from apps.monitor.models import AuditLog
class DbbackupDeleteSerializer(serializers.Serializer):
filepaths = serializers.ListField(child=serializers.CharField(), label="文件地址列表")
filepaths = serializers.ListField(
child=serializers.CharField(), label="文件地址列表")
class AuditLogSerializer(CustomModelSerializer):
change_user_name = serializers.CharField(
source='change_user.name', read_only=True)
class Meta:
model = AuditLog
fields = '__all__'

View File

@ -1,4 +1,63 @@
import psutil
from apps.monitor.models import AuditLog
from apps.system.models import User
from datetime import datetime
from apps.utils.tools import compare_values
from apps.utils.models import get_model_info
def delete_auditlog(model, instance_id):
"""
删除其对应的审计记录
"""
model_name = get_model_info(model)
AuditLog.objects.filter(model_name=model_name,
instance_id=instance_id).delete()
def create_auditlog(action: str, instance, val_new: dict, val_old: dict = None, change_reason: str = '', delete_time: datetime = None, delete_user: User = None):
"""
生成审计日志
action: create/update/delete/其他action
"""
app_label_model_name = get_model_info(instance)
if val_old is None:
val_old = {}
difference = []
has_changed = False
if action == 'create':
has_changed = True
change_user = instance.create_by
change_time = instance.create_time
elif action == 'delete':
has_changed = True
change_user = delete_user if delete_user else instance.update_by
change_time = delete_time if delete_time else instance.update_time
else:
change_user = instance.update_by
change_time = instance.update_time
for k, v in val_new.items():
if k not in ['create_by', 'update_by', 'create_time', 'update_time', 'id']:
if k not in val_old:
difference.append(
{'field': k, 'action': 'create', 'val_old': None, 'val_new': v})
elif not compare_values(val_new.get(k), val_old.get(k), ignore_order=True):
difference.append(
{'field': k, 'action': 'update', 'val_old': val_old[k], 'val_new': v})
if difference:
has_changed = True
if has_changed:
AuditLog.objects.create(
action=action,
model_name=app_label_model_name,
instance_id=instance.id,
val_new=val_new,
difference=difference,
change_reason=change_reason,
change_user=change_user,
change_time=change_time
)
class ServerService:
@classmethod
@ -17,7 +76,7 @@ class ServerService:
ret['count'] = psutil.cpu_count(logical=False)
ret['percent'] = psutil.cpu_percent(interval=1)
return ret
@classmethod
def get_disk_dict(cls):
ret = {}
@ -29,4 +88,4 @@ class ServerService:
@classmethod
def get_full(cls):
return {'cpu': cls.get_cpu_dict(), 'memory': cls.get_memory_dict(), 'disk': cls.get_disk_dict()}
return {'cpu': cls.get_cpu_dict(), 'memory': cls.get_memory_dict(), 'disk': cls.get_disk_dict()}

View File

@ -1,5 +1,5 @@
from django.urls import path
from .views import DrfRequestLogViewSet, ServerInfoView, LogView, LogDetailView, index, room, video, DbBackupView
from .views import DrfRequestLogViewSet, ServerInfoView, LogView, LogDetailView, index, room, video, DbBackupView, AuditlogViewSet
API_BASE_URL = 'api/monitor/'
HTML_BASE_URL = 'monitor/'
@ -13,5 +13,8 @@ urlpatterns = [
path(API_BASE_URL + 'log/<str:name>/', LogDetailView.as_view()),
path(API_BASE_URL + 'dbbackup/', DbBackupView.as_view()),
path(API_BASE_URL + 'server/', ServerInfoView.as_view()),
path(API_BASE_URL + 'request_log/', DrfRequestLogViewSet.as_view({'get': 'list'}), name='requestlog_view')
path(API_BASE_URL + 'request_log/',
DrfRequestLogViewSet.as_view({'get': 'list'}), name='requestlog_view'),
path(API_BASE_URL + 'auditlog/',
AuditlogViewSet.as_view({'get': 'list'}), name='auditlog_view')
]

View File

@ -7,13 +7,13 @@ from rest_framework.permissions import IsAuthenticated
from django.conf import settings
import os
from rest_framework import serializers
from apps.monitor.serializers import DbbackupDeleteSerializer
from apps.monitor.serializers import DbbackupDeleteSerializer, AuditLogSerializer
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework.exceptions import NotFound
from rest_framework.mixins import ListModelMixin
from apps.monitor.filters import DrfLogFilterSet
from apps.monitor.models import DrfRequestLog
from apps.monitor.models import DrfRequestLog, AuditLog
from apps.monitor.errors import LOG_NOT_FONED
from apps.monitor.services import ServerService
@ -188,3 +188,16 @@ class DrfRequestLogViewSet(ListModelMixin, CustomGenericViewSet):
ordering = ['-requested_at']
filterset_class = DrfLogFilterSet
search_fields = ['path', 'view']
class AuditlogViewSet(ListModelMixin, CustomGenericViewSet):
"""审计日志
审计日志
"""
perms_map = {'get': '*'}
queryset = AuditLog.objects.all()
list_serializer_class = AuditLogSerializer
ordering = ['-change_time']
filterset_fields = ['change_user', 'model_name', 'action', 'instance_id']
search_fields = ['model_name', 'action']

View File

@ -15,6 +15,7 @@ class MaterialFilter(filters.FilterSet):
"is_hidden": ["exact"],
"is_assemb": ["exact"],
"need_route": ["exact"],
"process": ["exact", "in", "isnull"],
"orderitem_material__order": ['exact'],
"pu_orderitem_material__pu_order": ["exact"],
"route_material_out__mgroup": ["exact"]
@ -48,4 +49,7 @@ class RouteFilter(filters.FilterSet):
"process": ["exact", "in"],
"is_autotask": ["exact"],
"mgroup": ["exact", "in", "isnull"],
"mgroup__name": ["exact", "contains"],
"mgroup__belong_dept": ["exact"],
"mgroup__belong_dept__name": ["exact", "contains"]
}

View File

@ -15,10 +15,12 @@ class ShiftSerializer(CustomModelSerializer):
class MaterialSimpleSerializer(CustomModelSerializer):
process_name = serializers.CharField(source='process.name', read_only=True)
class Meta:
model = Material
fields = ['id', 'name', 'number', 'model',
'specification', 'type', 'cate', 'brothers']
'specification', 'type', 'cate', 'brothers', 'process_name']
class MaterialSerializer(CustomModelSerializer):
@ -124,15 +126,16 @@ class RouteSerializer(CustomModelSerializer):
fields = '__all__'
read_only_fields = EXCLUDE_FIELDS
# def validate(self, attrs):
# material = attrs['material']
# if material.type != Material.MA_TYPE_GOOD:
# raise ValidationError('请选择最终产品')
# return super().validate(attrs)
def validate(self, attrs):
if 'mgroup' in attrs and attrs['mgroup']:
attrs['process'] = attrs['mgroup'].process
if attrs.get('process', None) is None:
raise ParseError('未提供操作工序')
return super().validate(attrs)
def gen_material_out(self, instance):
"""
废弃不用了
自动形成物料
"""
name = f'{instance.material.name}-中'
instance.material_out, _ = Material.objects.get_or_create(type=Material.MA_TYPE_HALFGOOD, parent=instance.material, process=instance.process,
@ -140,6 +143,7 @@ class RouteSerializer(CustomModelSerializer):
'is_hidden': True, 'name': name,
'number': instance.material.number,
'specification': instance.material.specification,
'model': instance.material.model,
'type': Material.MA_TYPE_HALFGOOD,
'create_by': self.request.user,
'update_by': self.request.user,
@ -147,24 +151,41 @@ class RouteSerializer(CustomModelSerializer):
instance.save()
def create(self, validated_data):
process = validated_data.get('process', None)
if process and Route.objects.filter(material=validated_data['material'], process=process).exists():
process = validated_data['process']
material = validated_data.get('material', None)
if material and process and Route.objects.filter(material=material, process=process).exists():
raise ValidationError('已选择该工序')
with transaction.atomic():
instance = super().create(validated_data)
# if 'material_out' in validated_data and validated_data['material_out'] and instance.material:
# pass
# else:
# self.gen_material_out(instance)
material_out = instance.material_out
if material_out:
if material_out.process is None:
material_out.process = process
if instance.material:
material_out.parent = instance.material
material_out.save()
elif material_out.process != process:
raise ParseError('物料工序错误!请重新选择')
else:
if instance.material:
self.gen_material_out()
return instance
def update(self, instance, validated_data):
validated_data.pop('material', None)
validated_data.pop('process', None)
process = validated_data.pop('process', None)
with transaction.atomic():
instance = super().update(instance, validated_data)
# if 'material_out' in validated_data and validated_data['material_out'] and instance.material:
# pass
# else:
# self.gen_material_out(instance)
material_out = instance.material_out
if material_out:
if material_out.process is None:
material_out.process = process
if instance.material:
material_out.parent = instance.material
material_out.save()
elif material_out.process != process:
raise ParseError('物料工序错误!请重新选择')
else:
if instance.material:
self.gen_material_out()
return instance

View File

@ -51,7 +51,13 @@ class MgroupViewSet(CustomModelViewSet):
queryset = Mgroup.objects.all()
serializer_class = MgroupSerializer
select_related_fields = ['create_by', 'belong_dept', 'process']
filterset_fields = ['belong_dept', 'process', 'cate', 'belong_dept__name']
filterset_fields = {
"belong_dept": ["exact"],
"process": ["exact"],
"cate": ["exact"],
"belong_dept__name": ["exact", "contains"],
"name": ["exact", "contains"]
}
search_fields = ['number']
ordering = ['sort', 'create_time']

View File

@ -38,7 +38,7 @@ class UtaskFilter(filters.FilterSet):
class MtaskFilter(filters.FilterSet):
tag = filters.CharFilter(method='filter_tag')
tag = filters.CharFilter(method='filter_tag', label='done, not_done')
class Meta:
model = Mtask
@ -55,17 +55,22 @@ class MtaskFilter(filters.FilterSet):
"material_out__type": ["exact"],
"material_out__is_hidden": ["exact"],
"mgroup__belong_dept__name": ["exact"],
"mgroup__belong_dept": ["exact"],
"utask": ["exact"]
}
def filter_tag(self, queryset, name, value):
now = timezone.now()
day7_after = now + timedelta(days=7)
if value == 'near_done':
queryset = queryset.filter(count_ok__lt=F('count'),
end_date__lte=day7_after.date(),
end_date__gte=now.date())
elif value == 'out_done':
queryset = queryset.filter(count_ok__lt=F('count'),
end_date__lt=now.date())
# now = timezone.now()
# day7_after = now + timedelta(days=7)
# if value == 'near_done':
# queryset = queryset.filter(count_ok__lt=F('count'),
# end_date__lte=day7_after.date(),
# end_date__gte=now.date())
# elif value == 'out_done':
# queryset = queryset.filter(count_ok__lt=F('count'),
# end_date__lt=now.date())
if value == 'done':
queryset = queryset.filter(count_ok__gte=F('count'))
elif value == 'not_done':
queryset = queryset.filter(count_ok__lt=F('count'))
return queryset

View File

@ -0,0 +1,26 @@
# Generated by Django 3.2.12 on 2023-11-30 08:28
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('pm', '0015_utask_count_day'),
]
operations = [
migrations.AddField(
model_name='mtask',
name='submit_time',
field=models.DateTimeField(blank=True, null=True, verbose_name='提交时间'),
),
migrations.AddField(
model_name='mtask',
name='submit_user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mtask_submit_user', to=settings.AUTH_USER_MODEL, verbose_name='提交人'),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.12 on 2023-12-05 09:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pm', '0016_auto_20231130_1628'),
]
operations = [
migrations.AddField(
model_name='mtask',
name='type',
field=models.CharField(default='mass', help_text="(('mass', '量产'), ('pilot', '中试'))", max_length=10, verbose_name='任务类型'),
),
migrations.AddField(
model_name='utask',
name='type',
field=models.CharField(default='mass', help_text="(('mass', '量产'), ('pilot', '中试'))", max_length=10, verbose_name='任务类型'),
),
]

View File

@ -4,6 +4,11 @@ from apps.mtm.models import Material, Mgroup
# Create your models here.
TASK_TYPE = (
('mass', '量产'),
('pilot', '中试')
)
class Utask(CommonBDModel):
"""
@ -14,15 +19,17 @@ class Utask(CommonBDModel):
UTASK_ASSGINED = 20
UTASK_WORKING = 30
UTASK_STOP = 34
UTASK_DONE = 40
UTASK_SUBMIT = 40
UTASK_STATES = (
(UTASK_CREATED, '创建中'),
(UTASK_DECOMPOSE, '已分解'),
(UTASK_ASSGINED, '已下达'),
(UTASK_WORKING, '生产中'),
(UTASK_STOP, '已停止'),
(UTASK_DONE, '已提交')
(UTASK_SUBMIT, '已提交')
)
type = models.CharField('任务类型', max_length=10,
help_text=str(TASK_TYPE), default='mass')
state = models.PositiveIntegerField(
'状态', choices=UTASK_STATES, default=UTASK_CREATED, help_text=str(UTASK_STATES))
number = models.CharField('编号', max_length=50, unique=True)
@ -48,13 +55,15 @@ class Mtask(CommonADModel):
MTASK_CREATED = 10
MTASK_ASSGINED = 20
MTASK_STOP = 34
MTASK_DONE = 40
MTASK_SUBMIT = 40
MTASK_STATES = (
(MTASK_CREATED, '创建中'),
(MTASK_ASSGINED, '已下达'),
(MTASK_STOP, '已停止'),
(MTASK_DONE, '已提交')
(MTASK_SUBMIT, '已提交')
)
type = models.CharField('任务类型', max_length=10,
help_text=str(TASK_TYPE), default='mass')
state = models.PositiveIntegerField(
'状态', choices=MTASK_STATES, default=MTASK_CREATED, help_text=str(MTASK_STATES))
number = models.CharField('编号', max_length=50, unique=True)
@ -75,6 +84,10 @@ class Mtask(CommonADModel):
Utask, verbose_name='关联大任务', on_delete=models.CASCADE, related_name='mtask_utask', null=True, blank=True)
peifen_kg = models.FloatField('配粉料数', default=0)
submit_time = models.DateTimeField('提交时间', null=True, blank=True)
submit_user = models.ForeignKey(
'system.user', verbose_name='提交人', on_delete=models.CASCADE, null=True, blank=True, related_name='mtask_submit_user')
@property
def related(self):
"""

View File

@ -12,6 +12,7 @@ from apps.wpm.models import Mlog
class UtaskSerializer(CustomModelSerializer):
material_ = MaterialSimpleSerializer(source='material', read_only=True)
mgroup_name = serializers.CharField(source='mgroup.name', read_only=True)
belong_dept = serializers.PrimaryKeyRelatedField(
queryset=Dept.objects.all(), required=False)

View File

@ -71,6 +71,7 @@ class PmService:
for i in range(rela_days):
task_date = start_date + timedelta(days=i)
Mtask.objects.create(**{
'type': utask.type,
'number': f'{number}_{i+1}',
'material_out': utask.material,
'material_in': utask.material_in,
@ -124,6 +125,7 @@ class PmService:
task_date = start_date + timedelta(days=i)
Mtask.objects.create(**{
'number': f'{number}_r{ind+1}_{i+1}',
'type': utask.type,
'material_out': halfgood,
'material_in': material_in,
'mgroup': mgroup,
@ -251,19 +253,23 @@ class PmService:
change_order_state_when_schedue(orderitemIds)
@classmethod
def mtasks_submit(cls, mtasks: QuerySet[Mtask], user: User):
def mtask_submit(cls, mtask: Mtask, user: User):
"""
锁定生产任务
"""
from apps.wpm.models import Mlog
from apps.wpm.services import mlog_submit, update_mtask
now = timezone.now()
for mtask in mtasks:
if mtask.state == Mtask.MTASK_ASSGINED:
mlogs = Mlog.objects.filter(mtask=mtask)
if mlogs.count() == 0:
raise ParseError(f'{mtask.mgroup.name}_未填写日志')
for mlog in mlogs:
mlog_submit(mlog, user, now)
update_mtask(mtask)
mtask.state = Mtask.MTASK_DONE
mtask.state = Mtask.MTASK_SUBMIT
mtask.submit_time = now
mtask.submit_user = user
mtask.save()
else:
raise ParseError('该任务状态不可提交')

View File

@ -158,18 +158,16 @@ class MtaskViewSet(CustomModelViewSet):
raise ParseError('该任务非创建中不可删除')
return super().perform_destroy(instance)
@action(methods=['post'], detail=False, perms_map={'post': 'mtask.submit'}, serializer_class=PkSerializer)
@action(methods=['post'], detail=True, perms_map={'post': 'mtask.submit'}, serializer_class=PkSerializer)
@transaction.atomic
def submit(self, request, *args, **kwargs):
"""提交任务(根据任务ID)
提交任务后不可更新日志
"""
ids = request.data.get('ids', [])
mtask: Mtask = self.get_object()
user = request.user
mtasks = Mtask.objects.filter(
id__in=ids, state=Mtask.MTASK_ASSGINED)
PmService.mtasks_submit(mtasks, user)
PmService.mtask_submit(mtask, user)
return Response()
@action(methods=['post'], detail=True, perms_map={'post': 'mtask.submit'}, serializer_class=Serializer)
@ -181,5 +179,6 @@ class MtaskViewSet(CustomModelViewSet):
"""
mtask = self.get_object()
mtasks = mtask.related
PmService.mtasks_submit(mtasks)
for mtask in mtasks:
PmService.mtask_submit(mtask, self.request.user)
return Response()

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.12 on 2023-12-01 05:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0025_auto_20231120_1139'),
('pum', '0002_alter_puorderitem_material'),
]
operations = [
migrations.AddField(
model_name='puorder',
name='materials',
field=models.ManyToManyField(blank=True, related_name='pu_order_materials', through='pum.PuOrderItem', to='mtm.Material', verbose_name='多个物料'),
),
]

View File

@ -0,0 +1,26 @@
# Generated by Django 3.2.12 on 2023-12-01 05:50
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('pum', '0003_puorder_materials'),
]
operations = [
migrations.AddField(
model_name='puorder',
name='submit_user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='submit_user_puorder', to=settings.AUTH_USER_MODEL, verbose_name='提交人'),
),
migrations.AddField(
model_name='puplan',
name='submit_user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='submit_user_puplan', to=settings.AUTH_USER_MODEL, verbose_name='提交人'),
),
]

View File

@ -35,6 +35,8 @@ class PuPlan(CommonBModel):
number = models.CharField('编号', max_length=20)
name = models.CharField('名称', max_length=50, null=True, blank=True)
submit_time = models.DateTimeField('提交时间', null=True, blank=True)
submit_user = models.ForeignKey(
'system.user', verbose_name='提交人', related_name='submit_user_puplan', on_delete=models.CASCADE, null=True, blank=True)
class PuOrder(CommonBModel):
@ -58,6 +60,10 @@ class PuOrder(CommonBModel):
Supplier, verbose_name='供应商', on_delete=models.CASCADE)
delivery_date = models.DateField('截止到货日期', null=True, blank=True)
submit_time = models.DateTimeField('提交时间', null=True, blank=True)
submit_user = models.ForeignKey(
'system.user', verbose_name='提交人', related_name='submit_user_puorder', on_delete=models.CASCADE, null=True, blank=True)
materials = models.ManyToManyField(
Material, verbose_name='多个物料', blank=True, through='pum.puorderitem', related_name='pu_order_materials')
class PuOrderItem(BaseModel):

View File

@ -4,7 +4,7 @@ from apps.utils.constants import EXCLUDE_FIELDS_DEPT, EXCLUDE_FIELDS_BASE, EXCLU
from rest_framework.exceptions import ValidationError
from apps.pum.models import Supplier, PuPlan, PuPlanItem, PuOrder, PuOrderItem
from apps.mtm.serializers import MaterialSerializer
from apps.mtm.serializers import MaterialSerializer, MaterialSimpleSerializer
class SupplierSerializer(CustomModelSerializer):
@ -83,6 +83,8 @@ class PuOrderSerializer(CustomModelSerializer):
source='create_by.name', read_only=True)
update_by_name = serializers.CharField(
source='update_by.name', read_only=True)
materials_ = MaterialSimpleSerializer(
source='materials', many=True, read_only=True)
class Meta:
model = PuOrder

View File

@ -46,7 +46,7 @@ class PuPlanViewSet(CustomModelViewSet):
raise ParseError('该计划存在明细不可删除')
return super().perform_destroy(instance)
@action(methods=['post'], detail=True, perms_map={'post': 'pu_plan.update'}, serializer_class=serializers.Serializer)
@action(methods=['post'], detail=True, perms_map={'post': 'pu_plan.submit'}, serializer_class=serializers.Serializer)
def submit(self, request, *args, **kwargs):
"""提交采购计划
@ -59,6 +59,7 @@ class PuPlanViewSet(CustomModelViewSet):
if puplan.state != PuPlan.PUPLAN_CREATE:
raise ParseError('采购计划状态异常')
puplan.submit_time = timezone.now()
puplan.submit_user = user
puplan.state = PuPlan.PUPLAN_SUBMITED
puplan.save()
return Response()
@ -106,7 +107,7 @@ class PuOrderViewSet(CustomModelViewSet):
raise ParseError('采购订单非创建中不可删除')
instance.delete(soft=False)
@action(methods=['post'], detail=True, perms_map={'post': 'pu_order.update'}, serializer_class=serializers.Serializer)
@action(methods=['post'], detail=True, perms_map={'post': 'pu_order.submit'}, serializer_class=serializers.Serializer)
@transaction.atomic
def submit(self, request, *args, **kwargs):
"""提交采购订单
@ -122,6 +123,7 @@ class PuOrderViewSet(CustomModelViewSet):
if puorder.state != PuOrder.PUORDER_CREATE:
raise ParseError('采购计划状态异常')
puorder.submit_time = timezone.now()
puorder.submit_user = user
puorder.state = PuOrder.PUORDER_SUBMITED
puorder.save()
PumService.change_puplan_state_when_puorder_sumbit(puorder)

View File

@ -60,6 +60,13 @@ class OrderViewSet(CustomModelViewSet):
search_fields = ['number']
filter_fields = ['contract', 'customer']
@transaction.atomic
def perform_destroy(self, instance):
order = instance.order
if order.state != Order.ORDER_CREATE:
raise ParseError('订单非创建中不可删除')
instance.delete()
@action(methods=['post'], detail=True, perms_map={'post': 'order.update'}, serializer_class=serializers.Serializer)
@transaction.atomic
def submit(self, request, *args, **kwargs):

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.12 on 2023-12-04 00:37
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('system', '0002_myschedule'),
]
operations = [
migrations.AlterField(
model_name='permission',
name='parent',
field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, to='system.permission', verbose_name=''),
),
]

View File

@ -26,10 +26,11 @@ class Permission(BaseModel):
(PERM_TYPE_BUTTON, '按钮')
)
name = models.CharField('名称', max_length=30)
type = models.PositiveSmallIntegerField('类型', choices=menu_type_choices, default=30)
type = models.PositiveSmallIntegerField(
'类型', choices=menu_type_choices, default=30)
sort = models.PositiveSmallIntegerField('排序标记', default=1)
parent = models.ForeignKey('self', null=True, blank=True,
on_delete=models.SET_NULL, verbose_name='')
on_delete=models.SET_NULL, verbose_name='', db_constraint=False)
codes = models.JSONField('权限标识', default=list, null=True, blank=True)
def __str__(self):
@ -67,7 +68,8 @@ class Role(CommonADModel):
"""
name = models.CharField('名称', max_length=32)
code = models.CharField('角色标识', max_length=32, null=True, blank=True)
perms = models.ManyToManyField(Permission, blank=True, verbose_name='功能权限', related_name='role_perms')
perms = models.ManyToManyField(
Permission, blank=True, verbose_name='功能权限', related_name='role_perms')
description = models.CharField('描述', max_length=50, blank=True, null=True)
class Meta:
@ -106,8 +108,10 @@ class PostRole(BaseModel):
"""
data_range = models.PositiveSmallIntegerField('数据权限范围', choices=DataFilter.choices,
default=DataFilter.THISLEVEL_AND_BELOW)
post = models.ForeignKey(Post, verbose_name='关联岗位', on_delete=models.CASCADE)
role = models.ForeignKey(Role, verbose_name='关联角色', on_delete=models.CASCADE)
post = models.ForeignKey(Post, verbose_name='关联岗位',
on_delete=models.CASCADE)
role = models.ForeignKey(Role, verbose_name='关联角色',
on_delete=models.CASCADE)
class SoftDeletableUserManager(SoftDeletableManagerMixin, UserManager):
@ -127,16 +131,21 @@ class User(AbstractUser, CommonBModel):
'self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='上级主管')
post = models.ForeignKey(Post, verbose_name='主要岗位', on_delete=models.SET_NULL,
null=True, blank=True)
posts = models.ManyToManyField(Post, through='system.userpost', related_name='user_posts')
posts = models.ManyToManyField(
Post, through='system.userpost', related_name='user_posts')
depts = models.ManyToManyField(Dept, through='system.userpost')
roles = models.ManyToManyField(Role, verbose_name='关联角色')
# 关联账号
secret = models.CharField('密钥', max_length=100, null=True, blank=True)
wx_openid = models.CharField('微信公众号OpenId', max_length=100, null=True, blank=True)
wx_nickname = models.CharField('微信昵称', max_length=100, null=True, blank=True)
wx_headimg = models.CharField('微信头像', max_length=100, null=True, blank=True)
wxmp_openid = models.CharField('微信小程序OpenId', max_length=100, null=True, blank=True)
wx_openid = models.CharField(
'微信公众号OpenId', max_length=100, null=True, blank=True)
wx_nickname = models.CharField(
'微信昵称', max_length=100, null=True, blank=True)
wx_headimg = models.CharField(
'微信头像', max_length=100, null=True, blank=True)
wxmp_openid = models.CharField(
'微信小程序OpenId', max_length=100, null=True, blank=True)
objects = SoftDeletableUserManager()
@ -154,9 +163,12 @@ class UserPost(BaseModel):
用户岗位关系表
"""
name = models.CharField('名称', max_length=20, null=True, blank=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='up_user')
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='up_post')
dept = models.ForeignKey(Dept, on_delete=models.CASCADE, related_name='up_dept')
user = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='up_user')
post = models.ForeignKey(
Post, on_delete=models.CASCADE, related_name='up_post')
dept = models.ForeignKey(
Dept, on_delete=models.CASCADE, related_name='up_dept')
sort = models.PositiveSmallIntegerField('排序', default=1)
class Meta:
@ -229,7 +241,8 @@ class File(CommonAModel):
(FILE_TYPE_OTHER, '其它')
)
mime = models.CharField('文件格式', max_length=120, null=True, blank=True)
type = models.CharField('文件类型', max_length=50, choices=type_choices, default='文档')
type = models.CharField('文件类型', max_length=50,
choices=type_choices, default='文档')
path = models.CharField('地址', max_length=200, null=True, blank=True)
class Meta:
@ -250,5 +263,7 @@ class MySchedule(CommonAModel):
)
name = models.CharField('名称', max_length=200)
type = models.PositiveSmallIntegerField('周期类型', default=10)
interval = models.ForeignKey(IntervalSchedule, on_delete=models.PROTECT, null=True, blank=True)
crontab = models.ForeignKey(CrontabSchedule, on_delete=models.PROTECT, null=True, blank=True)
interval = models.ForeignKey(
IntervalSchedule, on_delete=models.PROTECT, null=True, blank=True)
crontab = models.ForeignKey(
CrontabSchedule, on_delete=models.PROTECT, null=True, blank=True)

View File

@ -1,6 +1,7 @@
import time
import django.utils.timezone as timezone
from django.db import models
from django.db.models import Model
from django.db.models.query import QuerySet
from apps.utils.snowflake import idWorker
from django.db import IntegrityError
@ -184,8 +185,17 @@ class CommonBDModel(BaseModel):
abstract = True
# class Smslog(BaseModel):
# """
# 短信发送记录表
# """
# phone = models.CharField('号码')
def get_model_info(cls_or_instance):
"""
返回类似 system.dept 的字符
"""
if isinstance(cls_or_instance, Model):
# 是一个模型实例
app_label = cls_or_instance._meta.app_label
model_name = cls_or_instance._meta.model_name
else:
# 假定是一个模型类
app_label = cls_or_instance._meta.app_label
model_name = cls_or_instance._meta.model_name
return f'{app_label}.{model_name}'

View File

@ -9,10 +9,11 @@ import requests
from io import BytesIO
from rest_framework.serializers import ValidationError
def tran64(s):
missing_padding = len(s) % 4
if missing_padding != 0:
s = s+'='* (4 - missing_padding)
s = s+'=' * (4 - missing_padding)
return s
@ -202,4 +203,37 @@ def check_phone_e(phone):
re_phone = r'^1\d{10}$'
if not re.match(re_phone, phone):
raise ValidationError('手机号格式错误')
return phone
return phone
def compare_dicts(dict1, dict2, ignore_order=False):
if ignore_order:
for key in sorted(dict1.keys()):
if key not in dict2 or not compare_values(dict1[key], dict2[key], ignore_order):
return False
return True
else:
return dict1 == dict2
def compare_lists_of_dicts(list1, list2, ignore_order=False):
"""比较两个列表,这里的列表包含字典(对象)"""
if ignore_order:
# 转换列表中的字典为元组列表,然后排序进行比较
sorted_list1 = sorted((tuple(sorted(d.items())) for d in list1))
sorted_list2 = sorted((tuple(sorted(d.items())) for d in list2))
return sorted_list1 == sorted_list2
else:
# 按顺序比较列表中的字典
return all(compare_dicts(obj1, obj2) for obj1, obj2 in zip(list1, list2))
def compare_values(val1, val2, ignore_order=False):
"""通用比较函数,也可以处理字典和列表。"""
if isinstance(val1, list) and isinstance(val2, list):
# 假设这里我们关心列表中对象的顺序
return compare_lists_of_dicts(val1, val2, ignore_order)
elif isinstance(val1, dict) and isinstance(val2, dict):
return compare_dicts(val1, val2, ignore_order)
else:
return val1 == val2

View File

@ -35,6 +35,8 @@ class WMaterialFilter(filters.FilterSet):
model = WMaterial
fields = {
"material": ["exact", "in"],
"material__type": ["exact", "in"],
"material__process": ["exact", "in"],
"belong_dept": ["exact"],
"belong_dept__name": ["exact"],
"batch": ["exact"],
@ -50,9 +52,10 @@ class MlogFilter(filters.FilterSet):
"batch": ["exact"],
"handle_date": ["exact"],
"handle_user": ["exact"],
"mtask__mgroup__belong_dept__name": ["exact"],
"mgroup__belong_dept__name": ["exact", "in"],
"mgroup__name": ["exact", "in"],
"mgroup": ["exact"],
"mtask__mgroup__belong_dept__name": ["exact", "contains", "in"],
"mgroup__belong_dept__name": ["exact", "in", "contains"],
"mgroup__name": ["exact", "in", "contains"],
"submit_time": ["isnull"]
}
@ -69,5 +72,7 @@ class HandoverFilter(filters.FilterSet):
"recive_dept__name": ["exact"],
"send_date": ["exact"],
"material__type": ["exact", "in"],
"submit_time": ["isnull"]
"submit_time": ["isnull"],
"mlog": ["isnull"],
"send_mgroup": ["exact"]
}

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.12 on 2023-11-29 08:51
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0025_auto_20231120_1139'),
('wpm', '0035_otherlog'),
]
operations = [
migrations.AddField(
model_name='handover',
name='send_mgroup',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.mgroup', verbose_name='送料工段'),
),
]

View File

@ -0,0 +1,29 @@
# Generated by Django 3.2.12 on 2023-11-30 02:47
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('mtm', '0025_auto_20231120_1139'),
('wpm', '0036_handover_send_mgroup'),
]
operations = [
migrations.AlterField(
model_name='handover',
name='material',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='物料'),
preserve_default=False,
),
migrations.AlterField(
model_name='handover',
name='send_user',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='handover_send_user', to='system.user', verbose_name='交送人'),
preserve_default=False,
),
]

View File

@ -129,9 +129,9 @@ class Mlog(CommonADModel):
handle_date = models.DateField('操作日期')
handle_user = models.ForeignKey(
User, verbose_name='操作人', on_delete=models.CASCADE, related_name='mlog_handle_user', null=True, blank=True)
User, verbose_name='操作人', on_delete=models.CASCADE, related_name='mlog_handle_user', null=True, blank=True) # 成型人
handle_user_2 = models.ForeignKey(
User, verbose_name='操作人2', on_delete=models.CASCADE, related_name='mlog_handle_user_2', null=True, blank=True)
User, verbose_name='操作人2', on_delete=models.CASCADE, related_name='mlog_handle_user_2', null=True, blank=True) # 切料人
handle_users = models.ManyToManyField(
User, verbose_name='操作人(多选)', blank=True)
handle_leader = models.ForeignKey(
@ -163,12 +163,15 @@ class Handover(CommonADModel):
"""
send_date = models.DateField('送料日期')
send_user = models.ForeignKey(
User, verbose_name='交送人', on_delete=models.CASCADE, related_name='handover_send_user', null=True, blank=True)
User, verbose_name='交送人', on_delete=models.CASCADE, related_name='handover_send_user')
send_mgroup = models.ForeignKey(
Mgroup, verbose_name='送料工段', on_delete=models.CASCADE, null=True, blank=True
)
send_dept = models.ForeignKey(
Dept, verbose_name='送料部门', on_delete=models.CASCADE, related_name='handover_send_dept')
batch = models.CharField('批次号', max_length=50)
material = models.ForeignKey(
Material, verbose_name='物料', on_delete=models.CASCADE, null=True, blank=True)
Material, verbose_name='物料', on_delete=models.CASCADE)
count = models.PositiveIntegerField('送料数', default=0)
count_eweight = models.FloatField('单数重量', default=0)
recive_dept = models.ForeignKey(

View File

@ -223,6 +223,7 @@ class MlogSerializer(CustomModelSerializer):
validated_data['material_in'] = mtask.material_in
material_out = mtask.material_out
validated_data['material_out'] = material_out
validated_data['handle_date'] = mtask.start_date
# if not WMaterial.objects.filter(batch=batch).exists():
# raise ValidationError('批次号不存在')
else:
@ -298,13 +299,19 @@ class DeptBatchSerializer(serializers.Serializer):
class HandoverSerializer(CustomModelSerializer):
material = serializers.PrimaryKeyRelatedField(required=True, label='物料ID', queryset=Material.objects.all())
material = serializers.PrimaryKeyRelatedField(
required=True, label='物料ID', queryset=Material.objects.all())
send_user_name = serializers.CharField(
source='send_user.name', read_only=True)
recive_user_name = serializers.CharField(
source='recive_user.name', read_only=True)
material_ = MaterialSimpleSerializer(source='material', read_only=True)
def validate(self, attrs):
if attrs.get('mlog', None):
attrs['send_mgroup'] = attrs['mlog'].mgroup
return super().validate(attrs)
class Meta:
model = Handover
fields = '__all__'

View File

@ -144,10 +144,12 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
return
if now is None:
now = timezone.now()
if now.date() < mlog.handle_date:
raise ParseError('不可提交未来的日志')
belong_dept = mlog.mgroup.belong_dept
material_out = mlog.material_out
material_in = mlog.material_in
if material_in and material_in.is_hidden is False: # 需要进行车间库存管理
if material_in: # 需要进行车间库存管理
# 需要判断领用数是否合理
material_has_qs = WMaterial.objects.filter(
batch=mlog.batch, material=material_in, belong_dept=belong_dept)
@ -163,7 +165,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
else:
material_has.count = material_has.count - mlog.count_use
material_has.save()
if material_out and material_out.is_hidden is False: # 需要入车间库存
if material_out: # 需要入车间库存
# 有多个产物的情况
if material_out.brothers and Mlogb.objects.filter(mlog=mlog).exists():
for item in Mlogb.objects.filter(mlog=mlog):
@ -185,7 +187,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
def update_mtask(mtask: Mtask):
from apps.pm.models import Utask
res = Mlog.objects.filter(mtask=mtask).aggregate(sum_count_real=Sum(
res = Mlog.objects.filter(mtask=mtask).exclude(submit_time=None).aggregate(sum_count_real=Sum(
'count_real'), sum_count_ok=Sum('count_ok'), sum_count_notok=Sum('count_notok'))
mtask.count_real = res['sum_count_real'] if res['sum_count_real'] else 0
mtask.count_ok = res['sum_count_ok'] if res['sum_count_ok'] else 0
@ -200,8 +202,8 @@ def update_mtask(mtask: Mtask):
utask.count_notok = res2['sum_count_notok'] if res2['sum_count_notok'] else 0
if utask.count_ok > 0 and utask.state == Utask.UTASK_ASSGINED:
utask.state = Utask.UTASK_WORKING
if Mtask.objects.filter(utask=utask).exclude(state=Mtask.MTASK_DONE).count() == 0:
utask.state = Mtask.MTASK_DONE
if Mtask.objects.filter(utask=utask).exclude(state=Mtask.MTASK_SUBMIT).count() == 0:
utask.state = Utask.UTASK_SUBMIT
utask.save()

View File

@ -19,6 +19,7 @@ from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer,
MlogSerializer, MlogRelatedSerializer, DeptBatchSerializer, HandoverSerializer,
GenHandoverSerializer, GenHandoverWmSerializer, MlogAnaSerializer, AttLogSerializer, OtherLogSerializer)
from .services import mlog_submit, update_mtask, handover_submit
from apps.monitor.services import create_auditlog, delete_auditlog
# Create your views here.
@ -102,7 +103,7 @@ class WMaterialViewSet(ListModelMixin, CustomGenericViewSet):
perms_map = {'get': '*'}
queryset = WMaterial.objects.all()
serializer_class = WMaterialSerializer
select_related_fields = ['material', 'belong_dept']
select_related_fields = ['material', 'belong_dept', 'material__process']
search_fields = ['material__name',
'material__number', 'material__specification']
filterset_class = WMaterialFilter
@ -135,10 +136,26 @@ class MlogViewSet(CustomModelViewSet):
prefetch_related_fields = ['handle_users', 'material_outs', 'b_mlog']
filterset_class = MlogFilter
@transaction.atomic
def perform_create(self, serializer):
ins = serializer.save()
data = MlogSerializer(ins).data
create_auditlog('create', ins, data)
@transaction.atomic
def perform_destroy(self, instance):
if instance.submit_time is not None:
raise ParseError('日志已提交不可变动')
return super().perform_destroy(instance)
delete_auditlog(instance, instance.id)
instance.delete()
@transaction.atomic
def perform_update(self, serializer):
ins = serializer.instance
val_old = MlogSerializer(instance=ins).data
serializer.save()
val_new = MlogSerializer(instance=ins).data
create_auditlog('update', ins, val_new, val_old)
@action(methods=['post'], detail=True, perms_map={'post': 'mlog.submit'}, serializer_class=Serializer)
@transaction.atomic
@ -148,10 +165,13 @@ class MlogViewSet(CustomModelViewSet):
日志提交
"""
ins: Mlog = self.get_object()
vdata_old = MlogSerializer(ins).data
if ins.submit_time is None:
mlog_submit(ins, self.request.user, None)
if ins.mtask:
update_mtask(ins.mtask)
vdata_new = MlogSerializer(ins).data
create_auditlog('submit', ins, vdata_new, vdata_old)
return Response()
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=MlogRelatedSerializer)
@ -241,7 +261,7 @@ class HandoverViewSet(CustomModelViewSet):
@action(methods=['post'], detail=True, perms_map={'post': 'handover.submit'}, serializer_class=Serializer)
@transaction.atomic
def submit(self, request):
def submit(self, request, *args, **kwargs):
"""交接记录提交(变动车间库存)
交接记录提交
@ -283,7 +303,7 @@ class HandoverViewSet(CustomModelViewSet):
@action(methods=['post'], detail=False, perms_map={'post': 'handover.create'}, serializer_class=GenHandoverSerializer)
@transaction.atomic
def gen_by_mlogs(self, request):
def gen_by_mlog(self, request):
"""从生产日志生成交接记录
从生产日志生成交接记录
@ -306,6 +326,7 @@ class HandoverViewSet(CustomModelViewSet):
count=mlog.count_real,
count_eweight=mlog.count_real_eweight,
mlog=mlog,
send_mgroup=mlog.mgroup,
create_by=user
)
return Response()

View File

@ -1,11 +1,11 @@
import os
from . import conf
from celery import Celery
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'server.settings')
app = Celery('ehs')
app = Celery(conf.BASE_PROJECT_CODE)
# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.

View File

@ -70,7 +70,7 @@ DEBUG = conf.DEBUG
ALLOWED_HOSTS = ['*']
SYS_NAME = 'XT_EHS'
SYS_VERSION = '2.2.2'
SYS_VERSION = '2.3.0'
# Application definition
@ -282,7 +282,7 @@ AUTHENTICATION_BACKENDS = (
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/2",
"LOCATION": conf.CACHE_LOCATION,
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
@ -290,7 +290,8 @@ CACHES = {
}
# celery配置,celery正常运行必须安装redis
CELERY_BROKER_URL = "redis://127.0.0.1:6379/3" # 任务存储
CELERY_BROKER_URL = conf.CELERY_BROKER_URL # 任务存储
CELERY_TASK_DEFAULT_QUEUE = conf.CELERY_TASK_DEFAULT_QUEUE # 任务队列
CELERYD_MAX_TASKS_PER_CHILD = 100 # 每个worker最多执行100个任务就会被销毁可防止内存泄露
CELERY_TIMEZONE = 'Asia/Shanghai' # 设置时区
CELERY_ENABLE_UTC = True # 启动时区设置