1
0

3 کامیت‌ها 0a8cb5927f ... 1affb9d965

نویسنده SHA1 پیام تاریخ
  flower_bs 1affb9d965 批次流水 2 روز پیش
  flower_bs 75e016c32f 料水 2 روز پیش
  flower_bs c2ab10c7b2 日志准备 4 روز پیش
100فایلهای تغییر یافته به همراه587 افزوده شده و 98 حذف شده
  1. 2 2
      bin/views.py
  2. 17 0
      bound/migrations/0025_alter_batchlogmodel_options.py
  3. 68 29
      bound/models.py
  4. 19 1
      container/filter.py
  5. 2 2
      container/migrations/0022_containerdetaillogmodel_and_more.py
  6. 35 0
      container/migrations/0026_batchlogmodel.py
  7. 18 0
      container/migrations/0027_containerdetaillogmodel_tobatchlog.py
  8. 20 0
      container/migrations/0028_batchlogmodel_bound.py
  9. 32 0
      container/migrations/0029_remove_batchlogmodel_new_goods_qty_and_more.py
  10. 22 0
      container/migrations/0030_batchlogmodel_detail_logs_alter_batchlogmodel_table.py
  11. 231 35
      container/models.py
  12. 22 1
      container/serializers.py
  13. 3 0
      container/urls.py
  14. 71 4
      container/views.py
  15. 1 0
      templates/dist/spa/css/10.955fcd1c.css
  16. 0 0
      templates/dist/spa/css/11.eb31c91a.css
  17. 0 0
      templates/dist/spa/css/12.f57b1220.css
  18. 0 0
      templates/dist/spa/css/13.65fea8cc.css
  19. 0 0
      templates/dist/spa/css/14.296f042c.css
  20. 0 0
      templates/dist/spa/css/15.865457f7.css
  21. 0 0
      templates/dist/spa/css/16.a5d7d7ca.css
  22. 0 0
      templates/dist/spa/css/17.bb6b4a4d.css
  23. 0 0
      templates/dist/spa/css/18.601677c3.css
  24. 0 0
      templates/dist/spa/css/19.71123cd8.css
  25. 0 0
      templates/dist/spa/css/20.f721cf95.css
  26. 0 0
      templates/dist/spa/css/21.ed8e81e9.css
  27. 0 0
      templates/dist/spa/css/22.eed22a1c.css
  28. 0 0
      templates/dist/spa/css/23.4b9e275f.css
  29. 0 0
      templates/dist/spa/css/24.20ec1b8f.css
  30. 0 0
      templates/dist/spa/css/25.01a9029f.css
  31. 0 1
      templates/dist/spa/css/25.31ab8f86.css
  32. 1 0
      templates/dist/spa/css/26.9b0c5133.css
  33. 0 0
      templates/dist/spa/css/27.0d4c4716.css
  34. 0 0
      templates/dist/spa/css/28.e2633675.css
  35. 0 0
      templates/dist/spa/css/29.8f3f6188.css
  36. 1 0
      templates/dist/spa/css/3.311220c7.css
  37. 0 1
      templates/dist/spa/css/3.75b6ae63.css
  38. 0 1
      templates/dist/spa/css/30.368d1e05.css
  39. 0 0
      templates/dist/spa/css/30.97f5bf6a.css
  40. 1 0
      templates/dist/spa/css/31.9478c981.css
  41. 0 1
      templates/dist/spa/css/31.e4f041cc.css
  42. 1 0
      templates/dist/spa/css/32.c4652654.css
  43. 0 0
      templates/dist/spa/css/33.7a23b7fb.css
  44. 0 0
      templates/dist/spa/css/34.0faa4aeb.css
  45. 0 1
      templates/dist/spa/css/8.05ad646d.css
  46. 1 0
      templates/dist/spa/css/8.88208c94.css
  47. 0 1
      templates/dist/spa/css/9.12d7043d.css
  48. 1 0
      templates/dist/spa/css/9.4ff827cd.css
  49. 1 0
      templates/dist/spa/css/chunk-common.ae7a4dbb.css
  50. 0 1
      templates/dist/spa/css/chunk-common.f3f8c523.css
  51. 1 1
      templates/dist/spa/index.html
  52. BIN
      templates/dist/spa/js/10.56915cca.js.gz
  53. 1 0
      templates/dist/spa/js/10.ff0b5b2c.js
  54. BIN
      templates/dist/spa/js/10.ff0b5b2c.js.gz
  55. BIN
      templates/dist/spa/js/11.673b98cc.js.gz
  56. 1 1
      templates/dist/spa/js/10.56915cca.js
  57. BIN
      templates/dist/spa/js/11.d2c5553c.js.gz
  58. 1 1
      templates/dist/spa/js/11.673b98cc.js
  59. BIN
      templates/dist/spa/js/12.10622ab0.js.gz
  60. BIN
      templates/dist/spa/js/12.815480bb.js.gz
  61. BIN
      templates/dist/spa/js/13.05bdf440.js.gz
  62. 1 1
      templates/dist/spa/js/12.815480bb.js
  63. BIN
      templates/dist/spa/js/13.2df05f8d.js.gz
  64. BIN
      templates/dist/spa/js/14.249637e6.js.gz
  65. 1 1
      templates/dist/spa/js/13.05bdf440.js
  66. BIN
      templates/dist/spa/js/14.67f088cd.js.gz
  67. BIN
      templates/dist/spa/js/15.694f083b.js.gz
  68. 1 1
      templates/dist/spa/js/14.249637e6.js
  69. BIN
      templates/dist/spa/js/15.a1d31fc2.js.gz
  70. 1 1
      templates/dist/spa/js/15.694f083b.js
  71. BIN
      templates/dist/spa/js/16.0827bf08.js.gz
  72. BIN
      templates/dist/spa/js/16.83f90c5d.js.gz
  73. BIN
      templates/dist/spa/js/17.32db9573.js.gz
  74. 1 1
      templates/dist/spa/js/16.83f90c5d.js
  75. BIN
      templates/dist/spa/js/17.9c73eb9c.js.gz
  76. 1 1
      templates/dist/spa/js/17.32db9573.js
  77. BIN
      templates/dist/spa/js/18.ca785134.js.gz
  78. BIN
      templates/dist/spa/js/18.f3920d7c.js.gz
  79. BIN
      templates/dist/spa/js/19.00705837.js.gz
  80. 1 1
      templates/dist/spa/js/18.f3920d7c.js
  81. BIN
      templates/dist/spa/js/19.139fb325.js.gz
  82. 1 1
      templates/dist/spa/js/19.00705837.js
  83. BIN
      templates/dist/spa/js/20.13c39907.js.gz
  84. BIN
      templates/dist/spa/js/20.29051533.js.gz
  85. 1 1
      templates/dist/spa/js/20.29051533.js
  86. BIN
      templates/dist/spa/js/21.3722ac7c.js.gz
  87. BIN
      templates/dist/spa/js/22.27e97887.js.gz
  88. 1 1
      templates/dist/spa/js/21.6c456dd1.js
  89. BIN
      templates/dist/spa/js/21.6c456dd1.js.gz
  90. 1 1
      templates/dist/spa/js/22.27e97887.js
  91. BIN
      templates/dist/spa/js/23.aa80f2a2.js.gz
  92. BIN
      templates/dist/spa/js/23.b20207c3.js.gz
  93. BIN
      templates/dist/spa/js/24.4cc2dcf2.js.gz
  94. 1 1
      templates/dist/spa/js/23.b20207c3.js
  95. BIN
      templates/dist/spa/js/24.d98a09d7.js.gz
  96. 1 1
      templates/dist/spa/js/24.4cc2dcf2.js
  97. BIN
      templates/dist/spa/js/25.51321a20.js.gz
  98. 0 1
      templates/dist/spa/js/25.bd3d6a93.js
  99. BIN
      templates/dist/spa/js/25.bd3d6a93.js.gz
  100. 0 0
      templates/dist/spa/js/26.336b155c.js

