Browse Source

就近库位分配

flower_mr 3 months ago
parent
commit
1b726ae110
38 changed files with 774 additions and 341 deletions
  1. BIN
      bin/__pycache__/filter.cpython-38.pyc
  2. BIN
      bin/__pycache__/models.cpython-38.pyc
  3. BIN
      bin/__pycache__/serializers.cpython-38.pyc
  4. BIN
      bin/__pycache__/views.cpython-38.pyc
  5. 3 3
      bin/filter.py
  6. 62 57
      bin/migrations/0001_initial.py
  7. 93 0
      bin/migrations/0002_initial.py
  8. 0 43
      bin/migrations/0002_remove_locationchangelog_operator_and_more.py
  9. 33 0
      bin/migrations/0003_locationgroupmodel_access_priority_and_more.py
  10. 0 28
      bin/migrations/0003_locationmodel_access_priority_and_more.py
  11. 0 18
      bin/migrations/0004_alter_locationmodel_location_type.py
  12. 19 0
      bin/migrations/0004_locationgroupmodel_layer.py
  13. 0 17
      bin/migrations/0005_alter_devicemodel_unique_together.py
  14. 18 0
      bin/migrations/0005_alter_locationgroupmodel_status.py
  15. 0 18
      bin/migrations/0006_locationmodel_c_number.py
  16. 0 46
      bin/migrations/0007_locationmodel_location_group_and_more.py
  17. 0 17
      bin/migrations/0008_remove_locationgroupmodel_create_time.py
  18. 0 28
      bin/migrations/0009_locationgroupmodel_current_batch_and_more.py
  19. BIN
      bin/migrations/__pycache__/0001_initial.cpython-38.pyc
  20. BIN
      bin/migrations/__pycache__/0002_initial.cpython-38.pyc
  21. BIN
      bin/migrations/__pycache__/0003_locationgroupmodel_access_priority_and_more.cpython-38.pyc
  22. BIN
      bin/migrations/__pycache__/0004_locationgroupmodel_layer.cpython-38.pyc
  23. BIN
      bin/migrations/__pycache__/0005_alter_locationgroupmodel_status.cpython-38.pyc
  24. 54 7
      bin/models.py
  25. 1 1
      bin/serializers.py
  26. 309 35
      bin/views.py
  27. BIN
      bound/__pycache__/models.cpython-38.pyc
  28. 18 0
      bound/migrations/0002_alter_boundbatchmodel_status.py
  29. BIN
      bound/migrations/__pycache__/0002_alter_boundbatchmodel_status.cpython-38.pyc
  30. 6 3
      bound/models.py
  31. BIN
      container/__pycache__/views.cpython-38.pyc
  32. 2 1
      container/migrations/0001_initial.py
  33. 0 19
      container/migrations/0002_containerwcsmodel_tasknumber.py
  34. BIN
      container/migrations/__pycache__/0001_initial.cpython-38.pyc
  35. 92 0
      data_base/generate_location group copy.py
  36. BIN
      db.sqlite3
  37. 31 0
      logs/error.log
  38. 33 0
      logs/server.log

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


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


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


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


+ 3 - 3
bin/filter.py

@@ -8,7 +8,7 @@ class DeviceFilter(FilterSet):
             "location": ['exact'],
             "device_id": ['icontains'],
             "device_name": ['icontains'],
-            "device_type": ['icontains'],
+            "device_type": ['icontains','exact'],
             "ip_address": ['icontains'],
             "port": ['exact'],
             "status": ['icontains'],
@@ -21,7 +21,7 @@ class LocationGroupFilter(FilterSet):
         fields = {
             "warehouse_code": ['icontains'],
             "group_name": ['icontains'],
-            "group_type": ['icontains'],
+            "group_type": ['exact','icontains'],
             "group_code": ['icontains'],
             "status": ['icontains','exact'],
        
@@ -42,7 +42,7 @@ class LocationFilter(FilterSet):
             "update_time": ['exact', 'range'],
             "empty_label": ['exact'],
             "location_code": ['icontains'],
-            "location_type": ['icontains'],
+            "location_type": ['icontains','exact'],
             "status": ['icontains','exact'],
             "max_capacity": ['exact', 'range'],
             "current_quantity": ['exact', 'range'],

+ 62 - 57
bin/migrations/0001_initial.py

@@ -1,7 +1,6 @@
-# Generated by Django 4.1.2 on 2025-04-15 19:55
+# 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):
@@ -9,10 +8,43 @@ class Migration(migrations.Migration):
     initial = True
 
     dependencies = [
-        ('container', '0002_containerwcsmodel_tasknumber'),
     ]
 
     operations = [
+        migrations.CreateModel(
+            name='DeviceModel',
+            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')),
+            ],
+            options={
+                'verbose_name': 'Device',
+                'verbose_name_plural': 'Device',
+                'db_table': 'device',
+                'ordering': ['-id'],
+            },
+        ),
+        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='操作时间')),
+            ],
+            options={
+                'verbose_name': 'Location Change Log',
+                'verbose_name_plural': 'Location Change Log',
+                'db_table': 'location_change_log',
+                'ordering': ['-id'],
+            },
+        ),
         migrations.CreateModel(
             name='LocationContainerLink',
             fields=[
@@ -20,7 +52,6 @@ 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',
@@ -29,6 +60,28 @@ class Migration(migrations.Migration):
                 'ordering': ['-id'],
             },
         ),
