change: change offer model, and add new api
This commit is contained in:
@@ -5,6 +5,6 @@ from core.apps.orders.models import Offer
|
|||||||
|
|
||||||
@admin.register(Offer)
|
@admin.register(Offer)
|
||||||
class OfferAdmin(admin.ModelAdmin):
|
class OfferAdmin(admin.ModelAdmin):
|
||||||
list_display = ['id', 'number', 'order']
|
list_display = ['id', 'number', 'order', 'status']
|
||||||
search_fields = ['phone', 'number', 'price']
|
search_fields = ['phone', 'number', 'price']
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ class OrderFilter(django_filters.FilterSet):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Order
|
model = Order
|
||||||
fields = [
|
fields = [
|
||||||
'wherehouse', 'project', 'project_folder', 'date'
|
'wherehouse', 'project', 'project_folder', 'date',
|
||||||
]
|
]
|
||||||
|
|
||||||
18
core/apps/orders/migrations/0024_offer_status.py
Normal file
18
core/apps/orders/migrations/0024_offer_status.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.4 on 2025-09-24 14:40
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('orders', '0023_alter_party_orders'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='offer',
|
||||||
|
name='status',
|
||||||
|
field=models.CharField(choices=[('CANCELLED', 'rad etildi'), ('PENDING', 'kutilmoqda'), ('CONFIRMED', 'tasdiqlandi')], default='PENDING', max_length=20),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
core/apps/orders/migrations/0025_alter_offer_status.py
Normal file
18
core/apps/orders/migrations/0025_alter_offer_status.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.4 on 2025-09-24 14:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('orders', '0024_offer_status'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='offer',
|
||||||
|
name='status',
|
||||||
|
field=models.CharField(blank=True, choices=[('CANCELLED', 'rad etildi'), ('PENDING', 'kutilmoqda'), ('CONFIRMED', 'tasdiqlandi')], default='PENDING', max_length=20, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -10,15 +10,23 @@ class Offer(BaseModel):
|
|||||||
('UZS', 'uzs'),
|
('UZS', 'uzs'),
|
||||||
('USD', 'usd')
|
('USD', 'usd')
|
||||||
)
|
)
|
||||||
|
STATUS = (
|
||||||
|
('CANCELLED', 'rad etildi'),
|
||||||
|
('PENDING', 'kutilmoqda'),
|
||||||
|
('CONFIRMED', 'tasdiqlandi'),
|
||||||
|
)
|
||||||
|
|
||||||
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='offers')
|
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='offers')
|
||||||
counterparty = models.ForeignKey(Counterparty, on_delete=models.CASCADE, related_name='offers', null=True)
|
counterparty = models.ForeignKey(
|
||||||
|
Counterparty, on_delete=models.CASCADE, related_name='offers', null=True
|
||||||
|
)
|
||||||
price = models.PositiveBigIntegerField()
|
price = models.PositiveBigIntegerField()
|
||||||
price_type = models.CharField(choices=PRICE_TYPE, default='uzs')
|
price_type = models.CharField(choices=PRICE_TYPE, default='uzs')
|
||||||
phone = models.CharField(max_length=15, null=True, blank=True)
|
phone = models.CharField(max_length=15, null=True, blank=True)
|
||||||
comment = models.TextField(null=True, blank=True)
|
comment = models.TextField(null=True, blank=True)
|
||||||
qqs = models.BooleanField(default=False, null=True, blank=True)
|
qqs = models.BooleanField(default=False, null=True, blank=True)
|
||||||
number = models.PositiveIntegerField(default=1)
|
number = models.PositiveIntegerField(default=1)
|
||||||
|
status = models.CharField(max_length=20, choices=STATUS, default='PENDING', null=True, blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.number)
|
return str(self.number)
|
||||||
|
|||||||
@@ -95,7 +95,8 @@ class OffersSerializer(serializers.ModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Offer
|
model = Offer
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'number', 'price', 'price_type', 'phone', 'comment', 'qqs', 'counterparty', 'created_at'
|
'id', 'number', 'price', 'price_type', 'phone', 'comment', 'qqs', 'counterparty',
|
||||||
|
'status', 'created_at'
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_counterparty(self, obj):
|
def get_counterparty(self, obj):
|
||||||
@@ -106,7 +107,7 @@ class OffersSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class OrderListForOfferSerializer(serializers.ModelSerializer):
|
class OrderListForOfferSerializer(serializers.ModelSerializer):
|
||||||
offers = OffersSerializer(many=True)
|
offers = serializers.SerializerMethodField(method_name='get_offers')
|
||||||
product = serializers.SerializerMethodField(method_name='get_product')
|
product = serializers.SerializerMethodField(method_name='get_product')
|
||||||
unity = serializers.SerializerMethodField(method_name='get_unity')
|
unity = serializers.SerializerMethodField(method_name='get_unity')
|
||||||
|
|
||||||
@@ -128,3 +129,11 @@ class OrderListForOfferSerializer(serializers.ModelSerializer):
|
|||||||
'id': obj.unity.id,
|
'id': obj.unity.id,
|
||||||
'value': obj.unity.value
|
'value': obj.unity.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_offers(self, obj):
|
||||||
|
status = self.context.get('status')
|
||||||
|
if status:
|
||||||
|
offers = obj.offers.filter(status=status)
|
||||||
|
return OffersSerializer(offers, many=True).data
|
||||||
|
else:
|
||||||
|
return OffersSerializer(obj.offers, many=True).data
|
||||||
@@ -25,6 +25,7 @@ urlpatterns = [
|
|||||||
path('<uuid:id>/delete/', offer_views.OfferDeleteApiView.as_view()),
|
path('<uuid:id>/delete/', offer_views.OfferDeleteApiView.as_view()),
|
||||||
path('<uuid:id>/update/', offer_views.OfferUpdateApiView.as_view()),
|
path('<uuid:id>/update/', offer_views.OfferUpdateApiView.as_view()),
|
||||||
path('bulk-delete/', offer_views.DeleteMultipleOfferApiView.as_view()),
|
path('bulk-delete/', offer_views.DeleteMultipleOfferApiView.as_view()),
|
||||||
|
path('<uuid:id>/change-status/', offer_views.ChangeOfferStatusApiView.as_view()),
|
||||||
]
|
]
|
||||||
)),
|
)),
|
||||||
path('party/', include(
|
path('party/', include(
|
||||||
|
|||||||
@@ -40,9 +40,13 @@ class OfferListApiView(generics.GenericAPIView):
|
|||||||
filterset_class = OrderFilter
|
filterset_class = OrderFilter
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
|
offer_status = request.query_params.get('status', None)
|
||||||
orders = self.filter_queryset(self.get_queryset())
|
orders = self.filter_queryset(self.get_queryset())
|
||||||
page = self.paginate_queryset(orders)
|
page = self.paginate_queryset(orders)
|
||||||
if page is not None:
|
if page is not None:
|
||||||
|
if offer_status:
|
||||||
|
serializer = self.serializer_class(page, many=True, context={'status': offer_status})
|
||||||
|
else:
|
||||||
serializer = self.serializer_class(page, many=True)
|
serializer = self.serializer_class(page, many=True)
|
||||||
return self.get_paginated_response(serializer.data)
|
return self.get_paginated_response(serializer.data)
|
||||||
serializer = self.serializer_class(offers, many=True)
|
serializer = self.serializer_class(offers, many=True)
|
||||||
@@ -101,3 +105,20 @@ class DeleteMultipleOfferApiView(views.APIView):
|
|||||||
|
|
||||||
deleted_count, _ = Offer.objects.filter(id__in=ids).delete()
|
deleted_count, _ = Offer.objects.filter(id__in=ids).delete()
|
||||||
return Response({"deleted": deleted_count}, status=200)
|
return Response({"deleted": deleted_count}, status=200)
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeOfferStatusApiView(views.APIView):
|
||||||
|
permission_classes = [HasRolePermission]
|
||||||
|
|
||||||
|
def post(self, request, id):
|
||||||
|
offer = get_object_or_404(Offer, id=id)
|
||||||
|
status = request.data.get('status')
|
||||||
|
if not status:
|
||||||
|
return Response({'success': False, 'message': 'status field is required'}, status=400)
|
||||||
|
offer.status = status
|
||||||
|
offer.save()
|
||||||
|
return Response(
|
||||||
|
{'success': True, 'message': 'status updated'},
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
Reference in New Issue
Block a user