feat: add product activation/deactivation and filtering by active status
- Add 'active' boolean field to Product model with default=True - Implement ProductView.get_queryset() to filter products by active status - Default behavior: return only active products - Support query params: ?active=true|false|all - Support variations: 1/0, yes/no for true/false - Detail operations (GET/PATCH/DELETE by ID) work with all products - Update ProductSerializer to include 'active' field - Add comprehensive test suite (11 new tests): - Test filtering by active/inactive/all products - Test parameter variations (1, yes, 0, no) - Test PATCH to activate/deactivate products - Test default list behavior after status changes - Update API documentation in doc/requests.org with examples - All tests passing (13 product tests + 8 API tests)
This commit is contained in:
@@ -14,8 +14,8 @@ post /token/
|
||||
**** respuesta
|
||||
#+begin_src json
|
||||
{
|
||||
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTc4MDEwMzY0NiwiaWF0IjoxNzgwMDE3MjQ2LCJqdGkiOiI1NDk2NmQ0YTFmMGE0OWNjOGU5MGY5MmZmMTE0ZTMwZCIsInVzZXJfaWQiOiIxIn0.uWIe0Xm9i9eI4fFaM3Ha3FrIaQLfwvpHwbJue3OvhTo",
|
||||
"access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzgwMDE5MDQ2LCJpYXQiOjE3ODAwMTcyNDYsImp0aSI6IjQzYmYzOGM0ZWY3MTQ1YTk5ZjliMTQzODMyYjEwZmVkIiwidXNlcl9pZCI6IjEifQ.LMxWs0bHejpgcZvCpMCqfe5ue3YxAaWUweWHHoHhoH0"
|
||||
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTc4MDExNTc0NywiaWF0IjoxNzgwMDI5MzQ3LCJqdGkiOiIxNmVjZGMxZmY4Y2Y0MzA4ODM3ZjM5Y2ZiNjQwNmZiMCIsInVzZXJfaWQiOiIxIn0.wmN-wp3Izv0NrfL_ap_i8eyg29w-foHNrQCCL6HoZWg",
|
||||
"access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzgwMDMxMTQ3LCJpYXQiOjE3ODAwMjkzNDcsImp0aSI6ImQ4ZjE1YTRmODc5NzRjZGViZDEzYzc1ZTU4ZDk3ZjEwIiwidXNlcl9pZCI6IjEifQ.kkQVT2pcYeS_TxlJ6QPU3rNOlZhOv96pyqVEGJI85KA"
|
||||
}
|
||||
#+end_src
|
||||
*** Perfil de usuario
|
||||
@@ -47,7 +47,7 @@ post /token/refresh/
|
||||
** Don confiao :verb:
|
||||
template http://localhost:7000/don_confiao/api/
|
||||
Content-Type: application/json;
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzgwMDE5MDQ2LCJpYXQiOjE3ODAwMTcyNDYsImp0aSI6IjQzYmYzOGM0ZWY3MTQ1YTk5ZjliMTQzODMyYjEwZmVkIiwidXNlcl9pZCI6IjEifQ.LMxWs0bHejpgcZvCpMCqfe5ue3YxAaWUweWHHoHhoH0
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzgwMDMxMTQ3LCJpYXQiOjE3ODAwMjkzNDcsImp0aSI6ImQ4ZjE1YTRmODc5NzRjZGViZDEzYzc1ZTU4ZDk3ZjEwIiwidXNlcl9pZCI6IjEifQ.kkQVT2pcYeS_TxlJ6QPU3rNOlZhOv96pyqVEGJI85KA
|
||||
*** todas las rutas
|
||||
get
|
||||
**** response
|
||||
@@ -79,6 +79,22 @@ get customers/
|
||||
*** products
|
||||
get products/
|
||||
|
||||
*** Productos Inactivos
|
||||
get products/?active=false
|
||||
|
||||
*** Productos Activos
|
||||
get products/?active=true
|
||||
|
||||
*** Traer todos los productos
|
||||
get products/?active=all
|
||||
|
||||
*** Inactiva productos
|
||||
patch products/1
|
||||
|
||||
{
|
||||
"active": false
|
||||
}
|
||||
|
||||
*** Obtener Ventas por catalogo
|
||||
get catalog_sales/
|
||||
|
||||
|
||||
@@ -95,6 +95,34 @@ class ProductView(viewsets.ModelViewSet):
|
||||
queryset = Product.objects.all()
|
||||
serializer_class = ProductSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
"""
|
||||
Filters products by active status for list operations.
|
||||
Detail operations (retrieve, update, destroy) return all products.
|
||||
|
||||
Query params for list:
|
||||
- active=true (default): Only active products
|
||||
- active=false: Only inactive products
|
||||
- active=all: All products regardless of status
|
||||
"""
|
||||
queryset = Product.objects.all()
|
||||
|
||||
# Only filter for list action, not for detail operations
|
||||
if self.action != "list":
|
||||
return queryset
|
||||
|
||||
active_param = self.request.query_params.get("active", "true")
|
||||
|
||||
if active_param.lower() == "all":
|
||||
return queryset
|
||||
elif active_param.lower() in ["true", "1", "yes"]:
|
||||
return queryset.filter(active=True)
|
||||
elif active_param.lower() in ["false", "0", "no"]:
|
||||
return queryset.filter(active=False)
|
||||
else:
|
||||
# Default behavior: return only active products
|
||||
return queryset.filter(active=True)
|
||||
|
||||
|
||||
class CustomerView(viewsets.ModelViewSet):
|
||||
queryset = Customer.objects.all()
|
||||
@@ -120,21 +148,15 @@ class ReconciliateJarView(APIView):
|
||||
status=HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
reconciliation = serializer.save()
|
||||
other_purchases = self._get_other_purchases(
|
||||
data.get("other_totals")
|
||||
)
|
||||
other_purchases = self._get_other_purchases(data.get("other_totals"))
|
||||
|
||||
self._link_purchases(
|
||||
reconciliation, cash_purchases, other_purchases
|
||||
)
|
||||
self._link_purchases(reconciliation, cash_purchases, other_purchases)
|
||||
return Response({"id": reconciliation.id})
|
||||
return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
|
||||
|
||||
def get(self, request):
|
||||
reconciliations = ReconciliationJar.objects.all()
|
||||
serializer = ReconciliationJarSerializer(
|
||||
reconciliations, many=True
|
||||
)
|
||||
serializer = ReconciliationJarSerializer(reconciliations, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
def _is_valid_total(self, purchases, total):
|
||||
@@ -153,9 +175,7 @@ class ReconciliateJarView(APIView):
|
||||
return Sale.objects.filter(pk__in=purchases)
|
||||
return []
|
||||
|
||||
def _link_purchases(
|
||||
self, reconciliation, cash_purchases, other_purchases
|
||||
):
|
||||
def _link_purchases(self, reconciliation, cash_purchases, other_purchases):
|
||||
for purchase in cash_purchases:
|
||||
purchase.reconciliation = reconciliation
|
||||
purchase.clean()
|
||||
@@ -169,9 +189,7 @@ class ReconciliateJarView(APIView):
|
||||
|
||||
class PaymentMethodView(APIView):
|
||||
def get(self, request):
|
||||
serializer = PaymentMethodSerializer(
|
||||
PaymentMethods.choices, many=True
|
||||
)
|
||||
serializer = PaymentMethodSerializer(PaymentMethods.choices, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
@@ -255,23 +273,17 @@ class SalesToTrytonView(APIView):
|
||||
for sale in sales:
|
||||
try:
|
||||
lines = SaleLine.objects.filter(sale=sale.id)
|
||||
tryton_params = self.__to_tryton_params(
|
||||
sale, lines, tryton_context
|
||||
)
|
||||
tryton_params = self.__to_tryton_params(sale, lines, tryton_context)
|
||||
external_ids = tryton_client.call(method, tryton_params)
|
||||
sale.external_id = external_ids[0]
|
||||
sale.save()
|
||||
successful.append(sale.id)
|
||||
except Exception as e:
|
||||
print(
|
||||
f"Error al enviar la venta: {e}" f"venta_id: {sale.id}"
|
||||
)
|
||||
print(f"Error al enviar la venta: {e}venta_id: {sale.id}")
|
||||
failed.append(sale.id)
|
||||
continue
|
||||
|
||||
return Response(
|
||||
{"successful": successful, "failed": failed}, status=200
|
||||
)
|
||||
return Response({"successful": successful, "failed": failed}, status=200)
|
||||
|
||||
def __to_tryton_params(self, sale, lines, tryton_context):
|
||||
sale_tryton = TrytonSale(sale, lines)
|
||||
@@ -279,7 +291,6 @@ class SalesToTrytonView(APIView):
|
||||
|
||||
|
||||
class TrytonSale:
|
||||
|
||||
def __init__(self, sale, lines):
|
||||
self.sale = sale
|
||||
self.lines = lines
|
||||
@@ -299,18 +310,14 @@ class TrytonSale:
|
||||
"invoice_address": self.sale.customer.address_external_id,
|
||||
"currency": TRYTON_COP_CURRENCY,
|
||||
"comment": self.sale.description or "",
|
||||
"description": "Metodo pago: "
|
||||
+ str(self.sale.payment_method or ""),
|
||||
"description": "Metodo pago: " + str(self.sale.payment_method or ""),
|
||||
"party": self.sale.customer.external_id,
|
||||
"reference": "don_confiao " + str(self.sale.id),
|
||||
"sale_date": self._format_date(self.sale.date),
|
||||
"lines": [
|
||||
[
|
||||
"create",
|
||||
[
|
||||
TrytonLineSale(line).to_tryton()
|
||||
for line in self.lines
|
||||
],
|
||||
[TrytonLineSale(line).to_tryton() for line in self.lines],
|
||||
]
|
||||
],
|
||||
"self_pick_up": True,
|
||||
@@ -366,9 +373,7 @@ class ProductsFromTrytonView(APIView):
|
||||
|
||||
for tryton_product in tryton_products:
|
||||
try:
|
||||
product = Product.objects.get(
|
||||
external_id=tryton_product.get("id")
|
||||
)
|
||||
product = Product.objects.get(external_id=tryton_product.get("id"))
|
||||
except Product.DoesNotExist:
|
||||
try:
|
||||
product = self.__create_product(tryton_product)
|
||||
@@ -376,8 +381,7 @@ class ProductsFromTrytonView(APIView):
|
||||
continue
|
||||
except Exception as e:
|
||||
print(
|
||||
f"Error al importar productos: {e}"
|
||||
f"El producto: {tryton_product}"
|
||||
f"Error al importar productos: {e}El producto: {tryton_product}"
|
||||
)
|
||||
failed_products.append(tryton_product.get("id"))
|
||||
continue
|
||||
@@ -399,9 +403,7 @@ class ProductsFromTrytonView(APIView):
|
||||
status=200,
|
||||
)
|
||||
|
||||
def __get_product_datails_from_tryton(
|
||||
self, product_ids, tryton_client, context
|
||||
):
|
||||
def __get_product_datails_from_tryton(self, product_ids, tryton_client, context):
|
||||
tryton_fields = [
|
||||
"id",
|
||||
"name",
|
||||
@@ -459,9 +461,7 @@ class CustomersFromTrytonView(APIView):
|
||||
context = {"company": 1}
|
||||
params = [[], 0, 1000, [["name", "ASC"], ["id", None]], context]
|
||||
party_ids = tryton_client.call(method, params)
|
||||
tryton_parties = self.__get_party_datails(
|
||||
party_ids, tryton_client, context
|
||||
)
|
||||
tryton_parties = self.__get_party_datails(party_ids, tryton_client, context)
|
||||
checked_tryton_parties = party_ids
|
||||
failed_parties = []
|
||||
updated_customers = []
|
||||
@@ -470,9 +470,7 @@ class CustomersFromTrytonView(APIView):
|
||||
|
||||
for tryton_party in tryton_parties:
|
||||
try:
|
||||
customer = Customer.objects.get(
|
||||
external_id=tryton_party.get("id")
|
||||
)
|
||||
customer = Customer.objects.get(external_id=tryton_party.get("id"))
|
||||
except Customer.DoesNotExist:
|
||||
customer = self.__create_customer(tryton_party)
|
||||
created_customers.append(customer.id)
|
||||
@@ -504,10 +502,7 @@ class CustomersFromTrytonView(APIView):
|
||||
def __need_update(self, customer, tryton_party):
|
||||
if not customer.name == tryton_party.get("name"):
|
||||
return True
|
||||
if (
|
||||
tryton_party.get("addresses")
|
||||
and tryton_party.get("addresses")[0]
|
||||
):
|
||||
if tryton_party.get("addresses") and tryton_party.get("addresses")[0]:
|
||||
if not customer.address_external_id == str(
|
||||
tryton_party.get("addresses")[0]
|
||||
):
|
||||
@@ -517,10 +512,7 @@ class CustomersFromTrytonView(APIView):
|
||||
customer = Customer()
|
||||
customer.name = tryton_party.get("name")
|
||||
customer.external_id = tryton_party.get("id")
|
||||
if (
|
||||
tryton_party.get("addresses")
|
||||
and tryton_party.get("addresses")[0]
|
||||
):
|
||||
if tryton_party.get("addresses") and tryton_party.get("addresses")[0]:
|
||||
customer.address_external_id = tryton_party.get("addresses")[0]
|
||||
customer.save()
|
||||
return customer
|
||||
@@ -528,9 +520,6 @@ class CustomersFromTrytonView(APIView):
|
||||
def __update_customer(self, customer, tryton_party):
|
||||
customer.name = tryton_party.get("name")
|
||||
customer.external_id = tryton_party.get("id")
|
||||
if (
|
||||
tryton_party.get("addresses")
|
||||
and tryton_party.get("addresses")[0]
|
||||
):
|
||||
if tryton_party.get("addresses") and tryton_party.get("addresses")[0]:
|
||||
customer.address_external_id = tryton_party.get("addresses")[0]
|
||||
customer.save()
|
||||
|
||||
18
tienda_ilusion/don_confiao/migrations/0046_product_active.py
Normal file
18
tienda_ilusion/don_confiao/migrations/0046_product_active.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.6 on 2026-05-29 04:39
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('don_confiao', '0045_catalogsale_catalogsaleline'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='active',
|
||||
field=models.BooleanField(default=True),
|
||||
),
|
||||
]
|
||||
@@ -14,6 +14,7 @@ class ProductCategory(models.Model):
|
||||
|
||||
|
||||
class Product(models.Model):
|
||||
active = models.BooleanField(default=True)
|
||||
name = models.CharField(max_length=100, unique=True)
|
||||
price = models.DecimalField(max_digits=9, decimal_places=2)
|
||||
measuring_unit = models.CharField(
|
||||
|
||||
@@ -82,6 +82,7 @@ class ProductSerializer(serializers.ModelSerializer):
|
||||
fields = [
|
||||
"id",
|
||||
"name",
|
||||
"active",
|
||||
"price",
|
||||
"measuring_unit",
|
||||
"categories",
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
from django.test import Client, TestCase
|
||||
from django.conf import settings
|
||||
from rest_framework.test import APITestCase
|
||||
from rest_framework import status
|
||||
from ..models.products import ProductCategory, Product
|
||||
from .Mixins import LoginMixin
|
||||
|
||||
import os
|
||||
import json
|
||||
@@ -36,6 +39,211 @@ class TestProducts(TestCase):
|
||||
app_dir = os.path.join(settings.BASE_DIR, app_name)
|
||||
example_csv = os.path.join(app_dir, csv_file)
|
||||
with open(example_csv, "rb") as csv:
|
||||
self.client.post(
|
||||
"/don_confiao/importar_productos", {"csv_file": csv}
|
||||
self.client.post("/don_confiao/importar_productos", {"csv_file": csv})
|
||||
|
||||
|
||||
class TestProductsAPIFiltering(APITestCase, LoginMixin):
|
||||
"""Tests for filtering products by active status via API"""
|
||||
|
||||
def setUp(self):
|
||||
self.login()
|
||||
|
||||
# Create active products
|
||||
self.active_product_1 = Product.objects.create(
|
||||
name="Active Product 1", price=100.00, active=True
|
||||
)
|
||||
self.active_product_2 = Product.objects.create(
|
||||
name="Active Product 2", price=200.00, active=True
|
||||
)
|
||||
|
||||
# Create inactive products
|
||||
self.inactive_product_1 = Product.objects.create(
|
||||
name="Inactive Product 1", price=150.00, active=False
|
||||
)
|
||||
self.inactive_product_2 = Product.objects.create(
|
||||
name="Inactive Product 2", price=250.00, active=False
|
||||
)
|
||||
|
||||
def test_get_products_default_returns_only_active(self):
|
||||
"""By default, API should return only active products"""
|
||||
response = self.client.get("/don_confiao/api/products/")
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
data = response.json()
|
||||
self.assertEqual(len(data), 2)
|
||||
|
||||
product_names = [p["name"] for p in data]
|
||||
self.assertIn("Active Product 1", product_names)
|
||||
self.assertIn("Active Product 2", product_names)
|
||||
self.assertNotIn("Inactive Product 1", product_names)
|
||||
self.assertNotIn("Inactive Product 2", product_names)
|
||||
|
||||
def test_get_products_active_true(self):
|
||||
"""Filter products with active=true should return only active products"""
|
||||
response = self.client.get("/don_confiao/api/products/?active=true")
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
data = response.json()
|
||||
self.assertEqual(len(data), 2)
|
||||
|
||||
for product in data:
|
||||
self.assertTrue(product["active"])
|
||||
|
||||
def test_get_products_active_false(self):
|
||||
"""Filter products with active=false should return only inactive products"""
|
||||
response = self.client.get("/don_confiao/api/products/?active=false")
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
data = response.json()
|
||||
self.assertEqual(len(data), 2)
|
||||
|
||||
for product in data:
|
||||
self.assertFalse(product["active"])
|
||||
|
||||
product_names = [p["name"] for p in data]
|
||||
self.assertIn("Inactive Product 1", product_names)
|
||||
self.assertIn("Inactive Product 2", product_names)
|
||||
|
||||
def test_get_products_active_all(self):
|
||||
"""Filter products with active=all should return all products"""
|
||||
response = self.client.get("/don_confiao/api/products/?active=all")
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
data = response.json()
|
||||
self.assertEqual(len(data), 4)
|
||||
|
||||
def test_get_products_active_variations(self):
|
||||
"""Test different variations of true/false values"""
|
||||
# Test '1' for true
|
||||
response = self.client.get("/don_confiao/api/products/?active=1")
|
||||
self.assertEqual(len(response.json()), 2)
|
||||
|
||||
# Test 'yes' for true
|
||||
response = self.client.get("/don_confiao/api/products/?active=yes")
|
||||
self.assertEqual(len(response.json()), 2)
|
||||
|
||||
# Test '0' for false
|
||||
response = self.client.get("/don_confiao/api/products/?active=0")
|
||||
self.assertEqual(len(response.json()), 2)
|
||||
|
||||
# Test 'no' for false
|
||||
response = self.client.get("/don_confiao/api/products/?active=no")
|
||||
self.assertEqual(len(response.json()), 2)
|
||||
|
||||
def test_get_product_detail_regardless_of_status(self):
|
||||
"""Getting a specific product by ID should work regardless of active status"""
|
||||
# Get active product
|
||||
response = self.client.get(
|
||||
f"/don_confiao/api/products/{self.active_product_1.id}/"
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.json()["name"], "Active Product 1")
|
||||
|
||||
# Get inactive product
|
||||
response = self.client.get(
|
||||
f"/don_confiao/api/products/{self.inactive_product_1.id}/"
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.json()["name"], "Inactive Product 1")
|
||||
|
||||
|
||||
class TestProductsAPIActivation(APITestCase, LoginMixin):
|
||||
"""Tests for activating/deactivating products via API"""
|
||||
|
||||
def setUp(self):
|
||||
self.login()
|
||||
|
||||
self.product = Product.objects.create(
|
||||
name="Test Product", price=100.00, active=True
|
||||
)
|
||||
|
||||
def test_deactivate_product_via_patch(self):
|
||||
"""PATCH request should be able to deactivate a product"""
|
||||
response = self.client.patch(
|
||||
f"/don_confiao/api/products/{self.product.id}/",
|
||||
{"active": False},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
# Verify product was deactivated
|
||||
self.product.refresh_from_db()
|
||||
self.assertFalse(self.product.active)
|
||||
|
||||
# Verify response contains updated data
|
||||
self.assertFalse(response.json()["active"])
|
||||
|
||||
def test_activate_product_via_patch(self):
|
||||
"""PATCH request should be able to activate a product"""
|
||||
# First deactivate the product
|
||||
self.product.active = False
|
||||
self.product.save()
|
||||
|
||||
response = self.client.patch(
|
||||
f"/don_confiao/api/products/{self.product.id}/",
|
||||
{"active": True},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
# Verify product was activated
|
||||
self.product.refresh_from_db()
|
||||
self.assertTrue(self.product.active)
|
||||
|
||||
# Verify response contains updated data
|
||||
self.assertTrue(response.json()["active"])
|
||||
|
||||
def test_update_other_fields_preserves_active_status(self):
|
||||
"""Updating other fields should not affect active status"""
|
||||
response = self.client.patch(
|
||||
f"/don_confiao/api/products/{self.product.id}/",
|
||||
{"price": "250.00"},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
# Verify active status was preserved
|
||||
self.product.refresh_from_db()
|
||||
self.assertTrue(self.product.active)
|
||||
self.assertEqual(self.product.price, 250.00)
|
||||
|
||||
def test_deactivated_product_not_in_default_list(self):
|
||||
"""After deactivating a product, it should not appear in default list"""
|
||||
# Deactivate product
|
||||
self.client.patch(
|
||||
f"/don_confiao/api/products/{self.product.id}/",
|
||||
{"active": False},
|
||||
format="json",
|
||||
)
|
||||
|
||||
# Get default product list
|
||||
response = self.client.get("/don_confiao/api/products/")
|
||||
data = response.json()
|
||||
|
||||
# Product should not be in list
|
||||
product_ids = [p["id"] for p in data]
|
||||
self.assertNotIn(self.product.id, product_ids)
|
||||
|
||||
def test_activated_product_appears_in_default_list(self):
|
||||
"""After activating a product, it should appear in default list"""
|
||||
# Deactivate product first
|
||||
self.product.active = False
|
||||
self.product.save()
|
||||
|
||||
# Activate product
|
||||
self.client.patch(
|
||||
f"/don_confiao/api/products/{self.product.id}/",
|
||||
{"active": True},
|
||||
format="json",
|
||||
)
|
||||
|
||||
# Get default product list
|
||||
response = self.client.get("/don_confiao/api/products/")
|
||||
data = response.json()
|
||||
|
||||
# Product should be in list
|
||||
product_ids = [p["id"] for p in data]
|
||||
self.assertIn(self.product.id, product_ids)
|
||||
|
||||
Reference in New Issue
Block a user