+ 2 - 2
bin/views.py

@@ -160,13 +160,13 @@ class locationViewSet(viewsets.ModelViewSet):
             )
         )
         
-        # 收集所有激活链接的容器ID
+        # 收集所有激活链接的托盘ID
         container_ids = set()
         for loc in locations:
             if loc.active_links:  # 每个库位最多只有一个激活链接
                 container_ids.add(loc.active_links[0].container_id)
         
-        # 批量查询容器详情及其批次状态
+        # 批量查询托盘详情及其批次状态
         container_batch_status = defaultdict(dict)  # 改为字典存储,避免重复记录
         if container_ids:
             container_details = ContainerDetailModel.objects.filter(

+ 17 - 0
bound/migrations/0025_alter_batchlogmodel_options.py

@@ -0,0 +1,17 @@
+# Generated by Django 4.1.2 on 2025-07-23 16:32
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('bound', '0024_alter_batchlogmodel_goods_qty_and_more'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='batchlogmodel',
+            options={'ordering': ['-id'], 'verbose_name': 'Batch Log', 'verbose_name_plural': 'Batch Log'},
+        ),
+    ]

+ 68 - 29
bound/models.py

@@ -1,7 +1,7 @@
 from django.db import models
 from erp.models import InboundBill, MaterialDetail, OutboundBill,OutMaterialDetail
 from django.db.models import Sum
-from django.db.models.signals import post_save, post_delete
+from django.db.models.signals import post_save, post_delete, pre_save
 from django.dispatch import receiver
 from decimal import Decimal
 class BoundListModel(models.Model):
@@ -154,36 +154,74 @@ class MaterialStatistics(models.Model):
         verbose_name_plural = "物料统计"
         ordering = ['goods_code']
 
