Bläddra i källkod

增加出库申请

flower_mr 1 månad sedan
förälder
incheckning
e133c68ebb
54 ändrade filer med 3814 tillägg och 808 borttagningar
  1. 132 41
      bin/migrations/0001_initial.py
  2. 0 93
      bin/migrations/0002_initial.py
  3. 0 33
      bin/migrations/0003_locationgroupmodel_access_priority_and_more.py
  4. 0 19
      bin/migrations/0004_locationgroupmodel_layer.py
  5. 0 18
      bin/migrations/0005_alter_locationgroupmodel_status.py
  6. 0 29
      bin/migrations/0006_alter_locationcontainerlink_unique_together_and_more.py
  7. 0 29
      bin/migrations/0007_alter_locationcontainerlink_container_and_more.py
  8. 0 18
      bin/migrations/0008_alter_locationmodel_current_quantity.py
  9. 0 60
      bin/migrations/0009_alloction_pre_allocation_history.py
  10. 0 54
      bin/migrations/0010_remove_alloction_pre_layer1_pre_and_more.py
  11. 0 55
      bin/migrations/0011_base_location_remove_alloction_pre_layer1_pressure_and_more.py
  12. 0 18
      bin/migrations/0012_alloction_pre_layer_solution_type.py
  13. BIN
      bin/migrations/__pycache__/0001_initial.cpython-38.pyc
  14. BIN
      bound/__pycache__/filter.cpython-38.pyc
  15. BIN
      bound/__pycache__/models.cpython-38.pyc
  16. BIN
      bound/__pycache__/serializers.cpython-38.pyc
  17. BIN
      bound/__pycache__/urls.cpython-38.pyc
  18. BIN
      bound/__pycache__/views.cpython-38.pyc
  19. 124 2
      bound/filter.py
  20. 88 3
      bound/migrations/0001_initial.py
  21. 0 18
      bound/migrations/0002_alter_boundbatchmodel_status.py
  22. 0 18
      bound/migrations/0003_boundbatchmodel_container_number.py
  23. 0 18
      bound/migrations/0004_boundbatchmodel_goods_unit.py
  24. 0 44
      bound/migrations/0005_outboundmodel_boundbatchmodel_note.py
  25. 0 27
      bound/migrations/0006_remove_boundbatchmodel_note_boundlistmodel_note_and_more.py
  26. 0 41
      bound/migrations/0007_batchlogmodel_delete_outboundmodel_and_more.py
  27. 0 36
      bound/migrations/0008_batchlogmodel_goods_code_batchlogmodel_goods_qty_and_more.py
  28. 0 18
      bound/migrations/0009_alter_boundbatchmodel_bound_number.py
  29. 0 18
      bound/migrations/0010_alter_boundbatchmodel_bound_number.py
  30. BIN
      bound/migrations/__pycache__/0001_initial.cpython-38.pyc
  31. BIN
      bound/migrations/__pycache__/0002_alter_boundbatchmodel_status.cpython-38.pyc
  32. BIN
      bound/migrations/__pycache__/0002_bounddetailmodel_status.cpython-38.pyc
  33. BIN
      bound/migrations/__pycache__/0002_boundlistmodel_bound_desc.cpython-38.pyc
  34. BIN
      bound/migrations/__pycache__/0003_boundbatchmodel_container_number.cpython-38.pyc
  35. BIN
      bound/migrations/__pycache__/0003_boundbatchmodel_goods_std.cpython-38.pyc
  36. BIN
      bound/migrations/__pycache__/0004_boundbatchmodel_goods_unit.cpython-38.pyc
  37. BIN
      bound/migrations/__pycache__/0005_outboundmodel_boundbatchmodel_note.cpython-38.pyc
  38. BIN
      bound/migrations/__pycache__/0006_remove_boundbatchmodel_note_boundlistmodel_note_and_more.cpython-38.pyc
  39. BIN
      bound/migrations/__pycache__/0007_batchlogmodel_delete_outboundmodel_and_more.cpython-38.pyc
  40. BIN
      bound/migrations/__pycache__/0008_batchlogmodel_goods_code_batchlogmodel_goods_qty_and_more.cpython-38.pyc
  41. BIN
      bound/migrations/__pycache__/0009_alter_boundbatchmodel_bound_number.cpython-38.pyc
  42. BIN
      bound/migrations/__pycache__/0010_alter_boundbatchmodel_bound_number.cpython-38.pyc
  43. 80 5
      bound/models.py
  44. 137 3
      bound/serializers.py
  45. 21 1
      bound/urls.py
  46. 305 28
      bound/views.py
  47. 1 1
      container/migrations/0001_initial.py
  48. BIN
      container/migrations/__pycache__/0001_initial.cpython-38.pyc
  49. 3 3
      data_base/init.ps1
  50. BIN
      db.sqlite3
  51. 1348 0
      logs/error.log
  52. 1351 0
      logs/server.log
  53. 44 16
      templates/src/pages/inbound/asn.vue
  54. 180 41
      templates/src/pages/outbound/dn.vue

+ 132 - 41
bin/migrations/0001_initial.py

@@ -1,6 +1,7 @@
-# Generated by Django 4.1.2 on 2025-04-16 22:09
+# Generated by Django 4.1.2 on 2025-04-24 23:03
 
 from django.db import migrations, models
+import django.db.models.deletion
 
 
 class Migration(migrations.Migration):
@@ -8,40 +9,41 @@ class Migration(migrations.Migration):
     initial = True
 
     dependencies = [
+        ('container', '0001_initial'),
     ]
 
     operations = [
         migrations.CreateModel(
-            name='DeviceModel',
+            name='alloction_pre',
             fields=[
                 ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('device_id', models.CharField(max_length=255, verbose_name='Device ID')),
-                ('device_name', models.CharField(max_length=255, verbose_name='Device Name')),
-                ('device_type', models.CharField(max_length=255, verbose_name='Device Type')),
-                ('ip_address', models.CharField(max_length=255, verbose_name='IP Address')),
-                ('port', models.IntegerField(verbose_name='Port')),
-                ('status', models.CharField(max_length=255, verbose_name='Status')),
-                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
-                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
+                ('batch_number', models.CharField(max_length=255, verbose_name='批次号')),
+                ('layer_pre_type', models.JSONField(default=list, verbose_name='预留方案')),
+                ('layer_solution_type', models.JSONField(default=list, verbose_name='规划方案')),
+                ('layer1_task_finish_number', models.IntegerField(default=0, verbose_name='第一层任务完成数')),
+                ('layer2_task_finish_number', models.IntegerField(default=0, verbose_name='第二层任务完成数')),
+                ('layer3_task_finish_number', models.IntegerField(default=0, verbose_name='第三层任务完成数')),
+                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
             ],
             options={
-                'verbose_name': 'Device',
-                'verbose_name_plural': 'Device',
-                'db_table': 'device',
+                'verbose_name': 'Allocation_pre',
+                'verbose_name_plural': 'Allocation_pre',
+                'db_table': 'allocation_pre',
                 'ordering': ['-id'],
             },
         ),
         migrations.CreateModel(
-            name='LocationChangeLog',
+            name='base_location',
             fields=[
                 ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('operation_type', models.CharField(choices=[('put', '上架'), ('pick', '下架'), ('move_in', '移入'), ('move_out', '移出')], max_length=10, verbose_name='操作类型')),
-                ('timestamp', models.DateTimeField(auto_now_add=True, verbose_name='操作时间')),
+                ('layer1_pressure', models.IntegerField(default=0, verbose_name='第一层工作压力')),
+                ('layer2_pressure', models.IntegerField(default=0, verbose_name='第二层工作压力')),
+                ('layer3_pressure', models.IntegerField(default=0, verbose_name='第三层工作压力')),
             ],
             options={
-                'verbose_name': 'Location Change Log',
-                'verbose_name_plural': 'Location Change Log',
-                'db_table': 'location_change_log',
+                'verbose_name': 'Base_location',
+                'verbose_name_plural': 'Base_location',
+                'db_table': 'base_location',
                 'ordering': ['-id'],
             },
         ),
@@ -52,6 +54,7 @@ class Migration(migrations.Migration):
                 ('put_time', models.DateTimeField(auto_now_add=True, verbose_name='上架时间')),
                 ('operator', models.CharField(max_length=50, verbose_name='操作人')),
                 ('is_active', models.BooleanField(default=True, verbose_name='是否有效')),
+                ('container', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='container.containerlistmodel')),
             ],
             options={
                 'verbose_name': 'Location-Container Link',
@@ -60,6 +63,91 @@ class Migration(migrations.Migration):
                 'ordering': ['-id'],
             },
         ),
+        migrations.CreateModel(
+            name='LocationModel',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('warehouse_code', models.CharField(max_length=255, verbose_name='Warehouse code')),
+                ('warehouse_name', models.CharField(max_length=255, verbose_name='Warehouse Name')),
+                ('shelf_type', models.CharField(default='storage', max_length=255, verbose_name='Shelf Type')),
+                ('row', models.IntegerField(verbose_name='Row')),
+                ('col', models.IntegerField(verbose_name='Column')),
+                ('layer', models.IntegerField(verbose_name='Layer')),
+                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
+                ('empty_label', models.BooleanField(default=True, verbose_name='Empty Flag')),
+                ('location_code', models.CharField(max_length=20, unique=True, verbose_name='库位编码')),
+                ('location_group', models.CharField(max_length=20, verbose_name='库位组')),
+                ('location_type', models.CharField(choices=[('T5', '5货位'), ('T4', '4货位'), ('S4', '4单货位'), ('T2', '2货位'), ('T1', '散货位'), ('M1', '通道区'), ('E1', '提升机'), ('C1', '输送机'), ('B1', '充电桩')], max_length=3, verbose_name='货位类型')),
+                ('status', models.CharField(choices=[('available', '可用'), ('occupied', '占用'), ('disabled', '禁用'), ('reserved', '预留'), ('maintenance', '维护中')], default='available', max_length=20, verbose_name='库位状态')),
+                ('max_capacity', models.PositiveIntegerField(verbose_name='最大容量')),
+                ('current_quantity', models.PositiveIntegerField(default=0, verbose_name='当前数')),
+                ('c_number', models.IntegerField(default=1, verbose_name='库位远近排序')),
+                ('coordinate', models.CharField(max_length=50, verbose_name='三维坐标')),
+                ('access_priority', models.IntegerField(default=0, help_text='值越大表示越远离主通道,应优先使用', verbose_name='访问优先级')),
+                ('is_active', models.BooleanField(default=True, verbose_name='是否有效')),
+                ('current_containers', models.ManyToManyField(through='bin.LocationContainerLink', to='container.containerlistmodel', verbose_name='当前存放托盘')),
+            ],
+            options={
+                'verbose_name': 'Location',
+                'verbose_name_plural': 'Location',
+                'db_table': 'location',
+                'ordering': ['-id'],
+                'unique_together': {('warehouse_code', 'row', 'col', 'layer')},
+            },
+        ),
+        migrations.AddField(
+            model_name='locationcontainerlink',
+            name='location',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bin.locationmodel', verbose_name='库位'),
+        ),
+        migrations.AddField(
+            model_name='locationcontainerlink',
+            name='task_detail',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='container.taskmodel'),
+        ),
+        migrations.AddField(
+            model_name='locationcontainerlink',
+            name='task_wcs',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='container.containerwcsmodel'),
+        ),
+        migrations.CreateModel(
+            name='LocationChangeLog',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('operation_type', models.CharField(choices=[('put', '上架'), ('pick', '下架'), ('move_in', '移入'), ('move_out', '移出')], max_length=10, verbose_name='操作类型')),
+                ('timestamp', models.DateTimeField(auto_now_add=True, verbose_name='操作时间')),
+                ('container', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='container.containerlistmodel', verbose_name='托盘')),
+                ('location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bin.locationmodel', verbose_name='库位')),
+                ('related_location', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='related_logs', to='bin.locationmodel', verbose_name='关联库位')),
+                ('task_detail', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='container.taskmodel', verbose_name='批次详情')),
+                ('task_wcs', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='container.containerwcsmodel', verbose_name='WCS任务')),
+            ],
+            options={
+                'verbose_name': 'Location Change Log',
+                'verbose_name_plural': 'Location Change Log',
+                'db_table': 'location_change_log',
+                'ordering': ['-id'],
+            },
+        ),
+        migrations.CreateModel(
+            name='allocation_history',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('operation_type', models.CharField(max_length=10, verbose_name='操作类型')),
+                ('timestamp', models.DateTimeField(auto_now_add=True, verbose_name='操作时间')),
+                ('container', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='container.containerlistmodel', verbose_name='托盘')),
+                ('location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bin.locationmodel', verbose_name='库位')),
+                ('related_location', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='related_logs_history', to='bin.locationmodel', verbose_name='关联库位')),
+                ('task_detail', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='container.taskmodel', verbose_name='批次详情')),
+                ('task_wcs', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='container.containerwcsmodel', verbose_name='WCS任务')),
+            ],
+            options={
+                'verbose_name': 'Allocation_history',
+                'verbose_name_plural': 'Allocation_history',
+                'db_table': 'allocation_history',
+                'ordering': ['-id'],
+            },
+        ),
         migrations.CreateModel(
             name='LocationGroupModel',
             fields=[
@@ -68,48 +156,51 @@ class Migration(migrations.Migration):
                 ('group_name', models.CharField(max_length=50, verbose_name='库位组名称')),
                 ('group_type', models.CharField(choices=[('T5', '5货位'), ('T4', '4货位'), ('S4', '4单货位'), ('T2', '2货位'), ('T1', '散货位')], max_length=50, verbose_name='库位组类型')),
                 ('group_code', models.CharField(max_length=50, verbose_name='库位组编码')),
-                ('status', models.CharField(choices=[('available', '可用'), ('occupied', '占用'), ('disabled', '禁用'), ('reserved', '预留'), ('maintenance', '维护中')], default='available', max_length=20, verbose_name='库位状态')),
+                ('layer', models.PositiveIntegerField(verbose_name='层数')),
+                ('status', models.CharField(choices=[('available', '可用'), ('occupied', '占用'), ('full', '满'), ('disabled', '禁用'), ('reserved', '预留'), ('maintenance', '维护中')], default='available', max_length=20, verbose_name='库位状态')),
                 ('max_capacity', models.PositiveIntegerField(verbose_name='最大容量')),
                 ('current_quantity', models.PositiveIntegerField(default=0, verbose_name='当前托盘数')),
                 ('current_goods_quantity', models.PositiveIntegerField(default=0, verbose_name='当前货物数')),
                 ('current_batch', models.CharField(default='', max_length=50, verbose_name='当前批次')),
                 ('current_goods_code', models.CharField(default='', max_length=50, verbose_name='当前货物编码')),
+                ('access_priority', models.IntegerField(default=0, help_text='值越大表示越远离主通道,应优先使用', verbose_name='访问优先级')),
+                ('left_priority', models.IntegerField(default=0, help_text='值越大表示越靠左,应优先使用', verbose_name='左侧优先级')),
+                ('right_priority', models.IntegerField(default=0, help_text='值越大表示越靠右,应优先使用', verbose_name='右侧优先级')),
+                ('is_active', models.BooleanField(default=True, verbose_name='是否有效')),
+                ('location_items', models.ManyToManyField(to='bin.locationmodel', verbose_name='库位')),
             ],
             options={
                 'verbose_name': 'Location Group',
                 'verbose_name_plural': 'Location Group',
                 'db_table': 'location_group',
                 'ordering': ['-id'],
+                'unique_together': {('warehouse_code', 'group_code')},
             },
         ),
