Merge branch 'master' of http://gitea.xxhhcty.xyz:8080/zcdsj/factory
This commit is contained in:
commit
d21c1dc55d
|
@ -0,0 +1,35 @@
|
|||
# Generated by Django 3.2.12 on 2025-09-29 07:51
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('system', '0006_auto_20241213_1249'),
|
||||
('ofm', '0015_alter_vehicle_end_km'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='mroombooking',
|
||||
name='belong_dept',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mroombooking_belong_dept', to='system.dept', verbose_name='所属部门'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mroombooking',
|
||||
name='key_participants',
|
||||
field=models.TextField(blank=True, null=True, verbose_name='主要参会领导'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mroombooking',
|
||||
name='note',
|
||||
field=models.TextField(blank=True, null=True, verbose_name='备注'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mroombooking',
|
||||
name='participant_count',
|
||||
field=models.PositiveIntegerField(default=0, verbose_name='参会人数'),
|
||||
),
|
||||
]
|
|
@ -26,11 +26,15 @@ class Mroom(CommonADModel):
|
|||
location = models.CharField('位置', max_length=100)
|
||||
capacity = models.PositiveIntegerField('容纳人数')
|
||||
|
||||
class MroomBooking(CommonADModel):
|
||||
class MroomBooking(CommonBDModel):
|
||||
"""TN: 会议室预定信息"""
|
||||
# belong_dept 是预定部门
|
||||
title = models.CharField('会议主题', max_length=100)
|
||||
ticket = models.ForeignKey('wf.ticket', verbose_name='关联会议室',
|
||||
on_delete=models.SET_NULL, related_name='mrooms_ticket', null=True, blank=True, db_constraint=False)
|
||||
note = models.TextField('备注', null=True, blank=True)
|
||||
participant_count = models.PositiveIntegerField('参会人数', default=0)
|
||||
key_participants = models.TextField("主要参会领导", null=True, blank=True)
|
||||
|
||||
|
||||
class MroomSlot(BaseModel):
|
||||
|
|
|
@ -19,11 +19,14 @@ class MroomBookingSerializer(CustomModelSerializer):
|
|||
mdate = serializers.DateField(write_only=True, label="预订日期")
|
||||
slots = serializers.ListField(child=serializers.IntegerField(), write_only=True, label="时段索引")
|
||||
create_by_name = serializers.CharField(source='create_by.username', read_only=True)
|
||||
create_by_phone = serializers.CharField(source='create_by.phone', read_only=True)
|
||||
belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True)
|
||||
ticket_ = TicketSimpleSerializer(source='ticket', read_only=True)
|
||||
class Meta:
|
||||
model = MroomBooking
|
||||
fields = '__all__'
|
||||
read_only_fields = EXCLUDE_FIELDS
|
||||
extra_kwargs = {'belong_dept': {'required': True}}
|
||||
|
||||
def create(self, validated_data):
|
||||
mroom = validated_data.pop('mroom')
|
||||
|
|
|
@ -28,7 +28,7 @@ class MroomBookingViewSet(CustomModelViewSet):
|
|||
"""
|
||||
queryset = MroomBooking.objects.all()
|
||||
serializer_class = MroomBookingSerializer
|
||||
select_related_fields = ["create_by", "ticket"]
|
||||
select_related_fields = ["create_by", "ticket", "belong_dept"]
|
||||
filterset_class = MroomBookingFilterset
|
||||
|
||||
def add_info_for_list(self, data):
|
||||
|
@ -66,7 +66,7 @@ class MroomBookingViewSet(CustomModelViewSet):
|
|||
start_time = self._slot_to_time(info["current_slots"][0])
|
||||
end_time = self._slot_to_time(info["current_slots"][-1] + 1)
|
||||
info["time_ranges"].append(f"{start_time}-{end_time}")
|
||||
info.pop("current_slots") # 清理临时数据
|
||||
info["slots"] = info.pop("current_slots") # 清理临时数据
|
||||
|
||||
for item in data:
|
||||
item.update(booking_info.get(item["id"], {}))
|
||||
|
|
|
@ -195,6 +195,8 @@ class CustomRetrieveModelMixin(RetrieveModelMixin):
|
|||
|
||||
给dict返回数据添加额外信息
|
||||
"""
|
||||
if hasattr(self, 'add_info_for_list'):
|
||||
return self.add_info_for_list([data])[0]
|
||||
return data
|
||||
|
||||
class CustomListModelMixin(ListModelMixin):
|
||||
|
@ -243,6 +245,8 @@ class ComplexQueryMixin:
|
|||
vdata = sr.validated_data
|
||||
queryset = self.get_queryset()
|
||||
querys = vdata.get('querys', [])
|
||||
annotate_field_list = vdata.get('annotate_field_list', [])
|
||||
|
||||
if not querys:
|
||||
new_qs = queryset
|
||||
else:
|
||||
|
@ -264,17 +268,29 @@ class ComplexQueryMixin:
|
|||
new_qs = new_qs | one_qs
|
||||
except Exception as e:
|
||||
raise ParseError(str(e))
|
||||
|
||||
if annotate_field_list:
|
||||
annotate_dict = getattr(self, "annotate_dict", {})
|
||||
if annotate_dict:
|
||||
filtered_annotate_dict = { key: annotate_dict[key] for key in annotate_field_list if key in annotate_dict}
|
||||
new_qs = new_qs.annotate(**filtered_annotate_dict)
|
||||
|
||||
ordering = vdata.get('ordering', None)
|
||||
if not ordering:
|
||||
ordering = getattr(self, 'ordering', None)
|
||||
if isinstance(ordering, str):
|
||||
ordering = ordering.replace('\n', '').replace(' ', '')
|
||||
ordering = ordering.split(',')
|
||||
order_fields = []
|
||||
if ordering:
|
||||
for item in ordering:
|
||||
if item.startswith('-'):
|
||||
new_qs = new_qs.order_by(F(item[1:]).desc(nulls_last=True))
|
||||
# JSONField 排序只能用字符串,不要 F
|
||||
order_fields.append(F(item[1:]).desc(nulls_last=True) if '__' not in item else item)
|
||||
else:
|
||||
new_qs = new_qs.order_by(item)
|
||||
order_fields.append(F(item).asc(nulls_last=True) if '__' not in item else item)
|
||||
new_qs = new_qs.order_by(*order_fields)
|
||||
|
||||
page = self.paginate_queryset(new_qs)
|
||||
if page is not None:
|
||||
serializer = self.get_serializer(page, many=True)
|
||||
|
|
|
@ -85,3 +85,4 @@ class ComplexSerializer(serializers.Serializer):
|
|||
ordering = serializers.CharField(required=False)
|
||||
querys = serializers.ListField(child=QuerySerializer(
|
||||
many=True), label="查询列表", required=False)
|
||||
annotate_field_list = serializers.ListField(child=serializers.CharField(), label="RawSQL字段列表", required=False)
|
||||
|
|
|
@ -505,7 +505,7 @@ class HandoverViewSet(CustomModelViewSet):
|
|||
Prefetch('b_handover', queryset=Handoverb.objects.select_related('wm__defect'))
|
||||
]
|
||||
|
||||
def perform_destroy(self, instance):
|
||||
def perform_destroy(self, instance:Handover):
|
||||
user = self.request.user
|
||||
if instance.submit_time is not None:
|
||||
raise ParseError('该交接记录已提交不可删除')
|
||||
|
@ -570,6 +570,9 @@ class HandoverViewSet(CustomModelViewSet):
|
|||
交接记录撤回
|
||||
"""
|
||||
ins: Handover = self.get_object()
|
||||
if ins.new_batch: # 如果是合批
|
||||
if Handoverb.objects.filter(batch=ins.new_batch, handover__submit_time__isnull=True).exists():
|
||||
raise ParseError("该合批存在未提交的交接记录,不可撤回")
|
||||
if ins.submit_time:
|
||||
handover_revert(ins, handler=request.user)
|
||||
return Response()
|
||||
|
|
|
@ -10,6 +10,7 @@ from rest_framework.exceptions import ParseError
|
|||
from django.db import transaction
|
||||
from apps.wpmw.filters import WprFilter
|
||||
from apps.utils.sql import query_one_dict
|
||||
from django.db.models.expressions import RawSQL
|
||||
|
||||
|
||||
class WprViewSet(CustomListModelMixin, RetrieveModelMixin, ComplexQueryMixin, CustomGenericViewSet):
|
||||
|
@ -17,6 +18,7 @@ class WprViewSet(CustomListModelMixin, RetrieveModelMixin, ComplexQueryMixin, Cu
|
|||
|
||||
动态产品
|
||||
"""
|
||||
|
||||
perms_map = {"get": "*"}
|
||||
select_related_fields = ["wm", "mb", "material", "wm__material_ofrom"]
|
||||
prefetch_related_fields = ["defects"]
|
||||
|
@ -27,6 +29,10 @@ class WprViewSet(CustomListModelMixin, RetrieveModelMixin, ComplexQueryMixin, Cu
|
|||
ordering = ["number", "create_time"]
|
||||
ordering_fields = ["number", "create_time", "update_time"]
|
||||
search_fields = ["number", "material__name", "material__model", "material__specification", "number_out"]
|
||||
annotate_dict = {
|
||||
"number_prefix": RawSQL("regexp_replace(number, '(\\d+)$', '')", []),
|
||||
"number_suffix": RawSQL("COALESCE(NULLIF(regexp_replace(number, '.*?(\\d+)$', '\\1'), ''), '0')::bigint", []),
|
||||
}
|
||||
|
||||
def filter_queryset(self, queryset):
|
||||
qs = super().filter_queryset(queryset)
|
||||
|
@ -36,7 +42,7 @@ class WprViewSet(CustomListModelMixin, RetrieveModelMixin, ComplexQueryMixin, Cu
|
|||
qs.exclude(mb=None, wm=None)
|
||||
return qs
|
||||
|
||||
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=WprNewSerializer)
|
||||
@action(methods=["post"], detail=False, perms_map={"post": "*"}, serializer_class=WprNewSerializer)
|
||||
def new_number(self, request, *args, **kwargs):
|
||||
"""获取新的编号"""
|
||||
data = request.data
|
||||
|
@ -47,16 +53,17 @@ class WprViewSet(CustomListModelMixin, RetrieveModelMixin, ComplexQueryMixin, Cu
|
|||
wpr_last = wps_qs.order_by("number").last()
|
||||
count = wps_qs.count()
|
||||
last_number = wpr_last.number if count > 0 else None
|
||||
last_number_count = int(last_number.split("-")[-1].lstrip('0'))
|
||||
last_number_count = int(last_number.split("-")[-1].lstrip("0"))
|
||||
mat = Material.objects.get(id=material_start)
|
||||
return Response({"count": count, "last_number": last_number, "material_model": mat.model, "last_number_count": last_number_count})
|
||||
|
||||
@action(methods=['get'], detail=False, perms_map={'get': '*'})
|
||||
@action(methods=["get"], detail=False, perms_map={"get": "*"})
|
||||
def number_out_last(self, request, *args, **kwargs):
|
||||
"""获取最新的出库对外编号
|
||||
|
||||
获取最新的出库对外编号(get请求传入prefix参数和with_unsubmit参数,with_unsubmit默认为yes,表示是否包含未出库的记录,prefix为前缀,如'WPR-2023-0)"""
|
||||
from apps.inm.models import MIOItemw
|
||||
|
||||
prefix = request.query_params.get("prefix", None)
|
||||
if not prefix:
|
||||
raise ParseError("请传入前缀参数")
|
||||
|
@ -67,7 +74,7 @@ class WprViewSet(CustomListModelMixin, RetrieveModelMixin, ComplexQueryMixin, Cu
|
|||
SELECT id, number_out FROM wpmw_wpr
|
||||
WHERE number_out ~ %s order by number_out desc limit 1
|
||||
"""
|
||||
pattern = f'^{prefix}[0-9]+$'
|
||||
pattern = f"^{prefix}[0-9]+$"
|
||||
number_outs = []
|
||||
wpr_qs_last = query_one_dict(query, [pattern])
|
||||
if wpr_qs_last:
|
||||
|
@ -87,7 +94,7 @@ class WprViewSet(CustomListModelMixin, RetrieveModelMixin, ComplexQueryMixin, Cu
|
|||
if number_outs:
|
||||
number_outs.sort()
|
||||
number_out_last = number_outs[-1]
|
||||
number_int_last = number_out_last.lstrip(prefix).lstrip('0')
|
||||
number_int_last = number_out_last.lstrip(prefix).lstrip("0")
|
||||
try:
|
||||
number_int_last = int(number_int_last)
|
||||
except ValueError:
|
||||
|
@ -96,8 +103,7 @@ class WprViewSet(CustomListModelMixin, RetrieveModelMixin, ComplexQueryMixin, Cu
|
|||
else:
|
||||
return Response({"number_out_last": None})
|
||||
|
||||
|
||||
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=WproutListSerializer)
|
||||
@action(methods=["post"], detail=False, perms_map={"post": "*"}, serializer_class=WproutListSerializer)
|
||||
@transaction.atomic
|
||||
def assgin_number_out(self, request, *args, **kwargs):
|
||||
"""分配出库对外编号
|
||||
|
@ -108,7 +114,7 @@ class WprViewSet(CustomListModelMixin, RetrieveModelMixin, ComplexQueryMixin, Cu
|
|||
vdata = sr.validated_data
|
||||
items = vdata["items"]
|
||||
number_outs = [i["number_out"] for i in items]
|
||||
existing_numbers = Wpr.objects.filter(number_out__in=number_outs, number_out__isnull=False).values_list('number_out', flat=True)
|
||||
existing_numbers = Wpr.objects.filter(number_out__in=number_outs, number_out__isnull=False).values_list("number_out", flat=True)
|
||||
if existing_numbers.exists():
|
||||
used_numbers = list(existing_numbers)
|
||||
raise ParseError(f"以下对外编号已被使用: {used_numbers[0]} 共{len(used_numbers)}个")
|
||||
|
|
29
changelog.md
29
changelog.md
|
@ -1,3 +1,32 @@
|
|||
## 2.8.2025092816
|
||||
- feat: 新增功能
|
||||
- handover revert撤回时做校验 [caoqianming]
|
||||
- ofm-models 修改车辆表的字段信息 [zty]
|
||||
- iofm-serializer 增加ticket_ [zty]
|
||||
- 会议室预定修改 [caoqianming]
|
||||
- p_create_after 优化 [caoqianming]
|
||||
- mlog quick增加wprs_in传参 [caoqianming]
|
||||
- 车间领料时完善提示添加物料名 [caoqianming]
|
||||
- ofm-修改会议室信息 [zty]
|
||||
- 改版需提供新批次号 [caoqianming]
|
||||
- ofm 修改publicity 的model [zty]
|
||||
- 修改ofm-services.py [zty]
|
||||
- base send_sms auto_log send_mail使用False [caoqianming]
|
||||
- 优化bind_routepack [caoqianming]
|
||||
- base 优化wf通知发送 [caoqianming]
|
||||
- routepack_ticket_change 变为创建中状态 [caoqianming]
|
||||
- route增加查询条件以支持获取后续工段的信息 [caoqianming]
|
||||
- 导入物料优化一下 [caoqianming]
|
||||
- 优化的mplogxview [caoqianming]
|
||||
- base sql querydict可传入是否格式化时间参数 [caoqianming]
|
||||
- base workflow list 添加并返回view_path [caoqianming]
|
||||
- 优化handover list接口 [caoqianming]
|
||||
- 玻纤拉丝采集问题 [caoqianming]
|
||||
- base system和wf优化事务处理 [caoqianming]
|
||||
- 优化cd.py [caoqianming]
|
||||
- wpr list 返回process_name [caoqianming]
|
||||
- fix: 问题修复
|
||||
- mroombooking 创建时未create_by [caoqianming]
|
||||
## 2.8.2025091616
|
||||
- feat: 新增功能
|
||||
- mioitem处理事务处理 [caoqianming]
|
||||
|
|
|
@ -35,7 +35,7 @@ sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
|
|||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
SYS_NAME = '星途工厂综合管理系统'
|
||||
SYS_VERSION = '2.8.2025091616'
|
||||
SYS_VERSION = '2.8.2025092816'
|
||||
X_FRAME_OPTIONS = 'SAMEORIGIN'
|
||||
|
||||
# Application definition
|
||||
|
|
|
@ -21,10 +21,11 @@ from drf_yasg import openapi
|
|||
from drf_yasg.views import get_schema_view
|
||||
from rest_framework.documentation import include_docs_urls
|
||||
from django.views.generic import TemplateView
|
||||
from server.settings import get_sysconfig
|
||||
|
||||
schema_view = get_schema_view(
|
||||
openapi.Info(
|
||||
title=settings.SYS_NAME,
|
||||
title=f'{settings.SYS_NAME}--{get_sysconfig("base.base_name", "demo")}',
|
||||
default_version=settings.SYS_VERSION,
|
||||
contact=openapi.Contact(email="caoqianming@foxmail.com"),
|
||||
license=openapi.License(name="MIT License"),
|
||||
|
|
Loading…
Reference in New Issue