+
+
+
+@receiver(pre_save, sender=BoundBatchModel)
+def store_original_goods_code(sender, instance, **kwargs):
+    """保存前记录原始物料编码(仅更新时生效)"""
+    if not instance.pk:  # 新建对象无原始值
+        return
+
+    try:
+        original = BoundBatchModel.objects.get(pk=instance.pk)
+        # 将原始值存储在实例属性中供post_save使用
+        instance._original_goods_code = original.goods_code  
+    except BoundBatchModel.DoesNotExist:
+        pass
+
 @receiver([post_save, post_delete], sender=BoundBatchModel)
 def update_material_statistics(sender, instance, **kwargs):
-    goods_code = instance.goods_code
-    stats, created = MaterialStatistics.objects.get_or_create(
-        goods_code=goods_code,
-        defaults={
-            'goods_desc': instance.goods_desc,
-            'goods_std': instance.goods_std or '待填写',
-            'goods_unit': instance.goods_unit or '待填写',
-        }
-    )
-    
-    # 更新物料信息为最新批次的信息(可选)
-    stats.goods_desc = instance.goods_desc
-    if instance.goods_std and instance.goods_std != '待填写':
-        stats.goods_std = instance.goods_std
-    if instance.goods_unit and instance.goods_unit != '待填写':
-        stats.goods_unit = instance.goods_unit
-    stats.save()
-
-    # 计算总数量
-    total = BoundBatchModel.objects.filter(goods_code=goods_code).aggregate(
-        total=Sum('goods_in_location_qty')
-    )['total'] or 0
-    # 更新物料统计的出库数目
-    total_out = BoundBatchModel.objects.filter(goods_code=goods_code).aggregate(
-        total_out=Sum('goods_out_qty')
-    )['total_out'] or 0
-    stats.total_quantity = total
-    stats.save()
+    # 处理删除/创建/更新操作的核心逻辑
+    def refresh_stats(target_goods_code, force_desc=False):
+        """刷新指定物料的统计数据"""
+        stats, created = MaterialStatistics.objects.get_or_create(
+            goods_code=target_goods_code,
+            defaults={
+                'goods_desc': instance.goods_desc,
+                'goods_std': instance.goods_std or '待填写',
+                'goods_unit': instance.goods_unit or '待填写',
+            }
+        )
+        
+        # 仅强制更新描述(用于当前物料)或新建时初始化
+        if force_desc or created:
+            stats.goods_desc = instance.goods_desc
+            if instance.goods_std and instance.goods_std != '待填写':
+                stats.goods_std = instance.goods_std
+            if instance.goods_unit and instance.goods_unit != '待填写':
+                stats.goods_unit = instance.goods_unit
+        
+        # 重新聚合统计数据(始终执行)
+        agg = BoundBatchModel.objects.filter(goods_code=target_goods_code).aggregate(
+            total=Sum('goods_in_location_qty'),
+            total_out=Sum('goods_out_qty')
+        )
+        stats.total_quantity = agg['total'] or 0
+        # 如果有出库统计字段需更新,可在此添加
+        stats.save()
+
+    # 情况1:删除操作直接更新当前物料
+    if kwargs.get('signal') == post_delete:
+        refresh_stats(instance.goods_code)
+        return
+
+    # 情况2:创建操作直接更新新物料
+    if kwargs.get('created'):
+        refresh_stats(instance.goods_code, force_desc=True)
+        return
+
+    # 情况3:更新操作(检测物料编码变更)
+    original_code = getattr(instance, '_original_goods_code', None)
+    current_code = instance.goods_code
+
+    # 物料编码未变化时仅更新当前物料
+    if original_code == current_code:
+        refresh_stats(current_code, force_desc=True)
+    # 物料编码变化时更新新旧两个物料
+    else:
+        refresh_stats(original_code)      # 更新旧物料(仅刷新数量)
+        refresh_stats(current_code, force_desc=True)  # 更新新物料(全量刷新)
 
 
 
@@ -325,6 +363,7 @@ class BatchLogModel(models.Model):
         db_table = 'batchlog'
         verbose_name = 'Batch Log'
         verbose_name_plural = "Batch Log"
+        ordering = ['-id']
 
 # 利用创建好的批次来与申请单相对应       
 class BoundDetailModel(models.Model):

+ 19 - 1
container/filter.py

@@ -1,8 +1,26 @@
 from django_filters import FilterSet, NumberFilter, CharFilter
-from .models import ContainerListModel,ContainerDetailModel,ContainerOperationModel,TaskModel,ContainerWCSModel,ContainerDetailLogModel
+from .models import ContainerListModel,ContainerDetailModel,ContainerOperationModel,TaskModel,ContainerWCSModel,ContainerDetailLogModel,batchLogModel
 
 from django_filters import rest_framework as filters
 