+        migrations.AlterUniqueTogether(
+            name='locationcontainerlink',
+            unique_together={('location', 'container')},
+        ),
         migrations.CreateModel(
-            name='LocationModel',
+            name='DeviceModel',
             fields=[
                 ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('warehouse_code', models.CharField(max_length=255, verbose_name='Warehouse code')),
-                ('warehouse_name', models.CharField(max_length=255, verbose_name='Warehouse Name')),
-                ('shelf_type', models.CharField(default='storage', max_length=255, verbose_name='Shelf Type')),
-                ('row', models.IntegerField(verbose_name='Row')),
-                ('col', models.IntegerField(verbose_name='Column')),
-                ('layer', models.IntegerField(verbose_name='Layer')),
+                ('device_id', models.CharField(max_length=255, verbose_name='Device ID')),
+                ('device_name', models.CharField(max_length=255, verbose_name='Device Name')),
+                ('device_type', models.CharField(max_length=255, verbose_name='Device Type')),
+                ('ip_address', models.CharField(max_length=255, verbose_name='IP Address')),
+                ('port', models.IntegerField(verbose_name='Port')),
+                ('status', models.CharField(max_length=255, verbose_name='Status')),
+                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
                 ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
-                ('empty_label', models.BooleanField(default=True, verbose_name='Empty Flag')),
-                ('location_code', models.CharField(max_length=20, unique=True, verbose_name='库位编码')),
-                ('location_group', models.CharField(max_length=20, verbose_name='库位组')),
-                ('location_type', models.CharField(choices=[('T5', '5货位'), ('T4', '4货位'), ('S4', '4单货位'), ('T2', '2货位'), ('T1', '散货位'), ('M1', '通道区'), ('E1', '提升机'), ('C1', '输送机'), ('B1', '充电桩')], max_length=3, verbose_name='货位类型')),
-                ('status', models.CharField(choices=[('available', '可用'), ('occupied', '占用'), ('disabled', '禁用'), ('reserved', '预留'), ('maintenance', '维护中')], default='available', max_length=20, verbose_name='库位状态')),
-                ('max_capacity', models.PositiveIntegerField(verbose_name='最大容量')),
-                ('current_quantity', models.PositiveIntegerField(default=0, verbose_name='当前托盘数')),
-                ('c_number', models.IntegerField(default=1, verbose_name='库位远近排序')),
-                ('coordinate', models.CharField(max_length=50, verbose_name='三维坐标')),
-                ('access_priority', models.IntegerField(default=0, help_text='值越大表示越远离主通道,应优先使用', verbose_name='访问优先级')),
-                ('is_active', models.BooleanField(default=True, verbose_name='是否有效')),
+                ('location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bin.locationmodel')),
             ],
             options={
-                'verbose_name': 'Location',
-                'verbose_name_plural': 'Location',
-                'db_table': 'location',
+                'verbose_name': 'Device',
+                'verbose_name_plural': 'Device',
+                'db_table': 'device',
                 'ordering': ['-id'],
+                'unique_together': {('location', 'device_id')},
             },
         ),
     ]

+ 0 - 93
bin/migrations/0002_initial.py

@@ -1,93 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-16 22:09
-
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
-    initial = True
-
-    dependencies = [
-        ('container', '0001_initial'),
-        ('bin', '0001_initial'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='locationmodel',
-            name='current_containers',
-            field=models.ManyToManyField(through='bin.LocationContainerLink', to='container.containerlistmodel', verbose_name='当前存放托盘'),
-        ),
-        migrations.AddField(
-            model_name='locationgroupmodel',
-            name='location_items',
-            field=models.ManyToManyField(to='bin.locationmodel', verbose_name='库位'),
-        ),
-        migrations.AddField(
-            model_name='locationcontainerlink',
-            name='container',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='container.containerlistmodel'),
-        ),
-        migrations.AddField(
-            model_name='locationcontainerlink',
-            name='location',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bin.locationmodel'),
-        ),
-        migrations.AddField(
-            model_name='locationcontainerlink',
-            name='task_detail',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='container.taskmodel'),
-        ),
-        migrations.AddField(
-            model_name='locationcontainerlink',
-            name='task_wcs',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='container.containerwcsmodel'),
-        ),
-        migrations.AddField(
-            model_name='locationchangelog',
-            name='container',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='container.containerlistmodel', verbose_name='托盘'),
-        ),
-        migrations.AddField(
-            model_name='locationchangelog',
-            name='location',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bin.locationmodel', verbose_name='库位'),
-        ),
-        migrations.AddField(
-            model_name='locationchangelog',
-            name='related_location',
-            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='related_logs', to='bin.locationmodel', verbose_name='关联库位'),
-        ),
-        migrations.AddField(
-            model_name='locationchangelog',
-            name='task_detail',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='container.taskmodel', verbose_name='批次详情'),
-        ),
-        migrations.AddField(
-            model_name='locationchangelog',
-            name='task_wcs',
-            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='container.containerwcsmodel', verbose_name='WCS任务'),
-        ),
-        migrations.AddField(
-            model_name='devicemodel',
-            name='location',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bin.locationmodel'),
-        ),
-        migrations.AlterUniqueTogether(
-            name='locationmodel',
-            unique_together={('warehouse_code', 'row', 'col', 'layer')},
-        ),
-        migrations.AlterUniqueTogether(
-            name='locationgroupmodel',
-            unique_together={('warehouse_code', 'group_code')},
-        ),
-        migrations.AlterUniqueTogether(
-            name='locationcontainerlink',
-            unique_together={('location', 'container')},
-        ),
-        migrations.AlterUniqueTogether(
-            name='devicemodel',
-            unique_together={('location', 'device_id')},
-        ),
-    ]

+ 0 - 33
bin/migrations/0003_locationgroupmodel_access_priority_and_more.py

@@ -1,33 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-16 23:05
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bin', '0002_initial'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='locationgroupmodel',
-            name='access_priority',
-            field=models.IntegerField(default=0, help_text='值越大表示越远离主通道,应优先使用', verbose_name='访问优先级'),
-        ),
-        migrations.AddField(
-            model_name='locationgroupmodel',
-            name='is_active',
-            field=models.BooleanField(default=True, verbose_name='是否有效'),
-        ),
-        migrations.AddField(
-            model_name='locationgroupmodel',
-            name='left_priority',
-            field=models.IntegerField(default=0, help_text='值越大表示越靠左,应优先使用', verbose_name='左侧优先级'),
-        ),
-        migrations.AddField(
-            model_name='locationgroupmodel',
-            name='right_priority',
-            field=models.IntegerField(default=0, help_text='值越大表示越靠右,应优先使用', verbose_name='右侧优先级'),
-        ),
-    ]

+ 0 - 19
bin/migrations/0004_locationgroupmodel_layer.py

@@ -1,19 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-16 23:15
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bin', '0003_locationgroupmodel_access_priority_and_more'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='locationgroupmodel',
-            name='layer',
-            field=models.PositiveIntegerField(default=1, verbose_name='层数'),
-            preserve_default=False,
-        ),
-    ]

+ 0 - 18
bin/migrations/0005_alter_locationgroupmodel_status.py

@@ -1,18 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-17 10:15
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bin', '0004_locationgroupmodel_layer'),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name='locationgroupmodel',
-            name='status',
-            field=models.CharField(choices=[('available', '可用'), ('occupied', '占用'), ('full', '满'), ('disabled', '禁用'), ('reserved', '预留'), ('maintenance', '维护中')], default='available', max_length=20, verbose_name='库位状态'),
-        ),
-    ]

+ 0 - 29
bin/migrations/0006_alter_locationcontainerlink_unique_together_and_more.py

@@ -1,29 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-17 14:09
-
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('container', '0001_initial'),
-        ('bin', '0005_alter_locationgroupmodel_status'),
-    ]
-
-    operations = [
-        migrations.AlterUniqueTogether(
-            name='locationcontainerlink',
-            unique_together=set(),
-        ),
-        migrations.AlterField(
-            model_name='locationcontainerlink',
-            name='container',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='container.containerlistmodel', unique=True),
-        ),
-        migrations.AlterField(
-            model_name='locationcontainerlink',
-            name='location',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bin.locationmodel', unique=True, verbose_name='库位'),
-        ),
-    ]

+ 0 - 29
bin/migrations/0007_alter_locationcontainerlink_container_and_more.py

@@ -1,29 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-17 15:41
-
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('container', '0001_initial'),
-        ('bin', '0006_alter_locationcontainerlink_unique_together_and_more'),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name='locationcontainerlink',
-            name='container',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='container.containerlistmodel'),
-        ),
-        migrations.AlterField(
-            model_name='locationcontainerlink',
-            name='location',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bin.locationmodel', verbose_name='库位'),
-        ),
-        migrations.AlterUniqueTogether(
-            name='locationcontainerlink',
-            unique_together={('location', 'container')},
-        ),
-    ]

+ 0 - 18
bin/migrations/0008_alter_locationmodel_current_quantity.py

@@ -1,18 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-17 20:11
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bin', '0007_alter_locationcontainerlink_container_and_more'),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name='locationmodel',
-            name='current_quantity',
-            field=models.PositiveIntegerField(default=0, verbose_name='当前数'),
-        ),
-    ]

+ 0 - 60
bin/migrations/0009_alloction_pre_allocation_history.py