+        migrations.CreateModel(
+            name='LocationGroupModel',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('warehouse_code', models.CharField(max_length=50, verbose_name='仓库编码')),
+                ('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='库位状态')),
+                ('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='当前货物编码')),
+            ],
+            options={
+                'verbose_name': 'Location Group',
+                'verbose_name_plural': 'Location Group',
+                'db_table': 'location_group',
+                'ordering': ['-id'],
+            },
+        ),
         migrations.CreateModel(
             name='LocationModel',
             fields=[
@@ -42,69 +95,21 @@ class Migration(migrations.Migration):
                 ('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_type', models.CharField(choices=[('T5', '5货位'), ('T4', '4货位'), ('T2', '2货位'), ('S1', '散货位'), ('M', '通道区'), ('E', '提升机'), ('C', '输送机')], max_length=3, 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='三维坐标')),
-                ('current_containers', models.ManyToManyField(through='bin.LocationContainerLink', to='container.containerlistmodel', verbose_name='当前存放托盘')),
+                ('access_priority', models.IntegerField(default=0, help_text='值越大表示越远离主通道,应优先使用', verbose_name='访问优先级')),
+                ('is_active', models.BooleanField(default=True, 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'),
-        ),
-        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='操作时间')),
-                ('operator', models.CharField(max_length=50, verbose_name='操作人')),
-                ('wcs_task_id', models.CharField(max_length=50, null=True, verbose_name='WCS任务ID')),
-                ('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='关联库位')),
-            ],
-            options={
-                'verbose_name': 'Location Change Log',
-                'verbose_name_plural': 'Location Change Log',
-                'db_table': 'location_change_log',
-                'ordering': ['-id'],
-            },
-        ),
-        migrations.AlterUniqueTogether(
-            name='locationcontainerlink',
-            unique_together={('location', 'container')},
-        ),
-        migrations.CreateModel(
-            name='DeviceModel',
-            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')),
-                ('location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bin.locationmodel')),
-            ],
-            options={
-                'verbose_name': 'Device',
-                'verbose_name_plural': 'Device',
-                'db_table': 'device',
-                'ordering': ['-id'],
-                'unique_together': {('device_id',)},
             },
         ),
     ]

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

@@ -0,0 +1,93 @@
+# 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 - 43
bin/migrations/0002_remove_locationchangelog_operator_and_more.py

@@ -1,43 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-15 20:07
-
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('container', '0002_containerwcsmodel_tasknumber'),
-        ('bin', '0001_initial'),
-    ]
-
-    operations = [
-        migrations.RemoveField(
-            model_name='locationchangelog',
-            name='operator',
-        ),
-        migrations.RemoveField(
-            model_name='locationchangelog',
-            name='wcs_task_id',
-        ),
-        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='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'),
-        ),
-    ]

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

@@ -0,0 +1,33 @@
+# 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 - 28
bin/migrations/0003_locationmodel_access_priority_and_more.py

@@ -1,28 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-15 21:10
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bin', '0002_remove_locationchangelog_operator_and_more'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='locationmodel',
-            name='access_priority',
-            field=models.IntegerField(default=0, help_text='值越大表示越远离主通道,应优先使用', verbose_name='访问优先级'),
-        ),
-        migrations.AddField(
-            model_name='locationmodel',
-            name='is_active',
-            field=models.BooleanField(default=True, verbose_name='是否有效'),
-        ),
-        migrations.AlterField(
-            model_name='locationmodel',
-            name='location_type',
-            field=models.CharField(choices=[('T5', '5货位'), ('T4', '4货位'), ('T2', '2货位'), ('T1', '散货位'), ('M1', '通道区'), ('E1', '提升机'), ('C1', '输送机')], max_length=3, verbose_name='货位类型'),
-        ),
-    ]

+ 0 - 18
bin/migrations/0004_alter_locationmodel_location_type.py

@@ -1,18 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-15 22:07
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bin', '0003_locationmodel_access_priority_and_more'),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name='locationmodel',
-            name='location_type',
-            field=models.CharField(choices=[('T5', '5货位'), ('T4', '4货位'), ('S4', '4单货位'), ('T2', '2货位'), ('T1', '散货位'), ('M1', '通道区'), ('E1', '提升机'), ('C1', '输送机')], max_length=3, verbose_name='货位类型'),
-        ),
-    ]

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

@@ -0,0 +1,19 @@
+# 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 - 17
bin/migrations/0005_alter_devicemodel_unique_together.py

@@ -1,17 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-15 22:34
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bin', '0004_alter_locationmodel_location_type'),
-    ]
-
-    operations = [
-        migrations.AlterUniqueTogether(
-            name='devicemodel',
-            unique_together={('location', 'device_id')},
-        ),
-    ]

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

@@ -0,0 +1,18 @@
+# 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 - 18
bin/migrations/0006_locationmodel_c_number.py

@@ -1,18 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-15 22:51
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bin', '0005_alter_devicemodel_unique_together'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='locationmodel',
-            name='c_number',
-            field=models.IntegerField(default=1, verbose_name='库位远近排序'),
-        ),
-    ]

+ 0 - 46
bin/migrations/0007_locationmodel_location_group_and_more.py

@@ -1,46 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-16 14:03
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bin', '0006_locationmodel_c_number'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='locationmodel',
-            name='location_group',
-            field=models.CharField(default=0, max_length=20, verbose_name='库位组'),
-            preserve_default=False,
-        ),
-        migrations.AlterField(
-            model_name='locationmodel',
-            name='location_type',
-            field=models.CharField(choices=[('T5', '5货位'), ('T4', '4货位'), ('S4', '4单货位'), ('T2', '2货位'), ('T1', '散货位'), ('M1', '通道区'), ('E1', '提升机'), ('C1', '输送机'), ('B1', '充电桩')], max_length=3, verbose_name='货位类型'),
-        ),
-        migrations.CreateModel(
-            name='LocationGroupModel',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('warehouse_code', models.CharField(max_length=50, verbose_name='仓库编码')),
-                ('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='库位状态')),
-                ('max_capacity', models.PositiveIntegerField(verbose_name='最大容量')),
-                ('current_quantity', models.PositiveIntegerField(default=0, verbose_name='当前托盘数')),
-                ('create_time', models.DateTimeField(auto_now_add=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')},
-            },
-        ),
-    ]

+ 0 - 17
bin/migrations/0008_remove_locationgroupmodel_create_time.py

@@ -1,17 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-16 14:29
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bin', '0007_locationmodel_location_group_and_more'),
-    ]
-
-    operations = [
-        migrations.RemoveField(
-            model_name='locationgroupmodel',
-            name='create_time',
-        ),
-    ]