+
+class batchLogFilter(filters.FilterSet):
+    batch_code__icontains = filters.CharFilter(field_name='batch__bound_number', lookup_expr='icontains')
+    bound_code__icontains = filters.CharFilter(field_name='bound__bound_code', lookup_expr='icontains')
+    class Meta:
+        model = batchLogModel
+        fields = {
+            "id": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
+            "bound": ['exact'],
+            "batch": ['exact'],
+            "log_type": ['exact', 'icontains'],
+            "goods_code": ['exact', 'icontains'],
+            "goods_desc": ['exact', 'icontains'],
+            "goods_in_qty": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
+            "goods_out_qty": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
+            "detail_logs": ['exact'],
+            "create_time": ['exact', 'gt', 'gte', 'lt', 'lte', 'range'],
+        }
 class ContainerDetailLogFilter(filters.FilterSet):
     goods_code = filters.CharFilter(field_name='container_detail__goods_code', lookup_expr='exact')
     goods_code__icontains = filters.CharFilter(field_name='container_detail__goods_code', lookup_expr='icontains')

+ 2 - 2
container/migrations/0022_containerdetaillogmodel_and_more.py

@@ -26,8 +26,8 @@ class Migration(migrations.Migration):
                 ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='操作时间')),
             ],
             options={
-                'verbose_name': '容器明细变更日志',
-                'verbose_name_plural': '容器明细变更日志',
+                'verbose_name': '托盘明细变更日志',
+                'verbose_name_plural': '托盘明细变更日志',
                 'db_table': 'container_detail_log',
                 'ordering': ['-create_time'],
             },

+ 35 - 0
container/migrations/0026_batchlogmodel.py

@@ -0,0 +1,35 @@
+# Generated by Django 4.1.2 on 2025-07-22 20:03
+
+from decimal import Decimal
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('bound', '0024_alter_batchlogmodel_goods_qty_and_more'),
+        ('container', '0025_alter_containerdetaillogmodel_log_type'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='batchLogModel',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('log_type', models.CharField(choices=[('create', '创建'), ('update', '更新'), ('delete', '删除'), ('out', '出库'), ('cancel_out', '取消出库'), ('status_change', '状态变更')], max_length=20, verbose_name='日志类型')),
+                ('goods_code', models.CharField(max_length=50, verbose_name='货品编码')),
+                ('goods_desc', models.CharField(max_length=100, verbose_name='货品描述')),
+                ('old_goods_qty', models.DecimalField(blank=True, decimal_places=3, default=Decimal('0'), max_digits=10, null=True, verbose_name='原数量')),
+                ('new_goods_qty', models.DecimalField(blank=True, decimal_places=3, default=Decimal('0'), max_digits=10, null=True, verbose_name='新数量')),
+                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
+                ('batch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='logs', to='bound.boundbatchmodel')),
+            ],
+            options={
+                'verbose_name': '批次日志',
+                'verbose_name_plural': '批次日志',
+                'db_table': 'batch_log',
+                'ordering': ['-create_time'],
+            },
+        ),
+    ]

+ 18 - 0
container/migrations/0027_containerdetaillogmodel_tobatchlog.py

@@ -0,0 +1,18 @@
+# Generated by Django 4.1.2 on 2025-07-22 20:42
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('container', '0026_batchlogmodel'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='containerdetaillogmodel',
+            name='tobatchlog',
+            field=models.BooleanField(default=False, verbose_name='是否转移到批次日志'),
+        ),
+    ]

+ 20 - 0
container/migrations/0028_batchlogmodel_bound.py

@@ -0,0 +1,20 @@
+# Generated by Django 4.1.2 on 2025-07-23 14:29
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('bound', '0024_alter_batchlogmodel_goods_qty_and_more'),
+        ('container', '0027_containerdetaillogmodel_tobatchlog'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='batchlogmodel',
+            name='bound',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='logs', to='bound.boundlistmodel'),
+        ),
+    ]

+ 32 - 0
container/migrations/0029_remove_batchlogmodel_new_goods_qty_and_more.py

@@ -0,0 +1,32 @@
+# Generated by Django 4.1.2 on 2025-07-23 14:53
+
+from decimal import Decimal
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('container', '0028_batchlogmodel_bound'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='batchlogmodel',
+            name='new_goods_qty',
+        ),
+        migrations.RemoveField(
+            model_name='batchlogmodel',
+            name='old_goods_qty',
+        ),
+        migrations.AddField(
+            model_name='batchlogmodel',
+            name='goods_in_qty',
+            field=models.DecimalField(blank=True, decimal_places=3, default=Decimal('0'), max_digits=10, null=True, verbose_name='新入数量'),
+        ),
+        migrations.AddField(
+            model_name='batchlogmodel',
+            name='goods_out_qty',
+            field=models.DecimalField(blank=True, decimal_places=3, default=Decimal('0'), max_digits=10, null=True, verbose_name='新出数量'),
+        ),
+    ]

+ 22 - 0
container/migrations/0030_batchlogmodel_detail_logs_alter_batchlogmodel_table.py