@@ -1,60 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-18 09:27
-
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('container', '0001_initial'),
-        ('bin', '0008_alter_locationmodel_current_quantity'),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name='alloction_pre',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('batch_number', models.CharField(max_length=255, verbose_name='批次号')),
-                ('layer1_pre', models.IntegerField(default=0, verbose_name='第一层预留')),
-                ('layer2_pre', models.IntegerField(default=0, verbose_name='第二层预留')),
-                ('layer3_pre', models.IntegerField(default=0, verbose_name='第三层预留')),
-                ('layer1_pre_type', models.JSONField(default=list, verbose_name='第一层预留类型')),
-                ('layer1_pre_type_number', models.JSONField(default=list, verbose_name='第一层预留数目')),
-                ('layer2_pre_type', models.JSONField(default=list, verbose_name='第二层预留')),
-                ('layer2_pre_type_number', models.JSONField(default=list, verbose_name='第二层预留数目')),
-                ('layer3_pre_type', models.JSONField(default=list, verbose_name='第三层预留')),
-                ('layer3_pre_type_number', models.JSONField(default=list, verbose_name='第三层预留数目')),
-                ('layer1_pressure', models.IntegerField(default=0, verbose_name='第一层工作压力')),
-                ('layer2_pressure', models.IntegerField(default=0, verbose_name='第二层工作压力')),
-                ('layer3_pressure', models.IntegerField(default=0, verbose_name='第三层工作压力')),
-                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
-            ],
-            options={
-                'verbose_name': 'Allocation_pre',
-                'verbose_name_plural': 'Allocation_pre',
-                'db_table': 'allocation_pre',
-                'ordering': ['-id'],
-            },
-        ),
-        migrations.CreateModel(
-            name='allocation_history',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('operation_type', models.CharField(max_length=10, verbose_name='操作类型')),
-                ('timestamp', models.DateTimeField(auto_now_add=True, verbose_name='操作时间')),
-                ('container', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='container.containerlistmodel', verbose_name='托盘')),
-                ('location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bin.locationmodel', verbose_name='库位')),
-                ('related_location', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='related_logs_history', to='bin.locationmodel', verbose_name='关联库位')),
-                ('task_detail', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='container.taskmodel', verbose_name='批次详情')),
-                ('task_wcs', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='container.containerwcsmodel', verbose_name='WCS任务')),
-            ],
-            options={
-                'verbose_name': 'Allocation_history',
-                'verbose_name_plural': 'Allocation_history',
-                'db_table': 'allocation_history',
-                'ordering': ['-id'],
-            },
-        ),
-    ]

+ 0 - 54
bin/migrations/0010_remove_alloction_pre_layer1_pre_and_more.py

@@ -1,54 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-19 22:31
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bin', '0009_alloction_pre_allocation_history'),
-    ]
-
-    operations = [
-        migrations.RemoveField(
-            model_name='alloction_pre',
-            name='layer1_pre',
-        ),
-        migrations.RemoveField(
-            model_name='alloction_pre',
-            name='layer1_pre_type',
-        ),
-        migrations.RemoveField(
-            model_name='alloction_pre',
-            name='layer1_pre_type_number',
-        ),
-        migrations.RemoveField(
-            model_name='alloction_pre',
-            name='layer2_pre',
-        ),
-        migrations.RemoveField(
-            model_name='alloction_pre',
-            name='layer2_pre_type',
-        ),
-        migrations.RemoveField(
-            model_name='alloction_pre',
-            name='layer2_pre_type_number',
-        ),
-        migrations.RemoveField(
-            model_name='alloction_pre',
-            name='layer3_pre',
-        ),
-        migrations.RemoveField(
-            model_name='alloction_pre',
-            name='layer3_pre_type',
-        ),
-        migrations.RemoveField(
-            model_name='alloction_pre',
-            name='layer3_pre_type_number',
-        ),
-        migrations.AddField(
-            model_name='alloction_pre',
-            name='layer_pre_type',
-            field=models.JSONField(default=list, verbose_name='预留方案'),
-        ),
-    ]

+ 0 - 55
bin/migrations/0011_base_location_remove_alloction_pre_layer1_pressure_and_more.py

@@ -1,55 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-20 14:13
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bin', '0010_remove_alloction_pre_layer1_pre_and_more'),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name='base_location',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('layer1_pressure', models.IntegerField(default=0, verbose_name='第一层工作压力')),
-                ('layer2_pressure', models.IntegerField(default=0, verbose_name='第二层工作压力')),
-                ('layer3_pressure', models.IntegerField(default=0, verbose_name='第三层工作压力')),
-            ],
-            options={
-                'verbose_name': 'Base_location',
-                'verbose_name_plural': 'Base_location',
-                'db_table': 'base_location',
-                'ordering': ['-id'],
-            },
-        ),
-        migrations.RemoveField(
-            model_name='alloction_pre',
-            name='layer1_pressure',
-        ),
-        migrations.RemoveField(
-            model_name='alloction_pre',
-            name='layer2_pressure',
-        ),
-        migrations.RemoveField(
-            model_name='alloction_pre',
-            name='layer3_pressure',
-        ),
-        migrations.AddField(
-            model_name='alloction_pre',
-            name='layer1_task_finish_number',
-            field=models.IntegerField(default=0, verbose_name='第一层任务完成数'),
-        ),
-        migrations.AddField(
-            model_name='alloction_pre',
-            name='layer2_task_finish_number',
-            field=models.IntegerField(default=0, verbose_name='第二层任务完成数'),
-        ),
-        migrations.AddField(
-            model_name='alloction_pre',
-            name='layer3_task_finish_number',
-            field=models.IntegerField(default=0, verbose_name='第三层任务完成数'),
-        ),
-    ]

+ 0 - 18
bin/migrations/0012_alloction_pre_layer_solution_type.py

@@ -1,18 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-20 16:03
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bin', '0011_base_location_remove_alloction_pre_layer1_pressure_and_more'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='alloction_pre',
-            name='layer_solution_type',
-            field=models.JSONField(default=list, verbose_name='规划方案'),
-        ),
-    ]

BIN
bin/migrations/__pycache__/0001_initial.cpython-38.pyc


BIN
bound/__pycache__/filter.cpython-38.pyc


BIN
bound/__pycache__/models.cpython-38.pyc


BIN
bound/__pycache__/serializers.cpython-38.pyc


BIN
bound/__pycache__/urls.cpython-38.pyc


BIN
bound/__pycache__/views.cpython-38.pyc


+ 124 - 2
bound/filter.py

@@ -1,5 +1,5 @@
 from django_filters import FilterSet
-from .models import BoundListModel, BoundDetailModel,BoundBatchModel
+from .models import BoundListModel, BoundDetailModel,BoundBatchModel,OutBatchModel,BatchLogModel,OutBoundDetailModel
 
 
 class BoundListFilter(FilterSet):
@@ -124,4 +124,126 @@ class BoundBatchFilter(FilterSet):
               'date', 'date__gt', 'date__gte', 'date__lt', 'date__lte', 'date__range', 'date__in', 
               'time', 'time__gt', 'time__gte', 'time__lt', 'time__lte', 'time__range', 'time__in', 'isnull', 'in', 'range'],
 
-        }
+        }
+    
+
+class OutBatchFilter(FilterSet):
+    class Meta:
+        model = OutBatchModel
+        fields = {
+            "id": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
+            'out_number': ['exact', 'gt', 'gte', 'lt', 'lte', 'icontains','range'],
+            'out_date': ['exact', 'gt', 'gte', 'lt', 'lte', 'icontains','range'],
+            'out_type': ['icontains', 'exact'],
+            'out_note': ['icontains', 'exact'],
+
+            'warehouse_code': ['icontains', 'exact'],
+            'warehouse_name': ['icontains', 'exact'],
+
+            'goods_code': ['icontains', 'exact'],
+            'goods_desc': ['icontains', 'exact'],
+            'goods_std': ['icontains', 'exact'],
+            'goods_unit': ['icontains', 'exact'],
+            'goods_qty': ['exact', 'gt', 'gte', 'lt', 'lte', 'icontains','range'],
+            'goods_out_qty': ['exact', 'gt', 'gte', 'lt', 'lte', 'icontains','range'],
+           
+            'container_number': ['exact', 'gt', 'gte', 'lt', 'lte', 'icontains','range'],
+            'goods_weight': ['exact', 'gt', 'gte', 'lt', 'lte', 'icontains','range'],
+            'goods_total_weight': ['exact', 'gt', 'gte', 'lt', 'lte', 'icontains','range'],
+            
+            'creater': ['icontains', 'exact'],
+            'openid': ['exact'],
+            'is_delete': ['exact'],
+            'create_time':  ['exact', 'gt', 'gte', 'lt', 'lte',
+             'year', 'year__gt', 'year__gte', 'year__lt', 'year__lte', 'year__range', 'year__in', 
+             'month','month__gt','month__gte','month__lt','month__lte','month__range','month__in', 
+             'day', 'day__gt', 'day__gte', 'day__lt', 'day__lte', 'day__range', 'day__in',
+              'week_day', 'week_day__gt', 'week_day__gte', 'week_day__lt', 'week_day__lte', 'week_day__range', 'week_day__in', 
+              'hour', 'hour__gt', 'hour__gte', 'hour__lt', 'hour__lte', 'hour__range', 'hour__in',
+
+              'date', 'date__gt', 'date__gte', 'date__lt', 'date__lte', 'date__range', 'date__in', 
+              'time', 'time__gt', 'time__gte', 'time__lt', 'time__lte', 'time__range', 'time__in', 'isnull', 'in', 'range'],
+              
+            'update_time': ['exact', 'gt', 'gte', 'lt', 'lte',
+             'year', 'year__gt', 'year__gte', 'year__lt', 'year__lte', 'year__range', 'year__in', 
+             'month','month__gt','month__gte','month__lt','month__lte','month__range','month__in',        
+             'day', 'day__gt', 'day__gte', 'day__lt', 'day__lte', 'day__range', 'day__in',
+              'week_day', 'week_day__gt', 'week_day__gte', 'week_day__lt', 'week_day__lte', 'week_day__range', 'week_day__in', 
+              'hour', 'hour__gt', 'hour__gte', 'hour__lt', 'hour__lte', 'hour__range', 'hour__in',
+
+              'date', 'date__gt', 'date__gte', 'date__lt', 'date__lte', 'date__range', 'date__in', 
+              'time', 'time__gt', 'time__gte', 'time__lt', 'time__lte', 'time__range', 'time__in', 'isnull', 'in', 'range'],            
+        }   
+class BatchlogFilter(FilterSet):
+    class Meta:
+        model = BatchLogModel
+        fields = {
+            "id": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
+            'log_type': ['icontains', 'exact'],
+            'log_date' : ['exact', 'gt', 'gte', 'lt', 'lte',
+             'year', 'year__gt', 'year__gte', 'year__lt', 'year__lte', 'year__range', 'year__in', 
+             'month','month__gt','month__gte','month__lt','month__lte','month__range','month__in', 
+             'day', 'day__gt', 'day__gte', 'day__lt', 'day__lte', 'day__range', 'day__in',
+              'week_day', 'week_day__gt', 'week_day__gte', 'week_day__lt', 'week_day__lte', 'week_day__range', 'week_day__in', 
+              'hour', 'hour__gt', 'hour__gte', 'hour__lt', 'hour__lte', 'hour__range', 'hour__in',
+              'date', 'date__gt', 'date__gte', 'date__lt', 'date__lte', 'date__range', 'date__in',                                                                              
+              'time', 'time__gt', 'time__gte', 'time__lt', 'time__lte', 'time__range', 'time__in', 'isnull', 'in', 'range'],
+            'batch_id': ['exact'],
+            'goods_code' : ['icontains', 'exact'],
+            'goods_desc' : ['icontains', 'exact'],
+            'goods_qty' : ['exact', 'gt', 'gte', 'lt', 'lte', 'icontains','range'],
+            'create_time':  ['exact', 'gt', 'gte', 'lt', 'lte',
+             'year', 'year__gt', 'year__gte', 'year__lt', 'year__lte', 'year__range', 'year__in', 
+             'month','month__gt','month__gte','month__lt','month__lte','month__range','month__in', 
+             'day', 'day__gt', 'day__gte', 'day__lt', 'day__lte', 'day__range', 'day__in',
+              'week_day', 'week_day__gt', 'week_day__gte', 'week_day__lt', 'week_day__lte', 'week_day__range', 'week_day__in', 
+              'hour', 'hour__gt', 'hour__gte', 'hour__lt', 'hour__lte', 'hour__range', 'hour__in',
+
+              'date', 'date__gt', 'date__gte', 'date__lt', 'date__lte', 'date__range', 'date__in', 
+              'time', 'time__gt', 'time__gte', 'time__lt', 'time__lte', 'time__range', 'time__in', 'isnull', 'in', 'range'],
+              
+            'update_time': ['exact', 'gt', 'gte', 'lt', 'lte',
+             'year', 'year__gt', 'year__gte', 'year__lt', 'year__lte', 'year__range', 'year__in', 
+             'month','month__gt','month__gte','month__lt','month__lte','month__range','month__in',        
+             'day', 'day__gt', 'day__gte', 'day__lt', 'day__lte', 'day__range', 'day__in',             
+              'week_day', 'week_day__gt', 'week_day__gte', 'week_day__lt', 'week_day__lte', 'week_day__range', 'week_day__in',              
+              'hour', 'hour__gt', 'hour__gte', 'hour__lt', 'hour__lte', 'hour__range', 'hour__in',              
+              'date', 'date__gt', 'date__gte', 'date__lt', 'date__lte', 'date__range', 'date__in', 
+              'time', 'time__gt', 'time__gte', 'time__lt', 'time__lte', 'time__range', 'time__in', 'isnull', 'in', 'range'],
+
+            
+        }
+class OutBoundDetailFilter(FilterSet):
+    class Meta:
+        model = OutBoundDetailModel
+        fields = {
+            "id": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
+            "detail_code" : ['icontains', 'exact'],
+            "bound_list" : ['exact'],
+            "bound_batch" : ['exact'],
+            "bound_batch_number" : ['exact'],
+            'status': ['exact', 'gt', 'gte', 'lt', 'lte', 'icontains','range'],
+            'creater': ['icontains', 'exact'],
+            'openid': ['exact'],
+            'is_delete': ['exact'],
+            'create_time':  ['exact', 'gt', 'gte', 'lt', 'lte',
+             'year', 'year__gt', 'year__gte', 'year__lt', 'year__lte', 'year__range', 'year__in', 
+             'month','month__gt','month__gte','month__lt','month__lte','month__range','month__in', 
+             'day', 'day__gt', 'day__gte', 'day__lt', 'day__lte', 'day__range', 'day__in',
+              'week_day', 'week_day__gt', 'week_day__gte', 'week_day__lt', 'week_day__lte', 'week_day__range', 'week_day__in', 
+              'hour', 'hour__gt', 'hour__gte', 'hour__lt', 'hour__lte', 'hour__range', 'hour__in',
+
+              'date', 'date__gt', 'date__gte', 'date__lt', 'date__lte', 'date__range', 'date__in', 
+              'time', 'time__gt', 'time__gte', 'time__lt', 'time__lte', 'time__range', 'time__in', 'isnull', 'in', 'range'],
+              
+            'update_time': ['exact', 'gt', 'gte', 'lt', 'lte',
+             'year', 'year__gt', 'year__gte', 'year__lt', 'year__lte', 'year__range', 'year__in', 
+             'month','month__gt','month__gte','month__lt','month__lte','month__range','month__in', 
+             'day', 'day__gt', 'day__gte', 'day__lt', 'day__lte', 'day__range', 'day__in',
+              'week_day', 'week_day__gt', 'week_day__gte', 'week_day__lt', 'week_day__lte', 'week_day__range', 'week_day__in', 
+              'hour', 'hour__gt', 'hour__gte', 'hour__lt', 'hour__lte', 'hour__range', 'hour__in',
+
+              'date', 'date__gt', 'date__gte', 'date__lt', 'date__lte', 'date__range', 'date__in', 
+              'time', 'time__gt', 'time__gte', 'time__lt', 'time__lte', 'time__range', 'time__in', 'isnull', 'in', 'range'],
+        }
+                                                                                                                                                                              