+ 0 - 28
bin/migrations/0009_locationgroupmodel_current_batch_and_more.py

@@ -1,28 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-16 15:04
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('bin', '0008_remove_locationgroupmodel_create_time'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='locationgroupmodel',
-            name='current_batch',
-            field=models.CharField(default='', max_length=50, verbose_name='当前批次'),
-        ),
-        migrations.AddField(
-            model_name='locationgroupmodel',
-            name='current_goods_code',
-            field=models.CharField(default='', max_length=50, verbose_name='当前货物编码'),
-        ),
-        migrations.AddField(
-            model_name='locationgroupmodel',
-            name='current_goods_quantity',
-            field=models.PositiveIntegerField(default=0, verbose_name='当前货物数'),
-        ),
-    ]

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


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


BIN
bin/migrations/__pycache__/0003_locationgroupmodel_access_priority_and_more.cpython-38.pyc


BIN
bin/migrations/__pycache__/0004_locationgroupmodel_layer.cpython-38.pyc


BIN
bin/migrations/__pycache__/0005_alter_locationgroupmodel_status.cpython-38.pyc


+ 54 - 7
bin/models.py

@@ -519,6 +519,7 @@ class LocationGroupModel(models.Model):
     LOCATION_STATUS = (
         ('available', '可用'),
         ('occupied', '占用'),
+        ('full', '满'),
         ('disabled', '禁用'),
         ('reserved', '预留'),
         ('maintenance', '维护中'),
@@ -527,6 +528,7 @@ class LocationGroupModel(models.Model):
     group_name = models.CharField(max_length=50, verbose_name='库位组名称')
     group_type = models.CharField(max_length=50, choices=LOCATION_TYPES, verbose_name='库位组类型')
     group_code = models.CharField(max_length=50, verbose_name='库位组编码')
+    layer = models.PositiveIntegerField(verbose_name='层数')
     location_items = models.ManyToManyField(LocationModel, verbose_name='库位')
     status = models.CharField(max_length=20, choices=LOCATION_STATUS, default='available', verbose_name='库位状态')
     max_capacity = models.PositiveIntegerField(verbose_name='最大容量')  # 根据类型自动设置
@@ -534,6 +536,22 @@ class LocationGroupModel(models.Model):
     current_goods_quantity = models.PositiveIntegerField(default=0, verbose_name='当前货物数')
     current_batch = models.CharField(max_length=50, default='', verbose_name='当前批次')
     current_goods_code = models.CharField(max_length=50, default='', verbose_name='当前货物编码')
+    access_priority = models.IntegerField(
+        default=0, 
+        verbose_name='访问优先级',
+        help_text='值越大表示越远离主通道,应优先使用'
+    )
+    left_priority = models.IntegerField(
+        default=0,
+        verbose_name='左侧优先级',
+        help_text='值越大表示越靠左,应优先使用'
+    )
+    right_priority = models.IntegerField(
+        default=0,
+        verbose_name='右侧优先级',
+        help_text='值越大表示越靠右,应优先使用'
+    )
+    is_active = models.BooleanField(default=True, verbose_name='是否有效')
     # create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
     class Meta:
         db_table = 'location_group'
@@ -581,6 +599,9 @@ class LocationGroupModel(models.Model):
                     # 创建库位
                     group_code = f"{loc_type}-L{layer}C{col:03d}"
                     group_name = f"{loc_type}-L{layer}C{col:03d}"
+                    # 使用(row+col)*layer作为库位排序
+                    left_priority = (abs(row-13)+abs(col-1))*layer
+                    right_priority = (abs(row-13)+abs(col-18))*layer
         
                     if cls.objects.filter(warehouse_code=warehouse_code, group_code=group_code).exists():
                         group_item = cls.objects.get(warehouse_code=warehouse_code, group_code=group_code)
@@ -589,6 +610,7 @@ class LocationGroupModel(models.Model):
                     else:
                         group_item = cls.objects.create(
                             warehouse_code=warehouse_code,
+                            layer=layer,
                             group_name=group_name,
                             group_type=loc_type,
                             group_code=group_code,
@@ -604,7 +626,11 @@ class LocationGroupModel(models.Model):
                                 'C1': 0
                             }[loc_type],
                             current_quantity=0,
-                            status='available'
+                            status='available',
+                            access_priority=c_number,
+                            left_priority=left_priority,
+                            right_priority=right_priority,
+                            is_active=True
                         )
                         group_item.location_items.add(LocationModel.objects.get(warehouse_code=warehouse_code, row=row, col=col, layer=layer))
                         group_item.save()
@@ -643,6 +669,8 @@ class LocationGroupModel(models.Model):
                     # 创建库位
                     group_code = f"{loc_type}-L{layer}C{col:03d}"
                     group_name = f"{loc_type}-L{layer}C{col:03d}"
+                    left_priority = (abs(row-13)+abs(col-1))*layer
+                    right_priority = (abs(row-13)+abs(col-18))*layer
         
                     if cls.objects.filter(warehouse_code=warehouse_code, group_code=group_code).exists():
                         group_item = cls.objects.get(warehouse_code=warehouse_code, group_code=group_code)
@@ -651,6 +679,7 @@ class LocationGroupModel(models.Model):
                     else:
                         group_item = cls.objects.create(
                             warehouse_code=warehouse_code,
+                            layer=layer,
                             group_name=group_name,
                             group_type=loc_type,
                             group_code=group_code,
@@ -665,7 +694,11 @@ class LocationGroupModel(models.Model):
                                 'C1': 0
                             }[loc_type],
                             current_quantity=0,