@@ -0,0 +1,22 @@
+# Generated by Django 4.1.2 on 2025-07-23 16:32
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('container', '0029_remove_batchlogmodel_new_goods_qty_and_more'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='batchlogmodel',
+            name='detail_logs',
+            field=models.ManyToManyField(related_name='batch_logs', to='container.containerdetaillogmodel', verbose_name='关联托盘日志'),
+        ),
+        migrations.AlterModelTable(
+            name='batchlogmodel',
+            table='batch_log_from_container_log',
+        ),
+    ]

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 231 - 35
container/models.py


+ 22 - 1
container/serializers.py

@@ -1,10 +1,31 @@
 from rest_framework import serializers
 
-from .models import ContainerListModel,ContainerDetailModel,ContainerOperationModel,TaskModel,ContainerWCSModel,out_batch_detail,ContainerDetailLogModel
+from .models import ContainerListModel,ContainerDetailModel,ContainerOperationModel,TaskModel,ContainerWCSModel,out_batch_detail,ContainerDetailLogModel,batchLogModel
 from bound.models import BoundBatchModel,BoundDetailModel
 
 from utils import datasolve
 from decimal import Decimal
+
+class batchLogModelSerializer(serializers.ModelSerializer):
+
+    # 定义批次日志的序列化器,用于获取操作,字段只读
+    bound_code = serializers.SerializerMethodField()
+    batch_code = serializers.CharField(source='batch.bound_number', read_only=True)
+    goods_unit = serializers.CharField(source='batch.goods_unit', read_only=True)
+    check_status = serializers.IntegerField(source='batch.check_status', read_only=True)
+    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M', required=False)
+    class Meta:
+        # 指定模型和排除字段
+        model = batchLogModel
+        fields= ['id', 'bound_code', 'batch_code', 'log_type', 'goods_code', 'goods_desc', 'goods_in_qty', 'goods_out_qty', 'goods_unit','check_status','create_time']
+        read_only_fields = ['id']
+
+    def get_bound_code(self, obj):
+        """ 动态序列化关联的批次数据 """
+        return obj.bound.bound_code if obj.bound else '无主单,涉及手动操作'
+    
+   
+    
 class WCSTaskGetSerializer(serializers.ModelSerializer):
     class Meta:
         # 指定模型和排除字段

+ 3 - 0
container/urls.py