+ 88 - 3
bound/migrations/0001_initial.py

@@ -1,4 +1,4 @@
-# Generated by Django 4.1.2 on 2025-04-09 20:35
+# Generated by Django 4.1.2 on 2025-04-24 23:03
 
 from django.db import migrations, models
 import django.db.models.deletion
@@ -16,19 +16,23 @@ class Migration(migrations.Migration):
             name='BoundBatchModel',
             fields=[
                 ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('bound_number', models.CharField(max_length=255, verbose_name='入库批次号')),
+                ('bound_number', models.CharField(max_length=255, unique=True, verbose_name='入库批次号')),
                 ('bound_month', models.CharField(max_length=255, verbose_name='月份')),
+                ('bound_batch_order', models.IntegerField(default=0, verbose_name='批次顺序')),
                 ('warehouse_code', models.CharField(max_length=255, verbose_name='仓库编码')),
                 ('warehouse_name', models.CharField(max_length=255, verbose_name='仓库名称')),
                 ('goods_code', models.CharField(max_length=255, verbose_name='商品编码')),
                 ('goods_desc', models.CharField(max_length=255, verbose_name='商品描述')),
                 ('goods_std', models.CharField(default='待填写', max_length=255, verbose_name='商品标准')),
+                ('goods_unit', models.CharField(default='待填写', max_length=255, verbose_name='商品单位')),
                 ('goods_qty', models.BigIntegerField(default=0, verbose_name='商品数量')),
                 ('goods_in_qty', models.BigIntegerField(default=0, verbose_name='入库数量')),
                 ('goods_out_qty', models.BigIntegerField(default=0, verbose_name='出库数量')),
-                ('status', models.IntegerField(choices=[(0, '入库申请'), (1, '入库中'), (2, '在库'), (3, '出库中'), (4, '已出库')], default=0, verbose_name='批次状态')),
+                ('status', models.IntegerField(choices=[(0, '入库申请'), (1, '入库中'), (2, '部分入库'), (3, '在库'), (4, '出库中'), (5, '部分出库'), (6, '已出库')], default=0, verbose_name='批次状态')),
+                ('container_number', models.IntegerField(default=0, verbose_name='托盘数目')),
                 ('goods_weight', models.FloatField(default=0, verbose_name='商品单重')),
                 ('goods_total_weight', models.FloatField(default=0, verbose_name='商品总重')),
+                ('note', models.CharField(default='', max_length=255, verbose_name='备注')),
                 ('creater', models.CharField(default='uesr', max_length=255, verbose_name='Who Created')),
                 ('openid', models.CharField(max_length=255, verbose_name='Openid')),
                 ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
@@ -54,7 +58,9 @@ class Migration(migrations.Migration):
                 ('bound_type', models.CharField(max_length=255, verbose_name='出入库类型')),
                 ('bound_desc', models.CharField(default='', max_length=255, verbose_name='出入库描述')),
                 ('bound_department', models.CharField(max_length=255, verbose_name='部门')),
+                ('base_type', models.IntegerField(default=0, verbose_name='基准类型')),
                 ('bound_status', models.CharField(max_length=255, verbose_name='单据状态')),
+                ('note', models.CharField(default='', max_length=255, verbose_name='备注')),
                 ('creater', models.CharField(default='uesr', max_length=255, verbose_name='Who Created')),
                 ('openid', models.CharField(max_length=255, verbose_name='Openid')),
                 ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
@@ -68,6 +74,62 @@ class Migration(migrations.Migration):
                 'ordering': ['-id'],
             },
         ),
+        migrations.CreateModel(
+            name='OutBatchModel',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('out_number', models.CharField(max_length=255, verbose_name='出库批次号')),
+                ('out_date', models.DateTimeField(verbose_name='出库日期')),
+                ('out_type', models.IntegerField(choices=[(0, '发货出库'), (4, '其他出库')], default=4, verbose_name='出库类型')),
+                ('out_note', models.CharField(default='', max_length=255, verbose_name='出库备注')),
+                ('warehouse_code', models.CharField(max_length=255, verbose_name='仓库编码')),
+                ('warehouse_name', models.CharField(max_length=255, verbose_name='仓库名称')),
+                ('goods_code', models.CharField(max_length=255, verbose_name='商品编码')),
+                ('goods_desc', models.CharField(max_length=255, verbose_name='商品描述')),
+                ('goods_std', models.CharField(default='待填写', max_length=255, verbose_name='商品标准')),
+                ('goods_unit', models.CharField(default='待填写', max_length=255, verbose_name='商品单位')),
+                ('goods_qty', models.BigIntegerField(default=0, verbose_name='商品数量')),
+                ('goods_out_qty', models.BigIntegerField(default=0, verbose_name='出库数量')),
+                ('status', models.IntegerField(choices=[(0, '申请'), (1, '在途'), (2, '已出库')], default=0, verbose_name='批次状态')),
+                ('container_number', models.IntegerField(default=0, verbose_name='托盘数目')),
+                ('goods_weight', models.FloatField(default=0, verbose_name='商品单重')),
+                ('goods_total_weight', models.FloatField(default=0, verbose_name='商品总重')),
+                ('creater', models.CharField(default='uesr', max_length=255, verbose_name='Who Created')),
+                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
+                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
+                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
+                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
+                ('batch_number', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='out_batch', to='bound.boundbatchmodel', verbose_name='批次号')),
+            ],
+            options={
+                'verbose_name': 'Out Batch',
+                'verbose_name_plural': 'Out Batch',
+                'db_table': 'outbatch',
+                'ordering': ['-id'],
+            },
+        ),
+        migrations.CreateModel(
+            name='OutBoundDetailModel',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('status', models.IntegerField(choices=[(0, '出库申请'), (1, '出库中'), (2, '已出库'), (3, '入库中'), (4, '已入库')], default=0, verbose_name='批次状态')),
+                ('detail_code', models.CharField(max_length=255, unique=True, verbose_name='明细编号')),
+                ('creater', models.CharField(default='uesr', max_length=255, verbose_name='Who Created')),
+                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
+                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
+                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
+                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
+                ('bound_batch', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='out_bound_batch_detail', to='bound.outbatchmodel', verbose_name='Bound Batch')),
+                ('bound_batch_number', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='out_bound_batch_number_detail', to='bound.boundbatchmodel', verbose_name='Bound Batch Number')),
+                ('bound_list', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='out_bound_detail', to='bound.boundlistmodel', verbose_name='Bound List')),
+            ],
+            options={
+                'verbose_name': 'OutBound Detail',
+                'verbose_name_plural': 'OutBound Detail',
+                'db_table': 'Outbounddetail',
+                'ordering': ['-id'],
+            },
+        ),
         migrations.CreateModel(
             name='BoundDetailModel',
             fields=[
@@ -89,4 +151,27 @@ class Migration(migrations.Migration):
                 'ordering': ['-id'],
             },
         ),
+        migrations.CreateModel(
+            name='BatchLogModel',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('log_type', models.IntegerField(choices=[(0, '入库'), (1, '出库'), (2, '移库'), (9, '其他')], default=9, verbose_name='日志类型')),
+                ('log_date', models.DateTimeField(verbose_name='日志日期')),
+                ('goods_code', models.CharField(max_length=255, verbose_name='商品编码')),
+                ('goods_desc', models.CharField(max_length=255, verbose_name='商品描述')),
+                ('goods_qty', models.BigIntegerField(default=0, verbose_name='商品数量')),
+                ('log_content', models.CharField(max_length=255, verbose_name='日志内容')),
+                ('creater', models.CharField(default='uesr', max_length=255, verbose_name='Who Created')),
+                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
+                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
+                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
+                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
+                ('batch_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='batch_log', to='bound.boundbatchmodel', verbose_name='批次ID')),
+            ],
+            options={
+                'verbose_name': 'Batch Log',
+                'verbose_name_plural': 'Batch Log',
+                'db_table': 'batchlog',
+            },
+        ),
     ]

+ 0 - 18
bound/migrations/0002_alter_boundbatchmodel_status.py

@@ -1,18 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-17 09:19
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bound', '0001_initial'),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name='boundbatchmodel',
-            name='status',
-            field=models.IntegerField(choices=[(0, '入库申请'), (1, '入库中'), (2, '部分入库'), (3, '在库'), (4, '出库中'), (5, '部分出库'), (6, '已出库')], default=0, verbose_name='批次状态'),
-        ),
-    ]

+ 0 - 18
bound/migrations/0003_boundbatchmodel_container_number.py

@@ -1,18 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-17 20:11
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bound', '0002_alter_boundbatchmodel_status'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='boundbatchmodel',
-            name='container_number',
-            field=models.IntegerField(default=0, verbose_name='托盘数目'),
-        ),
-    ]

+ 0 - 18
bound/migrations/0004_boundbatchmodel_goods_unit.py

@@ -1,18 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-22 10:24
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bound', '0003_boundbatchmodel_container_number'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='boundbatchmodel',
-            name='goods_unit',
-            field=models.CharField(default='待填写', max_length=255, verbose_name='商品单位'),
-        ),
-    ]

+ 0 - 44
bound/migrations/0005_outboundmodel_boundbatchmodel_note.py

@@ -1,44 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-23 22:17
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bound', '0004_boundbatchmodel_goods_unit'),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name='OutBoundModel',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('bound_month', models.CharField(max_length=255, verbose_name='月份')),
-                ('bound_date', models.DateField(verbose_name='单据日期')),
-                ('bound_code', models.CharField(max_length=255, unique=True, verbose_name='出入库编号')),
-                ('bound_code_type', models.CharField(max_length=255, verbose_name='单据类型')),
-                ('bound_bs_type', models.CharField(max_length=255, verbose_name='业务类型')),
-                ('bound_type', models.CharField(max_length=255, verbose_name='出入库类型')),
-                ('bound_desc', models.CharField(default='', max_length=255, verbose_name='出入库描述')),
-                ('bound_department', models.CharField(max_length=255, verbose_name='部门')),
-                ('bound_status', models.CharField(max_length=255, verbose_name='单据状态')),
-                ('creater', models.CharField(default='uesr', max_length=255, verbose_name='Who Created')),
-                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
-                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
-                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
-                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
-            ],
-            options={
-                'verbose_name': 'Out List',
-                'verbose_name_plural': 'Out List',
-                'db_table': 'Outlist',
-                'ordering': ['-id'],
-            },
-        ),
-        migrations.AddField(
-            model_name='boundbatchmodel',
-            name='note',
-            field=models.CharField(default='', max_length=255, verbose_name='备注'),
-        ),
-    ]

+ 0 - 27
bound/migrations/0006_remove_boundbatchmodel_note_boundlistmodel_note_and_more.py