-                            status='available'
+                            status='available',
+                            access_priority=c_number,
+                            left_priority=left_priority,
+                            right_priority=right_priority,
+                            is_active=True
                         )
                         group_item.location_items.add(LocationModel.objects.get(warehouse_code=warehouse_code, row=row, col=col, layer=layer))
                         group_item.save()
@@ -706,6 +739,8 @@ class LocationGroupModel(models.Model):
                     # 创建库位
                     group_code = f"{loc_type}-L{layer}C{col:03d}"
                     group_name = f"{loc_type}-L{layer}C{col:03d}"
+                    left_priority = (abs(row-13)+abs(col-1))*layer
+                    right_priority = (abs(row-13)+abs(col-18))*layer
         
                     if cls.objects.filter(warehouse_code=warehouse_code, group_code=group_code).exists():
                         group_item = cls.objects.get(warehouse_code=warehouse_code, group_code=group_code)
@@ -714,6 +749,7 @@ class LocationGroupModel(models.Model):
                     else:
                         group_item = cls.objects.create(
                             warehouse_code=warehouse_code,
+                            layer=layer,
                             group_name=group_name,
                             group_type=loc_type,
                             group_code=group_code,
@@ -728,7 +764,11 @@ class LocationGroupModel(models.Model):
                                 'C1': 0
                             }[loc_type],
                             current_quantity=0,
-                            status='available'
+                            status='available',
+                            access_priority=c_number,
+                            left_priority=left_priority,
+                            right_priority=right_priority,
+                            is_active=True
                         )
                         group_item.location_items.add(LocationModel.objects.get(warehouse_code=warehouse_code, row=row, col=col, layer=layer))
                         group_item.save()
@@ -786,6 +826,8 @@ class LocationGroupModel(models.Model):
                     # 创建库位
                     group_code = f"{loc_type}-L{layer}C{col:03d}"
                     group_name = f"{loc_type}-L{layer}C{col:03d}"
+                    left_priority = (abs(row-13)+abs(col-1))*layer
+                    right_priority = (abs(row-13)+abs(col-18))*layer
         
                     if cls.objects.filter(warehouse_code=warehouse_code, group_code=group_code).exists():
                         group_item = cls.objects.get(warehouse_code=warehouse_code, group_code=group_code)
@@ -794,6 +836,7 @@ class LocationGroupModel(models.Model):
                     else:
                         group_item = cls.objects.create(
                             warehouse_code=warehouse_code,
+                            layer=layer,
                             group_name=group_name,
                             group_type=loc_type,
                             group_code=group_code,
@@ -808,7 +851,11 @@ class LocationGroupModel(models.Model):
                                 'C1': 0
                             }[loc_type],
                             current_quantity=0,
-                            status='available'
+                            status='available',
+                            access_priority=c_number,
+                            left_priority=left_priority,
+                            right_priority=right_priority,
+                            is_active=True
                         )
                         group_item.location_items.add(LocationModel.objects.get(warehouse_code=warehouse_code, row=row, col=col, layer=layer))
                         group_item.save()
@@ -820,8 +867,8 @@ class LocationGroupModel(models.Model):
 
 # 库位-托盘关联表(记录实时存放关系)
 class LocationContainerLink(models.Model):
-    location = models.ForeignKey(LocationModel, on_delete=models.CASCADE)
-    container = models.ForeignKey(ContainerListModel, on_delete=models.CASCADE)
+    location = models.ForeignKey(LocationModel, on_delete=models.CASCADE,unique=True, verbose_name='库位')
+    container = models.ForeignKey(ContainerListModel, unique=True,on_delete=models.CASCADE)
     task_wcs = models.ForeignKey(ContainerWCSModel, on_delete=models.CASCADE, null=True, blank=True)
     task_detail = models.ForeignKey(TaskModel, on_delete=models.CASCADE, null=True, blank=True)
     put_time = models.DateTimeField(auto_now_add=True, verbose_name='上架时间')
@@ -832,7 +879,7 @@ class LocationContainerLink(models.Model):
         verbose_name = 'Location-Container Link'
         verbose_name_plural = "Location-Container Link"
         ordering = ['-id']
-        unique_together = ( 'location', 'container')  # 防止重复关联关系
+  
 
 
 class DeviceModel(models.Model):

+ 1 - 1
bin/serializers.py

@@ -17,7 +17,7 @@ class LocationPostSerializer(serializers.ModelSerializer):
     class Meta:
         model = LocationModel
         fields = '__all__'
-        read_only_fields = ['id']
+        read_only_fields = ['id','row','col','layer', 'max_capacity', 'current_quantity', 'coordinate','access_priority']
 
 class LocationGroupSerializer(serializers.ModelSerializer):
     class Meta:

+ 309 - 35
bin/views.py

@@ -11,7 +11,7 @@ from django.utils import timezone
 from django.db import transaction
 import logging
 from rest_framework import status
-from .models import DeviceModel,LocationModel,LocationGroupModel,LocationContainerLink,LocationChangeLog,ContainerDetailModel
+from .models import DeviceModel,LocationModel,LocationGroupModel,LocationContainerLink,LocationChangeLog
 from bound.models import BoundBatchModel,BoundDetailModel,BoundListModel
 
 
@@ -20,11 +20,25 @@ from .serializers import LocationListSerializer,LocationPostSerializer
 from .serializers import LocationGroupListSerializer,LocationGroupPostSerializer
 # 以后添加模块时,只需要在这里添加即可
 from rest_framework.permissions import AllowAny
-from container.models import ContainerListModel,ContainerDetailModel,ContainerOperationModel,TaskModel,
+from container.models import ContainerListModel,ContainerDetailModel,ContainerOperationModel,TaskModel
 logger = logging.getLogger(__name__)
 
 # 库位分配
+# 入库规则函数
+# 逻辑根据批次下的托盘数目来找满足区间范围的库位,按照优先级排序,
 class LocationAllocation:
+    # 入库规则函数
+    # fun:get_pallet_count_by_batch: 根据托盘码查询批次下托盘总数
+    # fun:get_location_type: 根据托盘数目获取库位类型
+    # fun:updata_location_container_link: 更新库位和托盘的关联关系
+    # fun:get_batch_status: 获取批次状态
+    # fun:get_batch: 获取批次
+    # fun:get_location_list_remainder: 获取可用库位的c_number列表
+    # fun:get_min_list_index: 获取最小的库位
+    # fun:get_location_by_type_remainder: 根据库位类型获取库位
+    # fun:get_location_by_type: 第一次入库,根据库位类型获取库位
+    # fun:get_location_by_status: 根据库位状态获取库位
+
     @transaction.atomic
     def get_pallet_count_by_batch(self, container_code):
         """
@@ -33,38 +47,260 @@ class LocationAllocation:
         :return: 所属批次下的托盘总数
         """
         # 1. 通过托盘码获取容器详情
+        container = ContainerListModel.objects.filter(
+            container_code=container_code
+        ).first()
+
+        if not container:
+            logger.error(f"托盘 {container_code} 不存在")
+            print(f"托盘 {container_code} 不存在")
+            return None
+        # 2. 获取关联的批次明细
         container_detail = ContainerDetailModel.objects.filter(
+            container=container.id,
+            status=1
+        ).first()
+        if not container_detail:
+            print (f"容器 {container_code} 未组盘")
+            logger.error(f"容器 {container_code} 未组盘")
+            return None
+        else:
+            print (f"容器 {container_code} 已组盘")
+        batch_container_count = ContainerDetailModel.objects.filter(
+             batch = container_detail.batch.id,
+             status = 1
+        ).count()
+       
+        return batch_container_count
+    
+    def get_location_type(self,container_count):
+        """
+        根据托盘数目获取库位类型
+        :param container_count: 托盘数目
+        :return: 库位类型
+        """
+        if container_count <= 1:
+            return ["T1"]
+        elif container_count <= 2:
+            return ["T2"]
+        elif container_count <= 4:
+            return ["S4","T4"]
+        else:
+            return ["T5"]
+    @transaction.atomic
+    def updata_location_container_link(self,location_code,container_code):
+        """
+        更新库位和托盘的关联关系
+        :param location_code: 库位编码
+        :param container_code: 托盘编码
+        :return:
+        """
+        try:
+            # 1. 获取库位和托盘的关联关系
+            location = LocationModel.objects.filter(
+                location_code=location_code
+            ).first()
+            container = ContainerListModel.objects.filter(
+                container_code=container_code
+            ).first()
+            # 2. 如果库位和托盘的关联关系不存在,创建新的关联关系
+            if not LocationContainerLink.objects.filter(location=location).exists():
+                location_container_link = LocationContainerLink(
+                    location=location,
+                    container=container
+                )
+                location_container_link.save()
+                print(f"更新库位和托盘的关联关系成功!")
+            # 3. 更新库位和托盘的关联关系
+            else:
+                LocationContainerLink.objects.filter(location=location).update(location=location, container=container)
+                print(f"更新库位和托盘的关联关系成功!")
+                return True
+        except Exception as e:       
+            logger.error(f"更新库位和托盘的关联关系失败:{str(e)}")
+            print(f"更新库位和托盘的关联关系失败:{str(e)}")
+            return False    
+    def get_batch_status(self,container_code):
+        """
+        获取批次状态
+        :param container_code: 托盘码
+        :return: 批次状态
+        """
+        # 1. 通过托盘码获取容器详情
+        container = ContainerListModel.objects.filter(
             container_code=container_code
-        ).select_related('bound_detail').first()
+        ).first()
 
+        if not container:
+            logger.error(f"托盘 {container_code} 不存在")
+            print(f"托盘 {container_code} 不存在")
+            return None
+        # 2. 获取关联的批次明细
+        container_detail = ContainerDetailModel.objects.filter(
+            container=container.id,
+            status=1
+        ).first()
         if not container_detail:
-            logger.error(f"托盘 {pallet_code} 不存在")
-  
+            print (f"容器 {container_code} 未组盘")
+            logger.error(f"容器 {container_code} 未组盘")
+            return None
+        else:
+            print (f"容器 {container_code} 已组盘")
+        batch_status = container_detail.batch.status
+        return batch_status
+    def get_batch(self,container_code):
+        """
+        获取批次
+        :param container_code: 托盘码
+        :return: 批次
+        """
+        # 1. 通过托盘码获取容器详情
+        container = ContainerListModel.objects.filter(
+            container_code=container_code
+        ).first()
+
+        if not container:
+            logger.error(f"托盘 {container_code} 不存在")
+            print(f"托盘 {container_code} 不存在")
+            return None
         # 2. 获取关联的批次明细
-        bound_detail = container_detail.bound_detail
-        if not bound_detail:
-            logger.error(f"容器 {container_detail.container_code} 不存在")
+        container_detail = ContainerDetailModel.objects.filter(
+            container=container.id,
+            status=1
+        ).first()
+        if not container_detail:
+            print (f"容器 {container_code} 未组盘")
+            logger.error(f"容器 {container_code} 未组盘")
+            return None
+        else:
+            print (f"容器 {container_code} 已组盘")
+        batch = container_detail.batch.bound_number
+        return batch
+    @transaction.atomic
+    def get_location_list_remainder(self, location_list):
+        """
+        获取可用库位的c_number列表
+        :param location_list: 库位对象列表
+        :return: 可用库位编号列表
+        """
+        if not location_list:
+            return None
+
+        available_c_numbers = [
+            loc.c_number for loc in location_list 
+            if loc.status == 'available'
+        ]
+        
+        return available_c_numbers if available_c_numbers else None
+    def get_min_list_index(self,list):
+        """
+        获取最小的库位
+        :param list: 库位列表
+        :return: 最小库位
+        """
+        if not list:
+            return None
+        min_index = 0
+        for i in range(len(list)):
+            if list[i] < list[min_index]:
+                min_index = i
+        return min_index
 