@@ -60,4 +60,7 @@ re_path(r'^out_detail/(?P<pk>\d+)/$', views.OutDetailViewSet.as_view({
 
 path(r'detaillog/', views.ContainerDetailLogModelViewSet.as_view({"get": "list", "post": "create"}), name="Task"),
 
+path(r'batchdetaillog/', views.batchLogModelViewSet.as_view({"get": "list", "post": "create"}), name="Task"),
+path(r'batchdetaillog/containerlog/', views.batchLogModelViewSet.as_view({ "get": "get_container_operation_log"}), name="Task"),
+
 ]

+ 71 - 4
container/views.py

@@ -14,7 +14,7 @@ import requests
 from django.db import transaction
 import logging
 from rest_framework import status
-from .models import ContainerListModel,ContainerDetailModel,ContainerOperationModel,ContainerWCSModel,TaskModel,out_batch_detail,ContainerDetailLogModel
+from .models import ContainerListModel,ContainerDetailModel,ContainerOperationModel,ContainerWCSModel,TaskModel,out_batch_detail,ContainerDetailLogModel,batchLogModel
 from bound.models import BoundDetailModel,BoundListModel,OutBoundDetailModel
 from bin.views import LocationAllocation,base_location
 from bin.models import LocationModel,LocationContainerLink,LocationGroupModel
@@ -27,7 +27,8 @@ from .serializers import TaskGetSerializer,TaskPostSerializer
 from .serializers import WCSTaskGetSerializer
 from .serializers import OutBoundFullDetailSerializer,OutBoundDetailSerializer
 from .serializers import ContainerDetailLogSerializer
-from .filter import ContainerDetailFilter,ContainerListFilter,ContainerOperationFilter,TaskFilter,WCSTaskFilter,ContainerDetailLogFilter
+from .serializers import batchLogModelSerializer
+from .filter import ContainerDetailFilter,ContainerListFilter,ContainerOperationFilter,TaskFilter,WCSTaskFilter,ContainerDetailLogFilter,batchLogFilter
 
 from rest_framework.permissions import AllowAny
 import threading
@@ -38,6 +39,71 @@ from django.db.models import Sum
 from staff.models import ListModel as StaffListModel
 logger = logging.getLogger(__name__)
 
+# 托盘流水汇总批次流水
+class batchLogModelViewSet(viewsets.ModelViewSet):
+
+    """
+        retrieve:
+            Response a data list(get)
+        list:
+            Response a data list(all)
+        create:
+            Create a data line(post)
+
+        delete:
+            Delete a data line(delete)
+
+
+    """
+    pagination_class = MyPageNumberPagination   
+    filter_backends = [DjangoFilterBackend, OrderingFilter, ]
+    ordering_fields = ['id', "create_time", "update_time", ]
+    filter_class = batchLogFilter
+    
+    def get_project(self):
+        try:
+            id = self.kwargs.get('pk')
+            return id
+        except:
+            return None
+
+    def get_queryset(self):
+        id = self.get_project()
+        if self.request.user:
+            if id is None:
+                return batchLogModel.objects.filter()
+            else:
+                return batchLogModel.objects.filter(id=id)
+        else:
+            return batchLogModel.objects.none()
+        
+    def get_serializer_class(self):
+        if self.action in ['list', 'destroy','retrieve']:
+            return batchLogModelSerializer
+        else:
+            return self.http_method_not_allowed(request=self.request)
+
+    def create(self, request, *args, **kwargs):
+        data = self.request.data
+        return Response(data, status=200, headers=headers)
+    
+    def update(self, request, pk):
+        qs = self.get_object()
+        data = self.request.data
+        serializer = self.get_serializer(qs, data=data)
+        serializer.is_valid(raise_exception=True)
+        serializer.save()
+        headers = self.get_success_headers(serializer.data)  
+        return Response(serializer.data, status=200, headers=headers)
+    
+    def get_container_operation_log(self,request):
+        batchlog_id = self.request.query_params.get('batchlog_id')
+        batch_obj = batchLogModel.objects.get(id=batchlog_id)
+        container_operation_log = batch_obj.detail_logs.all()
+        serializer = ContainerDetailLogSerializer(container_operation_log, many=True)
+        return Response(serializer.data, status=200)
+    
+
 # 进出库log查看
 class ContainerDetailLogModelViewSet(viewsets.ModelViewSet):
     """
@@ -460,7 +526,7 @@ class ContainerWCSViewSet(viewsets.ModelViewSet):
                         self.generate_task_no_batch(container, start_location, allocation_target_location,batch_id,location_min_value.c_number) 
                         self.generate_container_operate_no_batch(container_obj, batch_id, allocation_target_location)
                     elif batch_info['class'] == 3:
-                        self.generate_task_no_batch(container, target_location, allocation_target_location,batch_id,location_min_value.c_number) 
+                        self.generate_task_no_batch(container, start_location, allocation_target_location,batch_id,location_min_value.c_number) 
                         self.generate_move_container_operate(container_obj, allocation_target_location)
                     else:   
                         self.generate_task(container, start_location, allocation_target_location,batch_id,location_min_value.c_number)  # 生成任务
@@ -2402,11 +2468,12 @@ class OutDetailViewSet(viewsets.ModelViewSet):
             container_obj = ContainerListModel.objects.filter(container_code=container_code).first()
             if not container_obj:
                 return Response({"code": "500", "message": f"托盘 {container_code} 不存在"}, status=status.HTTP_200_OK)
-            out_batch_detail_all = out_batch_detail.objects.filter(container=container_obj,working=1,is_delete=False).all()
+            out_batch_detail_all = out_batch_detail.objects.filter(container=container_obj,working=1,is_delete=False).order_by('-id').all()
             if not out_batch_detail_all:
                 return Response({"code": "500", "message": f"托盘 {container_code} 无出库明细"}, status=status.HTTP_200_OK)
             for obj in out_batch_detail_all:
                 obj.container_detail.goods_out_qty = obj.last_out_goods_qty
+                # print(f"取消出库托盘 {container_code} 批次 {obj.container_detail.batch.id},详情 {obj.container_detail.id} 变化前数量 {obj.container_detail.goods_out_qty} 变化后数量 {obj.last_out_goods_qty}")
                 obj.container_detail.save()
                 obj.is_delete = True
                 obj.working = 0

+ 1 - 0
templates/dist/spa/css/10.955fcd1c.css

@@ -0,0 +1 @@
+.q-date__calendar-item--selected[data-v-67d3cd19]{transition:all 0.3s ease;background-color:#1976d2!important}.q-date__range[data-v-67d3cd19]{background-color:rgba(25,118,210,0.1)}.custom-title[data-v-67d3cd19]{font-size:0.9rem;font-weight:500}.custom-timeline[data-v-67d3cd19]{--q-timeline-color:#e0e0e0}.custom-node .q-timeline__dot[data-v-67d3cd19]{background:#485573!important;border:2px solid #5c6b8c!important}.custom-node .q-timeline__content[data-v-67d3cd19]{color:#485573}

templates/dist/spa/css/10.eb31c91a.css → templates/dist/spa/css/11.eb31c91a.css


templates/dist/spa/css/11.f57b1220.css → templates/dist/spa/css/12.f57b1220.css


templates/dist/spa/css/12.65fea8cc.css → templates/dist/spa/css/13.65fea8cc.css


templates/dist/spa/css/13.296f042c.css → templates/dist/spa/css/14.296f042c.css


templates/dist/spa/css/14.865457f7.css → templates/dist/spa/css/15.865457f7.css


templates/dist/spa/css/15.a5d7d7ca.css → templates/dist/spa/css/16.a5d7d7ca.css


templates/dist/spa/css/16.bb6b4a4d.css → templates/dist/spa/css/17.bb6b4a4d.css


templates/dist/spa/css/17.601677c3.css → templates/dist/spa/css/18.601677c3.css


templates/dist/spa/css/18.71123cd8.css → templates/dist/spa/css/19.71123cd8.css


templates/dist/spa/css/19.f721cf95.css → templates/dist/spa/css/20.f721cf95.css


templates/dist/spa/css/20.ed8e81e9.css → templates/dist/spa/css/21.ed8e81e9.css


templates/dist/spa/css/21.eed22a1c.css → templates/dist/spa/css/22.eed22a1c.css


templates/dist/spa/css/22.4b9e275f.css → templates/dist/spa/css/23.4b9e275f.css


templates/dist/spa/css/23.20ec1b8f.css → templates/dist/spa/css/24.20ec1b8f.css


templates/dist/spa/css/24.01a9029f.css → templates/dist/spa/css/25.01a9029f.css


+ 0 - 1
templates/dist/spa/css/25.31ab8f86.css

@@ -1 +0,0 @@
-.q-date__calendar-item--selected[data-v-79f1d61c]{transition:all 0.3s ease;background-color:#1976d2!important}.q-date__range[data-v-79f1d61c]{background-color:rgba(25,118,210,0.1)}[data-v-79f1d61c] .q-field__label{margin-top:8px;align-self:center}[data-v-79f1d61c] .q-field__control-container{padding-left:50px;margin-top:-5px}.handle[data-v-79f1d61c]{cursor:move;padding:8px}

+ 1 - 0
templates/dist/spa/css/26.9b0c5133.css

@@ -0,0 +1 @@
+.q-date__calendar-item--selected[data-v-15f0cb4d]{transition:all 0.3s ease;background-color:#1976d2!important}.q-date__range[data-v-15f0cb4d]{background-color:rgba(25,118,210,0.1)}[data-v-15f0cb4d] .q-field__label{margin-top:8px;align-self:center}[data-v-15f0cb4d] .q-field__control-container{padding-left:50px;margin-top:-5px}.handle[data-v-15f0cb4d]{cursor:move;padding:8px}

templates/dist/spa/css/26.0d4c4716.css → templates/dist/spa/css/27.0d4c4716.css


templates/dist/spa/css/27.e2633675.css → templates/dist/spa/css/28.e2633675.css


templates/dist/spa/css/28.8f3f6188.css → templates/dist/spa/css/29.8f3f6188.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
templates/dist/spa/css/3.311220c7.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 1
templates/dist/spa/css/3.75b6ae63.css


+ 0 - 1
templates/dist/spa/css/30.368d1e05.css

@@ -1 +0,0 @@
-.handle[data-v-248852c7]{cursor:move;padding:8px}

templates/dist/spa/css/29.97f5bf6a.css → templates/dist/spa/css/30.97f5bf6a.css


+ 1 - 0
templates/dist/spa/css/31.9478c981.css

@@ -0,0 +1 @@
+.handle[data-v-5b1a2cf8]{cursor:move;padding:8px}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 1
templates/dist/spa/css/31.e4f041cc.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
templates/dist/spa/css/32.c4652654.css


templates/dist/spa/css/32.7a23b7fb.css → templates/dist/spa/css/33.7a23b7fb.css


templates/dist/spa/css/33.0faa4aeb.css → templates/dist/spa/css/34.0faa4aeb.css


+ 0 - 1
templates/dist/spa/css/8.05ad646d.css

@@ -1 +0,0 @@
-.q-date__calendar-item--selected[data-v-52e2073a]{transition:all 0.3s ease;background-color:#1976d2!important}.q-date__range[data-v-52e2073a]{background-color:rgba(25,118,210,0.1)}.custom-title[data-v-52e2073a]{font-size:0.9rem;font-weight:500}.custom-timeline[data-v-52e2073a]{--q-timeline-color:#e0e0e0}.custom-node .q-timeline__dot[data-v-52e2073a]{background:#485573!important;border:2px solid #5c6b8c!important}.custom-node .q-timeline__content[data-v-52e2073a]{color:#485573}

+ 1 - 0
templates/dist/spa/css/8.88208c94.css

@@ -0,0 +1 @@
+.q-date__calendar-item--selected[data-v-9265d28c]{transition:all 0.3s ease;background-color:#1976d2!important}.q-date__range[data-v-9265d28c]{background-color:rgba(25,118,210,0.1)}.custom-title[data-v-9265d28c]{font-size:0.9rem;font-weight:500}.custom-timeline[data-v-9265d28c]{--q-timeline-color:#e0e0e0}.custom-node .q-timeline__dot[data-v-9265d28c]{background:#485573!important;border:2px solid #5c6b8c!important}.custom-node .q-timeline__content[data-v-9265d28c]{color:#485573}

+ 0 - 1
templates/dist/spa/css/9.12d7043d.css

@@ -1 +0,0 @@
-.q-date__calendar-item--selected[data-v-02fe74f8]{transition:all 0.3s ease;background-color:#1976d2!important}.q-date__range[data-v-02fe74f8]{background-color:rgba(25,118,210,0.1)}.custom-title[data-v-02fe74f8]{font-size:0.9rem;font-weight:500}.custom-timeline[data-v-02fe74f8]{--q-timeline-color:#e0e0e0}.custom-node .q-timeline__dot[data-v-02fe74f8]{background:#485573!important;border:2px solid #5c6b8c!important}.custom-node .q-timeline__content[data-v-02fe74f8]{color:#485573}

+ 1 - 0
templates/dist/spa/css/9.4ff827cd.css

@@ -0,0 +1 @@
+.q-date__calendar-item--selected[data-v-54d23960]{transition:all 0.3s ease;background-color:#1976d2!important}.q-date__range[data-v-54d23960]{background-color:rgba(25,118,210,0.1)}.custom-title[data-v-54d23960]{font-size:0.9rem;font-weight:500}.custom-timeline[data-v-54d23960]{--q-timeline-color:#e0e0e0}.custom-node .q-timeline__dot[data-v-54d23960]{background:#485573!important;border:2px solid #5c6b8c!important}.custom-node .q-timeline__content[data-v-54d23960]{color:#485573}

+ 1 - 0
templates/dist/spa/css/chunk-common.ae7a4dbb.css

@@ -0,0 +1 @@
+[data-v-16e5f0ec] .q-field__label{margin-top:8px;align-self:center}[data-v-16e5f0ec] .q-field__control-container{padding-left:50px;margin-top:-5px}[data-v-16e5f0ec] .q-table .q-editable:hover{background-color:#f0f8ff;cursor:pointer}[data-v-16e5f0ec] .q-field__native{padding:5px 8px}[data-v-16e5f0ec] .q-table tr.editing{background-color:#e8f5e9!important}

+ 0 - 1
templates/dist/spa/css/chunk-common.f3f8c523.css

@@ -1 +0,0 @@
-[data-v-83418d0a] .q-field__label{margin-top:8px;align-self:center}[data-v-83418d0a] .q-field__control-container{padding-left:50px;margin-top:-5px}[data-v-83418d0a] .q-table .q-editable:hover{background-color:#f0f8ff;cursor:pointer}[data-v-83418d0a] .q-field__native{padding:5px 8px}[data-v-83418d0a] .q-table tr.editing{background-color:#e8f5e9!important}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/index.html


BIN
templates/dist/spa/js/10.56915cca.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
templates/dist/spa/js/10.ff0b5b2c.js


BIN
templates/dist/spa/js/10.ff0b5b2c.js.gz


BIN
templates/dist/spa/js/11.673b98cc.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/10.56915cca.js


BIN
templates/dist/spa/js/11.d2c5553c.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/11.673b98cc.js


BIN
templates/dist/spa/js/12.10622ab0.js.gz


BIN
templates/dist/spa/js/12.815480bb.js.gz


BIN
templates/dist/spa/js/13.05bdf440.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/12.815480bb.js


BIN
templates/dist/spa/js/13.2df05f8d.js.gz


BIN
templates/dist/spa/js/14.249637e6.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/13.05bdf440.js


BIN
templates/dist/spa/js/14.67f088cd.js.gz


BIN
templates/dist/spa/js/15.694f083b.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/14.249637e6.js


BIN
templates/dist/spa/js/15.a1d31fc2.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/15.694f083b.js


BIN
templates/dist/spa/js/16.0827bf08.js.gz


BIN
templates/dist/spa/js/16.83f90c5d.js.gz


BIN
templates/dist/spa/js/17.32db9573.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/16.83f90c5d.js


BIN
templates/dist/spa/js/17.9c73eb9c.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/17.32db9573.js


BIN
templates/dist/spa/js/18.ca785134.js.gz


BIN
templates/dist/spa/js/18.f3920d7c.js.gz


BIN
templates/dist/spa/js/19.00705837.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/18.f3920d7c.js


BIN
templates/dist/spa/js/19.139fb325.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/19.00705837.js


BIN
templates/dist/spa/js/20.13c39907.js.gz


BIN
templates/dist/spa/js/20.29051533.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/20.29051533.js


BIN
templates/dist/spa/js/21.3722ac7c.js.gz


BIN
templates/dist/spa/js/22.27e97887.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/21.6c456dd1.js


BIN
templates/dist/spa/js/21.6c456dd1.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/22.27e97887.js


BIN
templates/dist/spa/js/23.aa80f2a2.js.gz


BIN
templates/dist/spa/js/23.b20207c3.js.gz


BIN
templates/dist/spa/js/24.4cc2dcf2.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/23.b20207c3.js


BIN
templates/dist/spa/js/24.d98a09d7.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 1
templates/dist/spa/js/24.4cc2dcf2.js


BIN
templates/dist/spa/js/25.51321a20.js.gz


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 1
templates/dist/spa/js/25.bd3d6a93.js


BIN
templates/dist/spa/js/25.bd3d6a93.js.gz


+ 0 - 0
templates/dist/spa/js/26.336b155c.js


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است