@@ -1,27 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-23 22:17
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bound', '0005_outboundmodel_boundbatchmodel_note'),
-    ]
-
-    operations = [
-        migrations.RemoveField(
-            model_name='boundbatchmodel',
-            name='note',
-        ),
-        migrations.AddField(
-            model_name='boundlistmodel',
-            name='note',
-            field=models.CharField(default='', max_length=255, verbose_name='备注'),
-        ),
-        migrations.AddField(
-            model_name='outboundmodel',
-            name='note',
-            field=models.CharField(default='', max_length=255, verbose_name='备注'),
-        ),
-    ]

+ 0 - 41
bound/migrations/0007_batchlogmodel_delete_outboundmodel_and_more.py

@@ -1,41 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-23 23:14
-
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bound', '0006_remove_boundbatchmodel_note_boundlistmodel_note_and_more'),
-    ]
-
-    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=[(0, '入库'), (1, '出库'), (2, '移库'), (9, '其他')], default=9, max_length=255, verbose_name='日志类型')),
-                ('log_content', models.CharField(max_length=255, verbose_name='日志内容')),
-                ('creater', models.CharField(default='uesr', max_length=255, verbose_name='Who Created')),
-                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
-                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
-                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
-                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
-                ('batch_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='batch_log', to='bound.boundbatchmodel', verbose_name='批次ID')),
-            ],
-            options={
-                'verbose_name': 'Batch Log',
-                'verbose_name_plural': 'Batch Log',
-                'db_table': 'batchlog',
-            },
-        ),
-        migrations.DeleteModel(
-            name='OutBoundModel',
-        ),
-        migrations.AddField(
-            model_name='boundlistmodel',
-            name='base_type',
-            field=models.IntegerField(default=0, verbose_name='基准类型'),
-        ),
-    ]

+ 0 - 36
bound/migrations/0008_batchlogmodel_goods_code_batchlogmodel_goods_qty_and_more.py

@@ -1,36 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-24 00:26
-
-from django.db import migrations, models
-import django.utils.timezone
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bound', '0007_batchlogmodel_delete_outboundmodel_and_more'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='batchlogmodel',
-            name='goods_code',
-            field=models.CharField(default=0, max_length=255, verbose_name='商品编码'),
-            preserve_default=False,
-        ),
-        migrations.AddField(
-            model_name='batchlogmodel',
-            name='goods_qty',
-            field=models.BigIntegerField(default=0, verbose_name='商品数量'),
-        ),
-        migrations.AddField(
-            model_name='batchlogmodel',
-            name='log_date',
-            field=models.DateField(default=django.utils.timezone.now, verbose_name='日志日期'),
-            preserve_default=False,
-        ),
-        migrations.AddField(
-            model_name='boundbatchmodel',
-            name='bound_batch_order',
-            field=models.IntegerField(default=0, verbose_name='批次顺序'),
-        ),
-    ]

+ 0 - 18
bound/migrations/0009_alter_boundbatchmodel_bound_number.py

@@ -1,18 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-24 00:31
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bound', '0008_batchlogmodel_goods_code_batchlogmodel_goods_qty_and_more'),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name='boundbatchmodel',
-            name='bound_number',
-            field=models.CharField(blank=True, max_length=255, null=True, unique=True, verbose_name='入库批次号'),
-        ),
-    ]

+ 0 - 18
bound/migrations/0010_alter_boundbatchmodel_bound_number.py

@@ -1,18 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-24 00:33
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bound', '0009_alter_boundbatchmodel_bound_number'),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name='boundbatchmodel',
-            name='bound_number',
-            field=models.CharField(max_length=255, unique=True, verbose_name='入库批次号'),
-        ),
-    ]

BIN
bound/migrations/__pycache__/0001_initial.cpython-38.pyc


BIN
bound/migrations/__pycache__/0002_alter_boundbatchmodel_status.cpython-38.pyc


BIN
bound/migrations/__pycache__/0002_bounddetailmodel_status.cpython-38.pyc


BIN
bound/migrations/__pycache__/0002_boundlistmodel_bound_desc.cpython-38.pyc


BIN
bound/migrations/__pycache__/0003_boundbatchmodel_container_number.cpython-38.pyc


BIN
bound/migrations/__pycache__/0003_boundbatchmodel_goods_std.cpython-38.pyc


BIN
bound/migrations/__pycache__/0004_boundbatchmodel_goods_unit.cpython-38.pyc


BIN
bound/migrations/__pycache__/0005_outboundmodel_boundbatchmodel_note.cpython-38.pyc


BIN
bound/migrations/__pycache__/0006_remove_boundbatchmodel_note_boundlistmodel_note_and_more.cpython-38.pyc


BIN
bound/migrations/__pycache__/0007_batchlogmodel_delete_outboundmodel_and_more.cpython-38.pyc


BIN
bound/migrations/__pycache__/0008_batchlogmodel_goods_code_batchlogmodel_goods_qty_and_more.cpython-38.pyc


BIN
bound/migrations/__pycache__/0009_alter_boundbatchmodel_bound_number.cpython-38.pyc


BIN
bound/migrations/__pycache__/0010_alter_boundbatchmodel_bound_number.cpython-38.pyc


+ 80 - 5
bound/models.py

@@ -61,20 +61,95 @@ class BoundBatchModel(models.Model):
     container_number = models.IntegerField( default=0, verbose_name="托盘数目")
     goods_weight = models.FloatField(default=0, verbose_name="商品单重")
     goods_total_weight = models.FloatField(default=0, verbose_name="商品总重")
-
+    note = models.CharField(default='', max_length=255, verbose_name="备注")
 
     creater = models.CharField(default='uesr', max_length=255, verbose_name="Who Created")
     openid = models.CharField(max_length=255, verbose_name="Openid")
     is_delete = models.BooleanField(default=False, verbose_name='Delete Label')
     create_time = models.DateTimeField(auto_now_add=True, verbose_name="Create Time")
     update_time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name="Update Time")
-
+    
     class Meta:
         db_table = 'boundbatch'
         verbose_name = 'Bound Batch'
         verbose_name_plural = "Bound Batch"
         ordering = ['-id']
 
+class OutBatchModel(models.Model):
+    CONTAINER_STATUS = (
+        (0, '申请'),
+        (1, '在途'),
+        (2, '已出库')
+    )
+    OUT_TYPE = (
+        (0, '发货出库'),
+
+        (4, '其他出库'),
+    )
+    out_number = models.CharField(max_length=255, verbose_name="出库批次号",blank=False, null=False)
+
+    batch_number = models.ForeignKey(BoundBatchModel, on_delete=models.CASCADE, verbose_name="批次号", related_name='out_batch')
+
+    out_date = models.DateTimeField(verbose_name="出库日期")
+
+    out_type = models.IntegerField(choices=OUT_TYPE, default=4,  verbose_name="出库类型")
+    out_note = models.CharField(default='', max_length=255, verbose_name="出库备注")
+
+    warehouse_code = models.CharField(max_length=255, verbose_name="仓库编码")
+    warehouse_name = models.CharField(max_length=255, verbose_name="仓库名称")
+
+    goods_code = models.CharField(max_length=255, verbose_name="商品编码")
+    goods_desc = models.CharField(max_length=255, verbose_name="商品描述")
+    goods_std = models.CharField(default='待填写', max_length=255, verbose_name="商品标准")
+    goods_unit = models.CharField(default='待填写', max_length=255, verbose_name="商品单位")
+    goods_qty = models.BigIntegerField(default=0, verbose_name="商品数量")
+    goods_out_qty = models.BigIntegerField(default=0, verbose_name="出库数量")
+
+    status = models.IntegerField(choices=CONTAINER_STATUS, default=0, verbose_name='批次状态')
+
+    container_number = models.IntegerField( default=0, verbose_name="托盘数目")
+    goods_weight = models.FloatField(default=0, verbose_name="商品单重")
+    goods_total_weight = models.FloatField(default=0, verbose_name="商品总重")
+
+    creater = models.CharField(default='uesr', max_length=255, verbose_name="Who Created")
+    openid = models.CharField(max_length=255, verbose_name="Openid")
+    is_delete = models.BooleanField(default=False, verbose_name='Delete Label')
+    create_time = models.DateTimeField(auto_now_add=True, verbose_name="Create Time")
+    update_time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name="Update Time")
+
+    class Meta:
+        db_table = 'outbatch'
+        verbose_name = 'Out Batch'
+        verbose_name_plural = "Out Batch"
+        ordering = ['-id']
+
+# 利用创建好的批次来与申请单相对应       
+class OutBoundDetailModel(models.Model):
+    CONTAINER_STATUS = (
+        (0, '出库申请'),
+        (1, '出库中'),
+        (2, '已出库'),
+        (3, '入库中'),
+        (4, '已入库')
+    )
+
+    bound_list = models.ForeignKey(BoundListModel, on_delete=models.CASCADE, verbose_name="Bound List", related_name='out_bound_detail')
+    bound_batch = models.ForeignKey(OutBatchModel, on_delete=models.PROTECT, verbose_name="Bound Batch", related_name='out_bound_batch_detail')
+    bound_batch_number = models.ForeignKey(BoundBatchModel, on_delete=models.CASCADE, verbose_name="Bound Batch Number", related_name='out_bound_batch_number_detail')
+    status = models.IntegerField(choices=CONTAINER_STATUS, default=0, verbose_name='批次状态')
+    
+    detail_code = models.CharField(max_length=255, verbose_name="明细编号",unique=True)
+    creater = models.CharField(default='uesr', max_length=255, verbose_name="Who Created")
+    openid = models.CharField(max_length=255, verbose_name="Openid")
+    is_delete = models.BooleanField(default=False, verbose_name='Delete Label')
+    create_time = models.DateTimeField(auto_now_add=True, verbose_name="Create Time")
+    update_time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name="Update Time")
+
+    class Meta:
+        db_table = 'Outbounddetail'
+        verbose_name = 'OutBound Detail'
+        verbose_name_plural = "OutBound Detail"
+        ordering = ['-id']
 
 class BatchLogModel(models.Model):
     BATCH_LOG_TYPE = (
@@ -85,9 +160,10 @@ class BatchLogModel(models.Model):
         
     )
     batch_id  =models.ForeignKey(BoundBatchModel, on_delete=models.CASCADE, verbose_name="批次ID", related_name='batch_log')
-    log_type = models.CharField(choices=BATCH_LOG_TYPE, default=9,max_length=255,verbose_name="日志类型")
-    log_date = models.DateField(verbose_name="日志日期")
+    log_type = models.IntegerField(choices=BATCH_LOG_TYPE, default=9, verbose_name="日志类型")
+    log_date = models.DateTimeField(verbose_name="日志日期")
     goods_code = models.CharField(max_length=255, verbose_name="商品编码")
+    goods_desc = models.CharField(max_length=255, verbose_name="商品描述")
     goods_qty = models.BigIntegerField(default=0, verbose_name="商品数量")
     log_content = models.CharField(max_length=255, verbose_name="日志内容")
     creater = models.CharField(default='uesr', max_length=255, verbose_name="Who Created")
@@ -101,7 +177,6 @@ class BatchLogModel(models.Model):
         verbose_name = 'Batch Log'
         verbose_name_plural = "Batch Log"
 