-        # 3. 获取父级批次
-        batch = BoundBatchModel.objects.filter(
-            batch_code=bound_detail.batch_code
-        ).prefetch_related('bound_details').first()
 
-        if not batch:
-            logger.error(f"批次 {bound_detail.batch_code} 不存在")
+    @transaction.atomic
+    def get_location_by_type_remainder(self, batch, layer):
+        """
+        根据库位类型获取库位
+        :param batch: 批次号
+        :param layer: 层数限制
+        :return: 符合条件的库位列表
+        """
+        # 获取符合条件的库位组并按优先级排序
+        location_groups = LocationGroupModel.objects.filter(
+            current_batch=batch,
+            layer=layer,
+        ).first()
 
-        # 4. 统计批次下所有托盘数量(两种方式)
-        # 方式一:直接统计关联明细数量(如果每个detail对应一个托盘)
-        total_pallets = batch.bound_details.count()
-        
-        # 方式二:累加明细中的容器数量(如果detail包含多个容器)
-        # total_pallets = sum(detail.container_count for detail in batch.bound_details.all())
+        if not location_groups:
+            return None
+        # 合并所有库位组中的库位
+        locations = []
+        locations.extend(location_groups.location_items.all())  # 假设location_items是关联字段
+
+        return locations if locations else None
+    @transaction.atomic
+    def get_location_by_type(self, location_type_list, start_location, layer):
+        """
+        第一次入库,根据库位类型获取库位
+        :param location_type_list: 库位类型列表
+        :param start_location: 起始位置(决定优先级排序方式)
+        :param layer: 层数限制
+        :return: 符合条件的库位列表
+        """
+        # 获取符合条件的库位组并按优先级排序
+        location_groups = LocationGroupModel.objects.filter(
+            group_type__in=location_type_list,
+            layer=layer,
+            status='available'
+        )
+
+        # 根据起始位置选择排序字段
+        if start_location == 'in1':
+            ordered_groups = location_groups.order_by('left_priority')
+        elif start_location == 'in2':
+            ordered_groups = location_groups.order_by('right_priority')
+        else:
+            ordered_groups = location_groups.none()
+
+        # 合并所有库位组中的库位
+        locations = []
+    
+        locations.extend(ordered_groups.first().location_items.all())  # 假设location_items是关联字段
 
-        return {
-            "batch_code": batch.batch_code,
-            "total_pallets": total_pallets,
-            "current_pallet": pallet_code
-        }
+        return locations if locations else None
+    @transaction.atomic
+    def get_location_by_status(self,container_code,start_location,layer):
+        """
+        根据库位状态获取库位
+        :param location_type: 库位类型
+        :param start_location: 起始库位 if in1 优先考虑left_priority, if in2 优先考虑right_priority 就是获取库位组列表之后进行排序
+        :param layer: 层数 限定层数
+        :return: 库位列表
+        """
+        # 1. 获取批次状态 102 为已组盘 103 为部分入库 104 为全部入库
+        status = self.get_batch_status(container_code)
+        # 
+        if status == 1:
+            # 2. 获取库位组
+            print (f"第一次入库")
+            container_number = self.get_pallet_count_by_batch(container_code)
+            print (f"该批次下托盘总数:{container_number}")
+            location_type_list = self.get_location_type(container_number)
+            print(f"库位类型:{location_type_list}")
+            location_list = self.get_location_by_type(location_type_list,start_location,layer)
+            print(f"库位列表:{location_list}")
+            location_list_remainder = self.get_location_list_remainder(location_list)
+            print(f"库位列表剩余:{location_list_remainder}")
+            if not location_list_remainder:
+                # 库位已满,返回None
+                return None
+            else:
+                location_index = self.get_min_list_index(location_list_remainder)
+                # 返回和托盘关联的库位、库位剩余、库位类型
+                return location_list[location_index]
+        elif status == 2:
+            print(f"部分入库")
+            # 2. 获取库位组
+            location_list = self.get_location_by_type_remainder(self.get_batch(container_code),layer)
+            location_list_remainder = self.get_location_list_remainder(location_list)
+            if not location_list_remainder:
+                # 库位已满,返回None
+                return None
+            else:
+                location_index = self.get_min_list_index(location_list_remainder)
+                # 返回和托盘关联的库位、库位剩余、库位类型
+                return location_list[location_index]
+         
 
 
 class locationViewSet(viewsets.ModelViewSet):
@@ -113,23 +349,61 @@ class locationViewSet(viewsets.ModelViewSet):
             return LocationListSerializer
 
     def update(self, request, *args, **kwargs):
+        qs = self.get_object()
         data = self.request.data
-        order_month = str(timezone.now().strftime('%Y%m'))
-        data['month'] = order_month
+
         location_code = data.get('location_code')
         # 处理库位对象
         location_obj = LocationModel.objects.filter(location_code=location_code).first()
-        if location_obj:
+        if not location_obj:
+            logger.info(f"库位 {location_code} 不存在")
+            return Response(
+                {'code': '400', 'message': '库位不存在', 'data': None},
+                status=status.HTTP_400_BAD_REQUEST
+            )
+        else:
             data['id'] = location_obj.id
             logger.info(f"库位 {location_code} 已存在")
-        else:
-            logger.info(f"库位 {location_code} 不存在,创建库位对象")
-            serializer_list = LocationPostSerializer(data=data)
-            serializer_list.is_valid(raise_exception=True)
-            serializer_list.save()
-            data['id'] = serializer_list.data.get('id')
-        return Response(data, status=status.HTTP_201_CREATED)
+            serializer = self.get_serializer(qs, data=data)
+            serializer.is_valid(raise_exception=True)
+            serializer.save()
+            headers = self.get_success_headers(serializer.data)
+            self.handle_group_location_status(location_code,location_obj.location_group)
+            return Response(serializer.data, status=200, headers=headers)
 
