From 5a4fe875614821cf3d54f28debb5a90d1d80b82c Mon Sep 17 00:00:00 2001 From: Mojtaba-z Date: Mon, 19 Jan 2026 11:31:06 +0330 Subject: [PATCH] import & fix --> tagBatch / tagDistribution --- Dockerfile | 2 +- apps/tag/migrations/0030_tagdistribution.py | 38 +++++++++++++++++++ ...ch_identity_alter_tagbatch_organization.py | 25 ++++++++++++ .../0032_remove_tagbatch_batch_identity.py | 17 +++++++++ .../0033_tagbatch_batch_identity.py | 18 +++++++++ ...034_remove_tagdistribution_organization.py | 17 +++++++++ .../0035_tagdistribution_assigned_org.py | 20 ++++++++++ ...6_tagdistribution_assigner_org_and_more.py | 25 ++++++++++++ apps/tag/models.py | 22 ++++++++--- apps/tag/services/tag_services.py | 4 ++ apps/tag/web/api/v1/api.py | 26 ++++++++++++- apps/tag/web/api/v1/serializers.py | 34 +++++++++++++++++ 12 files changed, 241 insertions(+), 7 deletions(-) create mode 100644 apps/tag/migrations/0030_tagdistribution.py create mode 100644 apps/tag/migrations/0031_tagbatch_batch_identity_alter_tagbatch_organization.py create mode 100644 apps/tag/migrations/0032_remove_tagbatch_batch_identity.py create mode 100644 apps/tag/migrations/0033_tagbatch_batch_identity.py create mode 100644 apps/tag/migrations/0034_remove_tagdistribution_organization.py create mode 100644 apps/tag/migrations/0035_tagdistribution_assigned_org.py create mode 100644 apps/tag/migrations/0036_tagdistribution_assigner_org_and_more.py diff --git a/Dockerfile b/Dockerfile index 1b10eaa..62b8d96 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # pull official base image -FROM ghcr.io/seniorkian/python310-rasaddam:1.0.1 +FROM registry.hamdocker.ir/mamadk17/python310-rasaddam:1.0.0 # Create the app directory RUN #mkdir /app diff --git a/apps/tag/migrations/0030_tagdistribution.py b/apps/tag/migrations/0030_tagdistribution.py new file mode 100644 index 0000000..c9419b3 --- /dev/null +++ b/apps/tag/migrations/0030_tagdistribution.py @@ -0,0 +1,38 @@ +# Generated by Django 5.0 on 2026-01-18 10:44 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0060_organization_ownership_code'), + ('tag', '0029_alter_tag_tag_code_tagbatch'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='TagDistribution', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_date', models.DateTimeField(auto_now_add=True)), + ('modify_date', models.DateTimeField(auto_now=True)), + ('creator_info', models.CharField(max_length=100, null=True)), + ('modifier_info', models.CharField(max_length=100, null=True)), + ('trash', models.BooleanField(default=False)), + ('species_code', models.IntegerField(default=0)), + ('distributed_number', models.IntegerField(default=0)), + ('batch', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tag_distributions', to='tag.tagbatch')), + ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_createddby', to=settings.AUTH_USER_MODEL)), + ('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_modifiedby', to=settings.AUTH_USER_MODEL)), + ('organization', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tag_distributions', to='authentication.organization')), + ('tag', models.ManyToManyField(related_name='distributions', to='tag.tag')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/tag/migrations/0031_tagbatch_batch_identity_alter_tagbatch_organization.py b/apps/tag/migrations/0031_tagbatch_batch_identity_alter_tagbatch_organization.py new file mode 100644 index 0000000..39ab418 --- /dev/null +++ b/apps/tag/migrations/0031_tagbatch_batch_identity_alter_tagbatch_organization.py @@ -0,0 +1,25 @@ +# Generated by Django 5.0 on 2026-01-19 06:19 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0060_organization_ownership_code'), + ('tag', '0030_tagdistribution'), + ] + + operations = [ + migrations.AddField( + model_name='tagbatch', + name='batch_identity', + field=models.PositiveBigIntegerField(default=0), + ), + migrations.AlterField( + model_name='tagbatch', + name='organization', + field=models.ForeignKey(help_text='creator org of tag batch', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tag_batches', to='authentication.organization'), + ), + ] diff --git a/apps/tag/migrations/0032_remove_tagbatch_batch_identity.py b/apps/tag/migrations/0032_remove_tagbatch_batch_identity.py new file mode 100644 index 0000000..b8662e1 --- /dev/null +++ b/apps/tag/migrations/0032_remove_tagbatch_batch_identity.py @@ -0,0 +1,17 @@ +# Generated by Django 5.0 on 2026-01-19 06:25 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('tag', '0031_tagbatch_batch_identity_alter_tagbatch_organization'), + ] + + operations = [ + migrations.RemoveField( + model_name='tagbatch', + name='batch_identity', + ), + ] diff --git a/apps/tag/migrations/0033_tagbatch_batch_identity.py b/apps/tag/migrations/0033_tagbatch_batch_identity.py new file mode 100644 index 0000000..57fbaab --- /dev/null +++ b/apps/tag/migrations/0033_tagbatch_batch_identity.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0 on 2026-01-19 06:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tag', '0032_remove_tagbatch_batch_identity'), + ] + + operations = [ + migrations.AddField( + model_name='tagbatch', + name='batch_identity', + field=models.CharField(max_length=50, null=True, unique=True), + ), + ] diff --git a/apps/tag/migrations/0034_remove_tagdistribution_organization.py b/apps/tag/migrations/0034_remove_tagdistribution_organization.py new file mode 100644 index 0000000..192df16 --- /dev/null +++ b/apps/tag/migrations/0034_remove_tagdistribution_organization.py @@ -0,0 +1,17 @@ +# Generated by Django 5.0 on 2026-01-19 06:41 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('tag', '0033_tagbatch_batch_identity'), + ] + + operations = [ + migrations.RemoveField( + model_name='tagdistribution', + name='organization', + ), + ] diff --git a/apps/tag/migrations/0035_tagdistribution_assigned_org.py b/apps/tag/migrations/0035_tagdistribution_assigned_org.py new file mode 100644 index 0000000..f3d4905 --- /dev/null +++ b/apps/tag/migrations/0035_tagdistribution_assigned_org.py @@ -0,0 +1,20 @@ +# Generated by Django 5.0 on 2026-01-19 06:42 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0060_organization_ownership_code'), + ('tag', '0034_remove_tagdistribution_organization'), + ] + + operations = [ + migrations.AddField( + model_name='tagdistribution', + name='assigned_org', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tag_distributions', to='authentication.organization'), + ), + ] diff --git a/apps/tag/migrations/0036_tagdistribution_assigner_org_and_more.py b/apps/tag/migrations/0036_tagdistribution_assigner_org_and_more.py new file mode 100644 index 0000000..afcdb5d --- /dev/null +++ b/apps/tag/migrations/0036_tagdistribution_assigner_org_and_more.py @@ -0,0 +1,25 @@ +# Generated by Django 5.0 on 2026-01-19 06:46 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0060_organization_ownership_code'), + ('tag', '0035_tagdistribution_assigned_org'), + ] + + operations = [ + migrations.AddField( + model_name='tagdistribution', + name='assigner_org', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='assigner_tag_dist', to='authentication.organization'), + ), + migrations.AlterField( + model_name='tagdistribution', + name='assigned_org', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='assigned_tag_dist', to='authentication.organization'), + ), + ] diff --git a/apps/tag/models.py b/apps/tag/models.py index 6350e3d..03fcf67 100644 --- a/apps/tag/models.py +++ b/apps/tag/models.py @@ -47,11 +47,17 @@ class Tag(BaseModel): class TagBatch(BaseModel): + batch_identity = models.CharField( + unique=True, + max_length=50, + null=True + ) organization = models.ForeignKey( Organization, on_delete=models.CASCADE, related_name='tag_batches', - null=True + null=True, + help_text="creator org of tag batch" ) request_number = models.CharField( max_length=50, @@ -86,21 +92,27 @@ class TagDistribution(BaseModel): batch = models.ForeignKey( TagBatch, on_delete=models.CASCADE, - related_name='distributions', + related_name='tag_distributions', null=True ) tag = models.ManyToManyField(Tag, related_name='distributions') - organization = models.ForeignKey( + assigner_org = models.ForeignKey( Organization, on_delete=models.CASCADE, - related_name='distributions', + related_name='assigner_tag_dist', + null=True + ) + assigned_org = models.ForeignKey( + Organization, + on_delete=models.CASCADE, + related_name='assigned_tag_dist', null=True ) species_code = models.IntegerField(default=0) distributed_number = models.IntegerField(default=0) def __str__(self): - return f'{self.id}-{self.distributed_number}-{self.organization.name}' + return f'{self.id}-{self.distributed_number}-{self.assigned_org.name}' def save(self, *args, **kwargs): return super(TagDistribution, self).save(*args, **kwargs) diff --git a/apps/tag/services/tag_services.py b/apps/tag/services/tag_services.py index ef1758e..2aa500e 100644 --- a/apps/tag/services/tag_services.py +++ b/apps/tag/services/tag_services.py @@ -1,3 +1,5 @@ +import random + from django.db.models import Q from django.db.models.aggregates import Count @@ -44,7 +46,9 @@ class TagService: # create tag batch request_number = (serial_end_range - serial_start_range) + 1 + batch_identity = f'{serial_start_range}{serial_end_range}{data.get("species_code")}{random.randint(1000, 9999)}' batch = TagBatch.objects.create( + batch_identity=batch_identity, organization=org, request_number=request_number if request_number > 0 else 1, species_code=data.get('species_code'), diff --git a/apps/tag/web/api/v1/api.py b/apps/tag/web/api/v1/api.py index 70dcdaf..5465352 100644 --- a/apps/tag/web/api/v1/api.py +++ b/apps/tag/web/api/v1/api.py @@ -22,7 +22,7 @@ from common.liara_tools import upload_to_liara from .serializers import ( TagSerializer, TagAssignmentSerializer, - AllocatedTagsSerializer, TagBatchSerializer + AllocatedTagsSerializer, TagBatchSerializer, TagDistributionSerializer ) @@ -115,6 +115,25 @@ class TagViewSet(BaseViewSet, TagService, SoftDeleteMixin, DynamicSearchMixin, v response = self.tag_detail(by_id=pk) return Response(response) + @action( + methods=['get'], + detail=True, + url_name='tags_by_batch', + url_path='tags_by_batch', + name='tags_by_batch', + ) + def get_tags_by_batch_id(self, request, pk=None): + """ + get tags by batch id + """ + tags = self.queryset.filter(tags__id=pk) + + page = self.paginate_queryset(tags) + if page is not None: # noqa + serializer = self.get_serializer(page, many=True) + return self.get_paginated_response(serializer.data) + return Response(self.serializer_class(tags).data) + @action( methods=['get'], detail=False, @@ -323,3 +342,8 @@ class TagBatchViewSet(BaseViewSet, SoftDeleteMixin, DynamicSearchMixin, viewsets tag.soft_delete() return Response(status=status.HTTP_200_OK) + + +class TagDistributionViewSet(BaseViewSet, SoftDeleteMixin, DynamicSearchMixin, viewsets.ModelViewSet): + queryset = tag_models.TagDistribution.objects.all() + serializer_class = TagDistributionSerializer diff --git a/apps/tag/web/api/v1/serializers.py b/apps/tag/web/api/v1/serializers.py index e5e86d6..d75cecc 100644 --- a/apps/tag/web/api/v1/serializers.py +++ b/apps/tag/web/api/v1/serializers.py @@ -136,6 +136,11 @@ class TagBatchSerializer(serializers.ModelSerializer): def to_representation(self, instance): representation = super().to_representation(instance) + representation['organization'] = { + 'id': instance.organization.id, + 'name': instance.organization.name + } + representation['tag'] = [{ 'tag_code': tag.tag_code, 'species_code': tag.species_code, @@ -143,3 +148,32 @@ class TagBatchSerializer(serializers.ModelSerializer): } for tag in instance.tag.all()] return representation + + +class TagDistributionSerializer(serializers.ModelSerializer): + class Meta: + model = tag_models.TagDistribution + fields = '__all__' + + def to_representation(self, instance): + """ + customize output of serializer + """ + representation = super().to_representation(instance) + + representation['batch'] = { + 'batch_creator': instance.batch.organization.name, + 'batch_identity': instance.batch.batch_identity + } + + representation['assigner_org'] = { + 'id': instance.assigner_org.id, + 'name': instance.assigner_org.name + } + + representation['assigned_org'] = { + 'id': instance.assigned_org.id, + 'name': instance.assigned_org.name + } + + return representation