-
 # 利用创建好的批次来与申请单相对应       
 class BoundDetailModel(models.Model):
     CONTAINER_STATUS = (

+ 137 - 3
bound/serializers.py

@@ -1,5 +1,5 @@
 from rest_framework import serializers
-from .models import BoundListModel, BoundDetailModel, BoundBatchModel
+from .models import BoundListModel, BoundDetailModel, BoundBatchModel,OutBatchModel,BatchLogModel,OutBoundDetailModel
 from utils import datasolve
 
 
@@ -54,7 +54,7 @@ class BoundBatchGetSerializer(serializers.ModelSerializer):
     # 定义批次列表的序列化器,用于获取操作,字段只读
     bound_number = serializers.CharField(read_only=True, required=False)
     bound_month = serializers.CharField(read_only=True, required=False)
-
+    
     warehouse_code = serializers.CharField(read_only=True, required=False)
     warehouse_name = serializers.CharField(read_only=True, required=False)
     goods_code = serializers.CharField(read_only=True, required=False)
@@ -153,6 +153,7 @@ class BoundDetailGetSerializer(serializers.ModelSerializer):
 
 
 class BoundDetailPostSerializer(serializers.ModelSerializer):
+
     # 使用主键ID关联主单和批次
     bound_list = serializers.PrimaryKeyRelatedField(
         queryset=BoundListModel.objects.all(),
@@ -201,4 +202,137 @@ class BoundDetailPostSerializer(serializers.ModelSerializer):
                 'default': False,
                 'help_text': "逻辑删除标记(默认False)"
             }
-        }
+        }
+
+class OutBatchGetSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = OutBatchModel
+        fields = '__all__'
+        read_only_fields = ['id', 'openid']
+class OutBatchPostSerializer(serializers.ModelSerializer):
+    out_number = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate]) 
+    out_type = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate]) 
+    out_note = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate]) 
+    out_date = serializers.DateTimeField(read_only=False, required=False, validators=[datasolve.data_validate])
+    warehouse_code = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
+    warehouse_name = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
+    
+    goods_code = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
+    goods_desc = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
+    goods_std = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
+    goods_qty = serializers.IntegerField(read_only=False, required=False, validators=[datasolve.data_validate])
+
+    goods_out_qty = serializers.IntegerField(read_only=False, required=False, validators=[datasolve.data_validate])
+    creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
+
+
+
+    class Meta:
+        model = OutBatchModel
+        fields = '__all__'
+        read_only_fields = ['id', 'openid']
+
+
+class BatchLogGetSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = BatchLogModel
+        fields = '__all__'
+        read_only_fields = ['id', 'openid']
+
+
+class OutBoundDetailGetSerializer(serializers.ModelSerializer):
+ # 嵌套展示关联的主单和批次信息
+    bound_list = serializers.SerializerMethodField()
+    bound_batch = serializers.SerializerMethodField()
+    bound_batch_number = serializers.SerializerMethodField()
+    detail_code = serializers.CharField(read_only=True, required=False)
+    status = serializers.IntegerField(read_only=False, required=False)
+
+
+    # 定义其他字段,只读
+    creater = serializers.CharField(source='creater.username', read_only=True)
+    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S')
+    update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S')
+
+    class Meta:
+        # 指定模型和字段,所有字段只读
+        model = OutBoundDetailModel
+        fields = [
+            'id',
+            'bound_list',
+            'bound_batch',
+            'bound_batch_number',
+            'detail_code',
+            'creater',
+            'create_time',
+            'update_time',
+            'is_delete',
+            'status'
+        ]
+        read_only_fields = ['__all__']
+
+    def get_bound_list(self, obj):
+        """ 动态序列化关联的主单数据 """
+        from .serializers import BoundListGetSerializer  # 延迟导入避免循环引用
+        return BoundListGetSerializer(obj.bound_list).data
+
+    def get_bound_batch(self, obj):
+        from .serializers import OutBatchGetSerializer
+      
+        return OutBatchGetSerializer(obj.bound_batch).data
+    def get_bound_batch_number(self, obj):
+       
+        from .serializers import BoundBatchGetSerializer
+        return BoundBatchGetSerializer(obj.bound_batch_number).data
+        
+class OutBoundDetailPostSerializer(serializers.ModelSerializer):
+   # 使用主键ID关联主单和批次
+    bound_list = serializers.PrimaryKeyRelatedField(
+        queryset=BoundListModel.objects.all(),
+        help_text="关联主单ID(必须已存在)",
+        error_messages={
+            'does_not_exist': "指定主单不存在",
+            'incorrect_type': "主单ID格式错误"
+        }
+    )
+    bound_batch = serializers.PrimaryKeyRelatedField(
+        queryset=OutBatchModel.objects.all(),
+        help_text="关联批次ID(必须已存在)",
+        error_messages={
+            'does_not_exist': "指定批次不存在",
+            'incorrect_type': "批次ID格式错误"
+        }
+    )
+
+    # 创建人字段,必须填写
+    creater = serializers.CharField(
+        required=True,
+        max_length=255,
+        help_text="创建人标识(建议从用户系统获取)",
+        error_messages={
+            'blank': "创建人不能为空",
+            'max_length': "最长255个字符"
+        }
+    )
+
+    detail_code = serializers.CharField(read_only=False, required=False)
+    status = serializers.IntegerField(read_only=False, required=False)
+
+
+    class Meta:
+        # 指定模型和字段,部分字段只读
+        model = OutBoundDetailModel 
+        fields='__all__'
+        read_only_fields = [
+            'id',
+            'create_time',
+            'update_time',
+            'is_delete'
+        ]
+        extra_kwargs = {
+            'is_delete': {
+                'default': False,
+                'help_text': "逻辑删除标记(默认False)"
+            }
+        }
+

+ 21 - 1
bound/urls.py

@@ -19,13 +19,33 @@ re_path(r'^detail/(?P<pk>\d+)/$', views.BoundDetailViewSet.as_view({
     'delete': 'destroy',
 }), name="bounddetail_1"),
 
+path(r'outdetail/', views.OutBoundDetailViewSet.as_view({"get": "list", "post": "create" }), name="outbounddetail"), 
+
+re_path(r'^outdetail/(?P<pk>\d+)/$', views.OutBoundDetailViewSet.as_view({
+    'get': 'retrieve',
+    'put': 'update',
+    'patch': 'partial_update',
+    'delete': 'destroy',
+}), name="outbounddetail_1"),
+
 path(r'batch/', views.BoundBatchViewSet.as_view({"get": "list", "post": "create" }), name="boundbatch"), 
 