+    def handle_group_location_status(self,location_code,location_group):
+        """
+        处理库位组和库位的关联关系
+        :param location_code: 库位编码
+        :param location_group: 库位组编码
+        :return:
+        """
+        # 1. 获取库位空闲状态的库位数目
+        location_obj_number = LocationModel.objects.filter(
+            location_group=location_group,
+            status='available'
+        ).all().count()
+        # 2. 获取库位组对象
+        logger.info(f"库位组 {location_group} 下的库位数目:{location_obj_number}")
+        # 1. 获取库位和库位组的关联关系
+        location_group_obj = LocationGroupModel.objects.filter(
+            group_code=location_group
+        ).first()
+        if not location_group_obj:
+            logger.info(f"库位组 {location_group} 不存在")
+            return None
+        else:
+            if location_obj_number == 0:
+                # 库位组库位已满,更新库位组状态为full
+                location_group_obj.status = 'full'
+                location_group_obj.save()
+            elif location_obj_number < location_group_obj.max_capacity:
+                location_group_obj.status = 'occupied'
+                location_group_obj.save()
+            else:
+                location_group_obj.status = 'available'
+                location_group_obj.save()
+       
 class locationGroupViewSet(viewsets.ModelViewSet):
     """
         retrieve:

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


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

@@ -0,0 +1,18 @@
+# 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='批次状态'),
+        ),
+    ]

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


+ 6 - 3
bound/models.py

@@ -32,9 +32,12 @@ class BoundBatchModel(models.Model):
     CONTAINER_STATUS = (
         (0, '入库申请'),
         (1, '入库中'),
-        (2, '在库'),
-        (3, '出库中'),
-        (4, '已出库')
+        (2, '部分入库'),
+        (3, '在库'),
+        (4, '出库中'),
+        (5, '部分出库'),
+        (6, '已出库'),
+
     )
 
     bound_number = models.CharField(max_length=255, verbose_name="入库批次号")

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


+ 2 - 1
container/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-16 22:09
 
 from django.db import migrations, models
 import django.db.models.deletion
@@ -60,6 +60,7 @@ class Migration(migrations.Migration):
                 ('taskid', models.CharField(max_length=50, verbose_name='任务ID')),
                 ('month', models.IntegerField(verbose_name='月份')),
                 ('tasktype', models.CharField(max_length=50, verbose_name='任务类型')),
+                ('tasknumber', models.IntegerField(verbose_name='任务号')),
                 ('container', models.CharField(max_length=50, verbose_name='托盘号')),
                 ('current_location', models.CharField(max_length=50, verbose_name='当前库位')),
                 ('target_location', models.CharField(max_length=50, verbose_name='目标库位')),

+ 0 - 19
container/migrations/0002_containerwcsmodel_tasknumber.py

@@ -1,19 +0,0 @@
-# Generated by Django 4.1.2 on 2025-04-15 10:20
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('container', '0001_initial'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='containerwcsmodel',
-            name='tasknumber',
-            field=models.IntegerField(default=123456, verbose_name='任务号'),
-            preserve_default=False,
-        ),
-    ]

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


+ 92 - 0
data_base/generate_location group copy.py

@@ -0,0 +1,92 @@
+# generate_locations.py
+import os
+import django
+import sys
+
+# fun:get_pallet_count_by_batch: 根据托盘码查询批次下托盘总数
+# fun:get_location_type: 根据托盘数目获取库位类型
+# fun:updata_location_container_link: 更新库位和托盘的关联关系
+# fun:get_batch_status: 获取批次状态
+# fun:get_batch: 获取批次
+# fun:get_location_list_remainder: 获取可用库位的c_number列表
+# fun:get_min_list_index: 获取最小的库位
+# fun:get_location_by_type_remainder: 根据库位类型获取库位
+# fun:get_location_by_type: 第一次入库,根据库位类型获取库位
+# fun:get_location_by_status: 根据库位状态获取库位
+def setup_django():
+    # 使用原始字符串处理Windows路径
+    project_path = "D:/Document/code/vue/greater_wms"
+    sys.path.append(project_path)
+    
+    # 根据实际目录名设置(注意下划线)
+    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'greaterwms.settings')
+    django.setup()
+
+def main():
+    try:
+        # 从正确的应用导入模型
+        from bin.views import LocationAllocation
+        
+        container_code = "12345"
+        print(f"开始生成库位,托盘编码:{container_code}")
+       
+        
+        # 调用生成方法
+       # 修改调用部分的代码
+        allocator = LocationAllocation()  # 创建实例
+        number=allocator.get_pallet_count_by_batch(container_code)  # 通过实例调用)
+        if number is None:
+            print("❌ 该批次下无托盘,请检查托盘编码")
+            return
+        print(f"该批次下托盘总数:{number}")
+        
+        location_type = allocator.get_location_type(number)  # 获取库位类型
+        if not location_type:
+            print("❌ 库位类型获取失败,请检查托盘数量")
+            return
+        print(f"库位类型:{location_type}")
+        # 调用生成库位方法
+        
+        batch_status = allocator.get_batch_status(container_code)  # 获取批次状态
+        if not batch_status:
+            print("❌ 批次状态获取失败,请检查批次号")
+            return
+        print(f"批次状态:{batch_status}")
+
+        batch = allocator.get_batch(container_code)
+        if not batch:
+            print("❌ 批次获取失败,请检查托盘编码")
+            return
+        print(f"批次信息:{batch}")
+
+        location_list_cnumber = allocator.get_location_by_status(container_code, 'in2', 1)  # 获取库位列表
+        if not location_list_cnumber:
+            print("❌ 通用库位获取失败,请检查托盘编码")
+            return
+        print(f"库位列表:{location_list_cnumber}")
+        updata_location_container_link = allocator.updata_location_container_link(location_list_cnumber.location_code, container_code)  # 更新库位和托盘的关联关系
+        if not updata_location_container_link:
+            print("❌ 库位和托盘的关联关系更新失败,请检查托盘编码")
+            return
+        print(f"库位和托盘的关联关系更新成功!")
+        location_list = allocator.get_location_by_type(location_type, 'in2', 1)  # 获取库位列表
+        if not location_list:
+            print("❌ 第一次库位获取失败,请检查库位类型")
+            return
+        print(f"库位列表:{location_list}")
+        location_list_cnumber = allocator.get_location_by_type_remainder(batch, 1)  # 获取库位列表
+        if not location_list_cnumber:
+            print("❌ 剩余库位获取失败,请检查托盘编码")
+            return
+        print(f"库位列表:{location_list_cnumber}")
+        print("✅ 方法生成成功!")
+
+        
+    except Exception as e:
+        print(f"❌ 生成失败:{str(e)}")
+        import traceback
+        traceback.print_exc()
+
+if __name__ == "__main__":
+    setup_django()
+    main()

BIN
db.sqlite3


+ 31 - 0
logs/error.log

@@ -2393,3 +2393,34 @@ Traceback (most recent call last):
   File "d:\language\python38\lib\site-packages\rest_framework\serializers.py", line 1032, in get_fields
     assert hasattr(self.Meta, 'model'), (
 AssertionError: Class LocationGroupListSerializer missing "Meta.model" attribute
+[2025-04-17 10:15:59,738][django.request.log_response():241] [ERROR] Internal Server Error: /bin/1306/
+Traceback (most recent call last):
+  File "d:\language\python38\lib\site-packages\asgiref\sync.py", line 472, in thread_handler
+    raise exc_info[1]
+  File "d:\language\python38\lib\site-packages\django\core\handlers\exception.py", line 42, in inner
+    response = await get_response(request)
+  File "d:\language\python38\lib\site-packages\django\core\handlers\base.py", line 253, in _get_response_async
+    response = await wrapped_callback(
+  File "d:\language\python38\lib\site-packages\asgiref\sync.py", line 435, in __call__
+    ret = await asyncio.wait_for(future, timeout=None)
+  File "d:\language\python38\lib\asyncio\tasks.py", line 455, in wait_for
+    return await fut
+  File "d:\language\python38\lib\concurrent\futures\thread.py", line 57, in run
+    result = self.fn(*self.args, **self.kwargs)
+  File "d:\language\python38\lib\site-packages\asgiref\sync.py", line 476, in thread_handler
+    return func(*args, **kwargs)
+  File "d:\language\python38\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
+    return view_func(*args, **kwargs)
+  File "d:\language\python38\lib\site-packages\rest_framework\viewsets.py", line 125, in view
+    return self.dispatch(request, *args, **kwargs)
+  File "d:\language\python38\lib\site-packages\rest_framework\views.py", line 509, in dispatch
+    response = self.handle_exception(exc)
+  File "d:\language\python38\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
+    self.raise_uncaught_exception(exc)
+  File "d:\language\python38\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
+    raise exc
+  File "d:\language\python38\lib\site-packages\rest_framework\views.py", line 506, in dispatch
+    response = handler(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.\bin\views.py", line 325, in update
+    handle_group_location_status(location_code,location_obj.location_group)
+NameError: name 'handle_group_location_status' is not defined

+ 33 - 0
logs/server.log

@@ -2637,3 +2637,36 @@ AssertionError: Class LocationGroupListSerializer missing "Meta.model" attribute
 [2025-04-16 16:40:03,952][django.request.log_response():241] [WARNING] Not Found: /stock/list/
 [2025-04-16 16:40:06,813][django.request.log_response():241] [WARNING] Not Found: /cyclecount/manualcyclecount/
 [2025-04-16 16:40:27,778][django.request.log_response():241] [WARNING] Not Found: /cyclecount/qtyrecorviewset/
+[2025-04-16 22:17:23,387][django.request.log_response():241] [WARNING] Not Found: /dn/list/
+[2025-04-16 23:32:41,033][django.request.log_response():241] [WARNING] Not Found: /cyclecount/qtyrecorviewset/
+[2025-04-17 10:15:59,738][django.request.log_response():241] [ERROR] Internal Server Error: /bin/1306/
+Traceback (most recent call last):
+  File "d:\language\python38\lib\site-packages\asgiref\sync.py", line 472, in thread_handler
+    raise exc_info[1]
+  File "d:\language\python38\lib\site-packages\django\core\handlers\exception.py", line 42, in inner
+    response = await get_response(request)
+  File "d:\language\python38\lib\site-packages\django\core\handlers\base.py", line 253, in _get_response_async
+    response = await wrapped_callback(
+  File "d:\language\python38\lib\site-packages\asgiref\sync.py", line 435, in __call__
+    ret = await asyncio.wait_for(future, timeout=None)
+  File "d:\language\python38\lib\asyncio\tasks.py", line 455, in wait_for
+    return await fut
+  File "d:\language\python38\lib\concurrent\futures\thread.py", line 57, in run
+    result = self.fn(*self.args, **self.kwargs)
+  File "d:\language\python38\lib\site-packages\asgiref\sync.py", line 476, in thread_handler
+    return func(*args, **kwargs)
+  File "d:\language\python38\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
+    return view_func(*args, **kwargs)
+  File "d:\language\python38\lib\site-packages\rest_framework\viewsets.py", line 125, in view
+    return self.dispatch(request, *args, **kwargs)
+  File "d:\language\python38\lib\site-packages\rest_framework\views.py", line 509, in dispatch
+    response = self.handle_exception(exc)
+  File "d:\language\python38\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
+    self.raise_uncaught_exception(exc)
+  File "d:\language\python38\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
+    raise exc
+  File "d:\language\python38\lib\site-packages\rest_framework\views.py", line 506, in dispatch
+    response = handler(request, *args, **kwargs)
+  File "D:\Document\code\vue\greater_wms\.\bin\views.py", line 325, in update
+    handle_group_location_status(location_code,location_obj.location_group)
+NameError: name 'handle_group_location_status' is not defined