-re_path(r'^detail/(?P<pk>\d+)/$', views.BoundBatchViewSet.as_view({
+re_path(r'^batch/(?P<pk>\d+)/$', views.BoundBatchViewSet.as_view({
     'get': 'retrieve',
     'put': 'update',
     'patch': 'partial_update',
     'delete': 'destroy',
 }), name="boundbatch_1"),
 
+path(r'outbatch/', views.OutBoundBatchViewSet.as_view({"get": "list", "post": "create" }), name="outboundbatch"), 
+
+re_path(r'^outbatch/(?P<pk>\d+)/$', views.OutBoundBatchViewSet.as_view({
+    'get': 'retrieve',
+    'put': 'update',
+    'patch': 'partial_update',
+    'delete': 'destroy',
+}), name="outboundbatch_1"),
+
+path(r'batchlog/', views.BoundBatchLogViewSet.as_view({"get": "list", "post": "create" }), name="boundbatchlog"), 
+
 ]

+ 305 - 28
bound/views.py

@@ -11,19 +11,19 @@ from django.utils import timezone
 
 
 
-from .models import BoundListModel, BoundDetailModel,BoundBatchModel
+from .models import BoundListModel, BoundDetailModel,BoundBatchModel, BatchLogModel, OutBatchModel,OutBoundDetailModel
 # from .files import FileListRenderCN, FileDetailRenderCN
 
 from .serializers import BoundListGetSerializer,BoundListPostSerializer,BoundBatchGetSerializer,BoundBatchPostSerializer,BoundDetailGetSerializer,BoundDetailPostSerializer
+from .serializers import OutBoundDetailGetSerializer,OutBoundDetailPostSerializer,OutBatchGetSerializer,OutBatchPostSerializer,BatchLogGetSerializer
 from .filter import BoundListFilter, BoundDetailFilter,BoundBatchFilter
+from .filter import OutBatchFilter,OutBoundDetailFilter,BatchlogFilter
 # 以后添加模块检验
 from warehouse.models import ListModel as warehouse
 from staff.models import ListModel as staff
 from rest_framework.permissions import AllowAny
 
 
-
-
 class BoundListViewSet(viewsets.ModelViewSet):
     """
         retrieve:
@@ -167,31 +167,67 @@ class BoundBatchViewSet(viewsets.ModelViewSet):
 
     def create(self, request, *args, **kwargs):
         data = self.request.data
-       
-        data['openid'] = self.request.auth.openid
-        data['goods_total_weight'] = data['goods_weight']*data['goods_qty']
-      
-        order_day=str(timezone.now().strftime('-%Y%m'))
-        order_month=str(timezone.now().strftime('%Y%m'))
-        data['bound_month'] =str(timezone.now().strftime('%Y%m'))
-        print(data['order'])
-        if data['order'] == 'true':
-            qs_set = BoundBatchModel.objects.filter( goods_code=data['goods_code'], bound_month=order_month,  is_delete=False)
-            print('qs_set是:', len(qs_set))
-            if len(qs_set) > 0:
-                bound_last_code = qs_set.order_by('-id').first().bound_number
-                data['bound_batch_order'] = int(bound_last_code.split('-')[-1])+1
-                data['bound_number'] = data['goods_code'] + '-' + str(int(bound_last_code.split('-')[-1])+1)
+        try:
+            data['openid'] = self.request.auth.openid
+            data['goods_total_weight'] = data['goods_weight']*data['goods_qty']
+        
+            order_day=str(timezone.now().strftime('-%Y%m'))
+            order_month=str(timezone.now().strftime('%Y%m'))
+            data['bound_month'] =str(timezone.now().strftime('%Y%m'))
+            print(data['order'])
+            if data['order'] == 'true':
+                qs_set = BoundBatchModel.objects.filter( goods_code=data['goods_code'], bound_month=order_month,  is_delete=False)
+                print('qs_set是:', len(qs_set))
+                if len(qs_set) > 0:
+                    bound_last_code = qs_set.order_by('-id').first().bound_number
+                    data['bound_batch_order'] = int(bound_last_code.split('-')[-1])+1
+                    data['bound_number'] = data['goods_code'] + '-' + str(int(bound_last_code.split('-')[-1])+1)
+                else:
+                    data['bound_batch_order'] = int(order_day.split('-')[-1])*100 +1
+                    data['bound_number'] = data['goods_code'] + order_day + '01'
             else:
-                data['bound_batch_order'] = 1
-                data['bound_number'] = data['goods_code'] + order_day + '01'
+                data['bound_number'] = data['goods_code'] + '-' + str(data['bound_batch_order'])
+            serializer = self.get_serializer(data=data)
+            serializer.is_valid(raise_exception=True)
+            serializer.save()
+            headers = self.get_success_headers(serializer.data)
+            self.add_batch_log(serializer.data, 0, data['goods_qty'])
 
-        serializer = self.get_serializer(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)
+            return Response(serializer.data, status=200, headers=headers)
+        except Exception as e:
+            print(e)
+            raise APIException({"detail": "{}".format(e)})
     
+    def add_batch_log(self, data, log_type, goods_qty):
+        choices_dict = dict(BatchLogModel.BATCH_LOG_TYPE)
+        log_type_name = choices_dict.get(log_type, "未知类型")
+        
+        try:
+            # 获取 BoundBatchModel 实例
+            batch_obj = BoundBatchModel.objects.get(id=data['id'])
+        except BoundBatchModel.DoesNotExist:
+
+            return False
+
+        log_data = {
+            'batch_id': batch_obj,  
+            'log_type': log_type,
+            'log_date': timezone.now().strftime('%Y-%m-%d-%H:%M'),  # 直接格式化时间,无需转字符串
+            'goods_code': data['goods_code'],
+            'goods_desc': data['goods_desc'],
+            'goods_qty': data['goods_qty'],
+            'log_content': f"{log_type_name} {data['goods_qty']}件",
+            'creater': data['creater'],
+            'openid': data['openid'],
+            'is_delete': False,
+            
+        }
+        
+        # 创建日志记录
+        BatchLogModel.objects.create(**log_data)
+        return True
+
+
     def update(self, request, pk):
         qs = self.get_object()
         data = self.request.data
@@ -211,9 +247,7 @@ class BoundBatchViewSet(viewsets.ModelViewSet):
             serializer = self.get_serializer(qs, many=False)
             headers = self.get_success_headers(serializer.data)
             return Response(serializer.data, status=200, headers=headers)
-
-
-       
+      
 class BoundDetailViewSet(viewsets.ModelViewSet):
     """
         retrieve:
@@ -297,3 +331,246 @@ class BoundDetailViewSet(viewsets.ModelViewSet):
             serializer = self.get_serializer(qs, many=False)
             headers = self.get_success_headers(serializer.data)
             return Response(serializer.data, status=200, headers=headers)
+
+class OutBoundDetailViewSet(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)
+    """
+    # authentication_classes = []  # 禁用所有认证类
+    # permission_classes = [AllowAny]  # 允许任意访问
+    pagination_class = MyPageNumberPagination
+    filter_backends = [DjangoFilterBackend, OrderingFilter, ]
+    ordering_fields = ['id', "create_time", "update_time", ]
+    filter_class = OutBoundDetailFilter
+
+    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 OutBoundDetailModel.objects.filter( is_delete=False)
+            else:
+                return OutBoundDetailModel.objects.filter( id=id, is_delete=False)
+        else:
+            return OutBoundDetailModel.objects.none()
+
+    def get_serializer_class(self):
+        if self.action in ['list', 'destroy','retrieve']:
+            return OutBoundDetailGetSerializer
+        elif self.action in ['create', 'update']:
+            return OutBoundDetailPostSerializer
+        else:
+            return self.http_method_not_allowed(request=self.request)
+
+    def create(self, request, *args, **kwargs):
+        data = self.request.data
+        data['openid'] = self.request.auth.openid
+        data.setdefault('is_delete', False)
+
+        data['bound_batch_number'] = OutBatchModel.objects.get(id=data['bound_batch']).batch_number.id
+        # 验证并保存数据
+        data['detail_code'] = f"DC-{data['bound_list']:02}{data['bound_batch']:02}"
+        print(data['detail_code'])
+        if OutBoundDetailModel.objects.filter(detail_code=data['detail_code'], is_delete=False).exists():
+            raise APIException({"detail": "Data exists"})
+        else:
+            serializer = self.get_serializer(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 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 destroy(self, request, pk):
+        qs = self.get_object()
+        if qs.openid != self.request.auth.openid:
+            raise APIException({"detail": "该入库非您所属,禁止删除,您可以进行编辑"})
+        else:
+            qs.is_delete = True
+            qs.save()
+            serializer = self.get_serializer(qs, many=False)
+            headers = self.get_success_headers(serializer.data)
+            return Response(serializer.data, status=200, headers=headers)       
+
+class OutBoundBatchViewSet(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)
+            """
+    # authentication_classes = []  # 禁用所有认证类
+    # permission_classes = [AllowAny]  # 允许任意访问
+    pagination_class = MyPageNumberPagination
+    filter_backends = [DjangoFilterBackend, OrderingFilter, ]
+    ordering_fields = ['id', "create_time", "update_time", ]
+    filter_class = OutBatchFilter
+
+    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 OutBatchModel.objects.filter( is_delete=False)
+            else:
+                return OutBatchModel.objects.filter( id=id, is_delete=False)
+        else:
+            return OutBatchModel.objects.none()
+
+    def get_serializer_class(self):
+        if self.action in ['list', 'destroy','retrieve']:
+            return OutBatchGetSerializer
+        elif self.action in ['create', 'update']:
+            return OutBatchPostSerializer
+        else:
+            return self.http_method_not_allowed(request=self.request)
+
+    def create(self, request, *args, **kwargs):
+        data = self.request.data
+        batch_obj = BoundBatchModel.objects.get(bound_number=data['out_number'])
+        if batch_obj is None:
+            raise APIException({"detail": "批次不存在"})
+
+        data['batch_number'] = batch_obj.id
+        data['out_date'] = str(timezone.now().strftime('%Y-%m-%d %H:%M:%S'))
+
+        data['openid'] = self.request.auth.openid
+        data.setdefault('is_delete', False)
+        data['goods_total_weight'] = data['goods_weight']*data['goods_out_qty']
+        data['goods_qty'] = batch_obj.goods_qty -batch_obj.goods_out_qty - data['goods_out_qty']
+        batch_obj.goods_out_qty += data['goods_out_qty']
+        
+        if batch_obj.goods_out_qty > batch_obj.goods_in_qty:
+            raise APIException({"detail": "出库数量大于批次数量"})
+        batch_obj.goods_qty -= data['goods_out_qty']
+        batch_obj.save()
+        data['status'] = 0  #现在处于出库申请状态
+   
+        serializer = self.get_serializer(data=data)
+        serializer.is_valid(raise_exception=True)
+        serializer.save()
+        headers = self.get_success_headers(serializer.data)
+        self.add_batch_log(serializer.data, 1, data['goods_out_qty'])
+        
+        return Response(serializer.data, status=200, headers=headers)
+
+    def update(self, request, pk):        
+        qs = self.get_object()
+        data = self.request.data
+        data['openid'] = self.request.auth.openid
+        data.setdefault('is_delete', False)
+        data['goods_total_weight'] = data['goods_weight']*data['goods_qty']
+        serializer = self.get_serializer(qs, data=data)
+        serializer.is_valid(raise_exception=True)
+        serializer.save()
+        headers = self.get_success_headers(serializer.data)
+        self.add_batch_log(serializer.data, 1, data['goods_qty'])
+        return Response(serializer.data, status=200, headers=headers)
+
+    def destroy(self, request, pk):
+        qs = self.get_object()
+        if qs.openid != self.request.auth.openid:            
+            raise APIException({"detail": "该出库非您所属,禁止删除,您可以进行编辑"})
+        else:
+            qs.is_delete = True
+            qs.save()
+            serializer = self.get_serializer(qs, many=False)
+            headers = self.get_success_headers(serializer.data)
+            return Response(serializer.data, status=200, headers=headers)
+
+    def add_batch_log(self, data, log_type, goods_qty):
+        choices_dict = dict(BatchLogModel.BATCH_LOG_TYPE)
+        log_type_name = choices_dict.get(log_type, "未知类型")
+
+        try:
+            # 获取 BoundBatchModel 实例
+            batch_obj = BoundBatchModel.objects.get(id=data['batch_number'])
+        except BoundBatchModel.DoesNotExist:
+            # 处理批次不存在的情况(如记录日志或抛出异常)
+            return False
+
+        log_data = {            
+            'batch_id': batch_obj,  # 关键修复:传入实例对象,而不是 batch_obj.id
+            'log_type': log_type,
+            'log_date': timezone.now().strftime('%Y-%m-%d-%H:%M'),  # 直接格式化时间,无需转字符串
+            'goods_code': data['goods_code'],
+            'goods_desc': data['goods_desc'],
+            'goods_qty': data['goods_qty'],
+            'log_content': f"{log_type_name} {goods_qty}件",
+            'creater': data['creater'],
+            'openid': data['openid'],
+            'is_delete': False,
+            # 注意:create_time 和 update_time 由模型的 auto_now_add 和 auto_now 自动处理,无需手动赋值
+        }
+
+        # 创建日志记录
+        BatchLogModel.objects.create(**log_data)
+        return True 
+class BoundBatchLogViewSet(viewsets.ModelViewSet):
+    
+    """
+        retrieve:
+            Response a data list(get)
+            list:
+            Response a data list(all)
+     
+            delete:
+            Delete a data line(delete)
+    """ 
+    # authentication_classes = []  # 禁用所有认证类
+    # permission_classes = [AllowAny]  # 允许任意访问
+    pagination_class = MyPageNumberPagination
+    filter_backends = [DjangoFilterBackend, OrderingFilter, ]
+    ordering_fields = ['id', "create_time", "update_time", ]
+    filter_class = BatchlogFilter
+
+    def get_queryset(self):
+
+        return BatchLogModel.objects.filter( is_delete=False)
+        
+
+    def get_serializer_class(self):
+        if self.action in ['list', 'destroy','retrieve']:
+            return BatchLogGetSerializer
+        else:
+            return self.http_method_not_allowed(request=self.request)
+
+    def destroy(self, request, pk):
+        qs = self.get_object()
+        qs.is_delete = True
+        qs.save()
+        serializer = self.get_serializer(qs, many=False)
+        headers = self.get_success_headers(serializer.data)
+        return Response(serializer.data, status=200, headers=headers)  

+ 1 - 1
container/migrations/0001_initial.py

@@ -1,4 +1,4 @@
-# Generated by Django 4.1.2 on 2025-04-16 22:09
+# Generated by Django 4.1.2 on 2025-04-24 23:03
 
 from django.db import migrations, models
 import django.db.models.deletion

BIN
container/migrations/__pycache__/0001_initial.cpython-38.pyc


+ 3 - 3
data_base/init.ps1

@@ -1,6 +1,6 @@
 python generate_warehouse.py
-# python generate_location.py
+python generate_location.py
 python generate_location_group.py
-# python import_data.py
-# python import_product.py
+python import_data.py
+python import_product.py
 

BIN
db.sqlite3


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1348 - 0
logs/error.log


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1351 - 0
logs/server.log


+ 44 - 16
templates/src/pages/inbound/asn.vue

@@ -256,8 +256,8 @@
         </div>
       </q-card>
     </q-dialog>
-    <q-dialog v-model="newBatchForm">
-      <q-card class="shadow-24">
+    <q-dialog v-model="newBatchForm" >
+      <q-card class="shadow-24" >
         <q-bar class="bg-light-blue-10 text-white rounded-borders" style="height: 50px">
           <div>{{ '新建批次' }}</div>
           <q-space />
@@ -265,13 +265,9 @@
             <q-tooltip content-class="bg-amber text-black shadow-4">{{ $t('index.close') }}</q-tooltip>
           </q-btn>
         </q-bar>
-        <q-card-section style="max-height: 325px; width: 400px" class="scroll">
-          <div class="text-h6 q-mb-md">{{ "批次信息" }}
-
-            
-        
-          </div>
-          <div class="row q-gutter-x-md">
+        <q-card-section style="min-height: 325px; width: 500px" class="scroll">
+          <div class="text-h6 q-mb-md">{{ "批次信息" }}</div>
+          <div class="row q-gutter-x-md" >
               <div class="col column q-gutter-y-md">
                 <q-select dense outlined square v-model="newBatchFormData.goods_code"
                   :label="'物料编码'"  
@@ -301,12 +297,30 @@
          
           <q-input dense outlined square v-model="newBatchFormData.goods_desc" :label="'名称'" 
             :rules="[val => (val && val.length > 0) || error1]" />
-          <q-input dense outlined square v-model="newBatchFormData.goods_std" :label="'规格/备注'" 
-            :rules="[val => (val && val.length > 0) || error1]" />
-          <q-input dense outlined square v-model.number="newBatchFormData.goods_weight" :label="'单重'" type="number"
+       
+            <div class="row q-gutter-x-md" >
+              <div class="col column q-gutter-y-md">
+                <q-input dense outlined square v-model.number="newBatchFormData.goods_weight" :label="'单重'" type="number"
+                  :rules="[val => (val && val > 0) || error1]" />
+                <q-input dense outlined square v-model="newBatchFormData.goods_std" :label="'规格/备注'" 
+                  :rules="[val => (val && val.length > 0) || error1]" />
+              </div>
+              <div class="col column q-gutter-y-md">
+                <q-input dense outlined square v-model="newBatchFormData.goods_unit" :label="'单位'" 
+                :rules="[val => (val && val.length > 0) || error1]" />
+                <q-toggle
+                  v-model="isorder"
+                  :label="isorder ? '自动编码' : '手动编码(建议)'"
+        
+    
+                />
+              </div>
+            </div>
+          <q-input v-show="!isorder"  dense outlined square v-model.number="newBatchFormData.bound_batch_order" :label="'批号——年月第几批(20250409)'" type="number"
             :rules="[val => (val && val > 0) || error1]" />
           <q-input dense outlined square v-model.number="newBatchFormData.goods_qty" :label="'数量'" type="number"
             :rules="[val => (val && val > 0) || error1]" />
+          
           <q-input dense outlined square v-model=" newBatchFormData.creater" :label="'经办人'"
             :rules="[val => (val && val.length > 0) || error1]" />
 
@@ -424,10 +438,13 @@
 import { getauth, postauth, putauth, deleteauth } from 'boot/axios_request'
 
 import { date, exportFile, LocalStorage } from 'quasar'
-
+import { QToggle } from 'quasar'
 
 
 export default {
+  components: {
+    QToggle
+  },
   name: 'Pageasnlist',
   data() {
     return {
@@ -518,8 +535,9 @@ export default {
       onlyread: false,
       bound_batch_list: [],
 
-      activeTab: 'tab1'
-
+      activeTab: 'tab1',
+      isorder: false,
+      order :'false'
     }
 
   },
@@ -529,6 +547,7 @@ export default {
     }
   },
   methods: {
+  
     getList(params = {}) {
       var _this = this
       _this.loading = true
@@ -760,7 +779,8 @@ export default {
       _this.newBatchFormData.openid = _this.openid
       _this.newBatchFormData.warehouse_code = _this.warehouse_code
       _this.newBatchFormData.warehouse_name = _this.warehouse_name
-
+      _this.newBatchFormData.order = _this.order
+      console.log('当前的order是',_this.newBatchFormData.order)
       postauth('bound/batch/', _this.newBatchFormData)
         .then(res => {
           if (res.status_code != 500) {
@@ -1133,6 +1153,14 @@ export default {
   destroyed() { },
 
   watch: {
+    isorder: function(val) {
+      console.log(val)
+      if (val) {
+        this.order = 'true'
+      } else {
+        this.order = 'false'
+        }},
+
     createDate1(val) {
       if (val) {
         if (val.to) {

+ 180 - 41
templates/src/pages/outbound/dn.vue

@@ -158,7 +158,7 @@
                 </q-btn>
                 <q-btn round flat push color="dark" icon="trolley" @click="change_status(props.row)">
                   <q-tooltip content-class="bg-amber text-black shadow-4" :offset="[10, 10]"
-                    content-style="font-size: 12px">一键分拣</q-tooltip>
+                    content-style="font-size: 12px">确认出库</q-tooltip>
                 </q-btn>
                 <q-btn round flat push color="dark" icon="delete" @click="deleteData(props.row.id)">
                   <q-tooltip content-class="bg-amber text-black shadow-4" :offset="[10, 10]"
@@ -248,7 +248,7 @@
             <q-tooltip>{{ $t('index.close') }}</q-tooltip>
           </q-btn>
         </q-bar>
-        <q-card-section style="max-height: 325px; width: 400px" class="scroll">{{ $t('deletetip') }}</q-card-section>
+        <q-card-section style="min-height: 325px; width: 550px" class="scroll">{{ $t('deletetip') }}</q-card-section>
         <div style="float: right; padding: 15px 15px 15px 0">
           <q-btn color="white" text-color="black" style="margin-right: 25px" @click="deleteDataCancel()">{{ $t('cancel')
           }}</q-btn>
@@ -259,30 +259,36 @@
     <q-dialog v-model="newBatchForm">
       <q-card class="shadow-24">
         <q-bar class="bg-light-blue-10 text-white rounded-borders" style="height: 50px">
-          <div>{{ '新建批次' }}</div>
+          <div>{{ '新建出库批次' }}</div>
           <q-space />
           <q-btn dense flat icon="close" v-close-popup>
             <q-tooltip content-class="bg-amber text-black shadow-4">{{ $t('index.close') }}</q-tooltip>
           </q-btn>
         </q-bar>
-        <q-card-section style="max-height: 325px; width: 400px" class="scroll">
-          <div class="text-h6 q-mb-md">{{ "批次信息" }}
-
-            
-        
-          </div>
+        <q-card-section style="min-height: 325px; width: 550px" class="scroll">
+          <div class="text-h6 q-mb-md">{{ "目标批次信息" }}
+            <q-select dense outlined square v-model="newBatchFormData.out_type"
+                  :label="'物料'"  
+                    :options="out_type_list" option-label="label" option-value="value" emit-value map-options  
+                    transition-show="scale"
+                    transition-hide="scale"
+                    :rules="[val => (val && val.length > 0) || error1]" />
+       
           <div class="row q-gutter-x-md">
               <div class="col column q-gutter-y-md">
-                <q-select dense outlined square v-model="newBatchFormData.goods_code"
+                <q-select dense outlined square v-model="target_batch"
                   :label="'物料编码'"  
                     :options="product_list" option-label="value" option-value="value" emit-value map-options
                     transition-show="scale"
                     transition-hide="scale"
-                    :rules="[val => (val && val.length > 0) || error1]" />
-
+                    :rules="[val => (val && val.length > 0) || error1]" 
+                     />
+                  
               </div>
+        
               <div class="col column q-gutter-y-md">
-                <q-input outlined  dense  color="primary" v-model="product_filter" :placeholder="'搜索名称'" autofocus
+
+                <q-input outlined  dense  color="primary" v-model="product_filter" :placeholder="'搜索批次号'" autofocus
                     @input="getProductSearchList()" @keyup.enter="getProductSearchList()">
                   <template v-slot:append>
                     <q-icon name="search" />
@@ -290,22 +296,44 @@
                 </q-input>
               </div>
           </div>
+
           <q-select dense outlined square v-model="newBatchFormData.goods_code"
                   :label="'物料'"  
                     :options="product_list" option-label="label" option-value="value" emit-value map-options  :readonly=true
                     transition-show="scale"
                     transition-hide="scale"
                     :rules="[val => (val && val.length > 0) || error1]" />
-
-
-         
+          <div class="q-mb-md">{{ "已有批次信息" }}
+            <div style="float: right; padding: 15px 15px 15px 0">
+            <q-btn color="primary" @click="get_refresh_data()">{{ '刷新' }}</q-btn>
+        </div>
+          </div>
+          <q-card class="q-mb-md" bordered>
+            <q-card-section class="q-pt-md ">
+              <div class="row q-gutter-x-md">
+                <div class="col column q-gutter-y-md">
+                  <q-input dense outlined square v-model.number="newBatchFormData.goods_weight" :label="'单重'" type="number"
+                  :rules="[val => (val && val > 0) || error1]" :readonly=true />
+                <q-input dense outlined square v-model.number="newBatchFormData.goods_qty" 
+                :label="'当前数量'" type="number" 
+                :readonly=true
+                :rules="[val => (val && val > 0) || error1]" />
+              </div>
+              <div class="col column q-gutter-y-md">
+                <q-input dense outlined square v-model="newBatchFormData.goods_unit" :label="'单位'" 
+                :rules="[val => (val && val.length > 0) || error1]" :readonly=true />
+                <q-input dense outlined square v-model="newBatchFormData.goods_std" :label="'规格/备注'" 
+                 :rules="[val => (val && val.length > 0) || error1]" :readonly=true />
+              </div>
+            </div>
+            </q-card-section>
+          </q-card>
+        </div>
           <q-input dense outlined square v-model="newBatchFormData.goods_desc" :label="'名称'" 
             :rules="[val => (val && val.length > 0) || error1]" />
-          <q-input dense outlined square v-model="newBatchFormData.goods_std" :label="'规格/备注'" 
-            :rules="[val => (val && val.length > 0) || error1]" />
-          <q-input dense outlined square v-model.number="newBatchFormData.goods_weight" :label="'单重'" type="number"
-            :rules="[val => (val && val > 0) || error1]" />
-          <q-input dense outlined square v-model.number="newBatchFormData.goods_qty" :label="'数量'" type="number"
+          
+          
+          <q-input dense outlined square v-model.number="newBatchFormData.goods_out_qty" :label="'出库数量'" type="number"
             :rules="[val => (val && val > 0) || error1]" />
           <q-input dense outlined square v-model=" newBatchFormData.creater" :label="'经办人'"
             :rules="[val => (val && val.length > 0) || error1]" />
@@ -373,7 +401,7 @@
                               >             
                                   <div class="col"    style="min-width: 150px">
                                     <q-input 
-                                      v-model="item.bound_batch.bound_number" 
+                                      v-model="item.bound_batch.out_number" 
                                       :label="'批次'" 
                                       :readonly="onlyread" 
                                       dense outlined 
@@ -398,8 +426,8 @@
                                   </div>
                                   <div class="col">
                                     <q-input 
-                                      v-model="item.bound_batch.goods_qty" 
-                                      :label="'数量'"
+                                      v-model="item.bound_batch.goods_out_qty" 
+                                      :label="'出库数量'"
                                       :readonly="onlyread" 
                                       dense outlined 
                                     />
@@ -428,7 +456,7 @@ import { date, exportFile, LocalStorage } from 'quasar'
 
 
 export default {
-  name: 'Pageasnlist',
+  name: 'Pagednlist',
   data() {
     return {
       createDate1: '',
@@ -473,6 +501,10 @@ export default {
       bound_status_map:[],
       product_list:[],
       product_map:[],
+      out_type_list:[
+        { label: '销售出库', value: '0' },
+        { label: '其他出库', value: '4' }
+      ],
 
       columns: [
         { name :'detail',label:'详情', field: 'detail', align: 'center'},
@@ -497,7 +529,23 @@ export default {
       newFormData: {
 
       },
-      newBatchFormData: {},
+      newBatchFormData: {
+
+        goods_code: '',
+        goods_desc: '',
+        goods_weight: 0,
+        goods_qty: 0,
+        goods_unit: '',
+        goods_out_qty: 0,
+        creater: '',
+        out_number: '',
+        out_type : '0',
+        
+        goods_std: '',
+        goods_batch: '',
+  
+
+      },
       newDetailFormData:{},
       editid: 0,
       editFormData: {
@@ -518,7 +566,8 @@ export default {
       onlyread: false,
       bound_batch_list: [],
 
-      activeTab: 'tab1'
+      activeTab: 'tab1',
+      target_batch: '',
 
     }
 
@@ -586,12 +635,39 @@ export default {
       this.getSearchList(this.current)
     },
 
+    get_refresh_data() {
+      getauth('bound/batch/?bound_number=' + this.target_batch)
+        .then(res => {
+          console.log('当前长度',res.results.length)
+          console.log('当前值',res.results[0])
+            if (res.results.length > 0) {
+
+              this.newBatchFormData.goods_qty = res.results[0].goods_qty
+              console.log('当前数目', this.newBatchFormData.goods_qty)
+              this.newBatchFormData.goods_weight = res.results[0].goods_weight
+              this.newBatchFormData.goods_std = res.results[0].goods_std
+              this.newBatchFormData.goods_unit = res.results[0].goods_unit
+
+            } else {
+              this.newBatchFormData.goods_qty = ''
+              this.newBatchFormData.goods_weight = ''
+              this.newBatchFormData.goods_std = ''
+              this.newBatchFormData.goods_unit = ''
+            }
+         })
+        .catch(err => {
+            this.$q.notify({
+              message: err.detail,
+              icon: 'close',
+              color: 'negative'
+            })
+          })},
     getProductSearchList()
     {
       var _this = this
       _this.loading = true
       const params = {
-        product_name__icontains: _this.product_filter,
+        bound_number__icontains: _this.product_filter,
         max_page:1000
       }
       const queryParams = new URLSearchParams({
@@ -604,15 +680,15 @@ export default {
           queryParams.delete(key)
         }
       })
-      console.log(`warehouse/product/?${queryParams}`)
-      getauth(`warehouse/product/?${queryParams}`)
+    
+      getauth(`bound/batch/?${queryParams}`)
         .then(res => {
           _this.product_list = res.results.map(item => ({
-          label: item.product_name,
-          value: item.product_code
+          label: item.goods_desc,
+          value: item.bound_number
         }))
         _this.product_map = res.results.reduce((acc, item) => {
-          acc[item.product_code] = item.product_name;
+          acc[item.bound_number] = item.goods_desc;
           return acc;
         }, {});
         })
@@ -762,14 +838,14 @@ export default {
       _this.newBatchFormData.warehouse_code = _this.warehouse_code
       _this.newBatchFormData.warehouse_name = _this.warehouse_name
 
-      postauth('bound/batch/', _this.newBatchFormData)
+      postauth('bound/outbatch/', _this.newBatchFormData)
         .then(res => {
           if (res.status_code != 500) {
             _this.newDetailFormData.bound_batch = res.id
             _this.newDetailFormData.creater =   _this.login_name
         
 
-            postauth('bound/detail/', _this.newDetailFormData)
+            postauth('bound/outdetail/', _this.newDetailFormData)
             .then(
                 res => {
                   if (res.status_code != 500) {
@@ -800,6 +876,33 @@ export default {
             color: 'negative'
           })
         })
+
+        getauth('bound/batch/?bound_number=' + this.target_batch)
+        .then(res => {
+          console.log('当前长度',res.results.length)
+          console.log('当前值',res.results[0])
+            if (res.results.length > 0) {
+
+              this.newBatchFormData.goods_qty = res.results[0].goods_qty
+              console.log('当前数目', this.newBatchFormData.goods_qty)
+              this.newBatchFormData.goods_weight = res.results[0].goods_weight
+              this.newBatchFormData.goods_std = res.results[0].goods_std
+              this.newBatchFormData.goods_unit = res.results[0].goods_unit
+
+            } else {
+              this.newBatchFormData.goods_qty = ''
+              this.newBatchFormData.goods_weight = ''
+              this.newBatchFormData.goods_std = ''
+              this.newBatchFormData.goods_unit = ''
+            }
+         })
+        .catch(err => {
+            this.$q.notify({
+              message: err.detail,
+              icon: 'close',
+              color: 'negative'
+            })
+          })
     },
     newDataCancel() {
       var _this = this
@@ -851,8 +954,8 @@ export default {
  
         bound_department: e.bound_department,
         creater: _this.login_name,
-        bound_type :'in',
-        bound_status :'101'
+        bound_type :'out',
+        bound_status :'201'
       }
 
       putauth(_this.pathname + e.id + '/', status_FormData)
@@ -861,7 +964,7 @@ export default {
           _this.getSearchList()
           if (res.status_code != 500) {
             _this.$q.notify({
-              message: '开始库',
+              message: '开始库',
               icon: 'check',
               color: 'green'
             })
@@ -937,7 +1040,7 @@ export default {
           })
       console.log("detail查询的结果是:",_this.table_detail)
 
-      getauth('bound/detail/?bound_list=' + _this.detailid)
+      getauth('bound/outdetail/?bound_list=' + _this.detailid)
       .then(res =>{
         _this.batch_detail = res.results
       })          
@@ -948,8 +1051,7 @@ export default {
               color: 'negative'
             })
           })
-      console.log("batch查询的结果是:",_this.batch_detail)
-      console.log("batch长度查询的结果是:",_this.batch_detail.length)
+
       
     },
     deleteDataSubmit() {
@@ -1134,6 +1236,43 @@ export default {
   destroyed() { },
 
   watch: {
+    target_batch (val) {
+      if (val) {
+        this.newBatchFormData.goods_code = val.split('-')[0]
+        this.newBatchFormData.out_number =val
+        this.newBatchFormData.goods_desc = this.product_map[val]
+      } else {
+        this.newBatchFormData.goods_code = ''
+        this.newBatchFormData.out_number = ''
+        this.newBatchFormData.goods_desc = ''
+      }
+      getauth('bound/batch/?bound_number=' + val)
+        .then(res => {
+          console.log('当前长度',res.results.length)
+          console.log('当前值',res.results[0])
+            if (res.results.length > 0) {
+
+              this.newBatchFormData.goods_qty = res.results[0].goods_qty
+              console.log('当前数目', this.newBatchFormData.goods_qty)
+              this.newBatchFormData.goods_weight = res.results[0].goods_weight
+              this.newBatchFormData.goods_std = res.results[0].goods_std
+              this.newBatchFormData.goods_unit = res.results[0].goods_unit
+
+            } else {
+              this.newBatchFormData.goods_qty = ''
+              this.newBatchFormData.goods_weight = ''
+              this.newBatchFormData.goods_std = ''
+              this.newBatchFormData.goods_unit = ''
+            }
+         })
+        .catch(err => {
+            this.$q.notify({
+              message: err.detail,
+              icon: 'close',
+              color: 'negative'
+            })
+          })
+    },
     createDate1(val) {
       if (val) {
         if (val.to) {