Add catalog sale purchase summary endpoint

- Add CatalogSaleSummarySerializer and CatalogSummarySaleLineSerializer
- Add CatalogSaleSummary API view for GET requests
- Register endpoint at /don_confiao/resumen_compra_catalogo_json/<id>
- Add comprehensive test for catalog sale summary
- Include nested customer and product details in response
- Endpoint returns id, date, customer, and lines with products
This commit is contained in:
2026-05-30 20:32:20 -05:00
parent 52ff61354e
commit d4a61b8340
6 changed files with 80 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ from .sales import (
SaleView, SaleView,
CatalogSaleView, CatalogSaleView,
SaleSummary, SaleSummary,
CatalogSaleSummary,
SalesForTrytonView, SalesForTrytonView,
SalesToTrytonView, SalesToTrytonView,
) )
@@ -27,6 +28,7 @@ __all__ = [
"SaleView", "SaleView",
"CatalogSaleView", "CatalogSaleView",
"SaleSummary", "SaleSummary",
"CatalogSaleSummary",
"SalesForTrytonView", "SalesForTrytonView",
"SalesToTrytonView", "SalesToTrytonView",
# Payments # Payments

View File

@@ -12,6 +12,7 @@ from ..serializers import (
SaleSerializer, SaleSerializer,
CatalogSaleSerializer, CatalogSaleSerializer,
SaleSummarySerializer, SaleSummarySerializer,
CatalogSaleSummarySerializer,
) )
from ..permissions import IsAdministrator from ..permissions import IsAdministrator
from ..services.tryton.sales import SaleTrytonService from ..services.tryton.sales import SaleTrytonService
@@ -66,6 +67,13 @@ class SaleSummary(APIView):
return Response(serializer.data) return Response(serializer.data)
class CatalogSaleSummary(APIView):
def get(self, request, id):
catalog_sale = CatalogSale.objects.get(pk=id)
serializer = CatalogSaleSummarySerializer(catalog_sale)
return Response(serializer.data)
class SalesForTrytonView(APIView): class SalesForTrytonView(APIView):
permission_classes = [IsAuthenticated, IsAdministrator] permission_classes = [IsAuthenticated, IsAdministrator]

View File

@@ -7,6 +7,8 @@ from .sales import (
CatalogSaleLineSerializer, CatalogSaleLineSerializer,
SummarySaleLineSerializer, SummarySaleLineSerializer,
SaleSummarySerializer, SaleSummarySerializer,
CatalogSummarySaleLineSerializer,
CatalogSaleSummarySerializer,
SaleForRenconciliationSerializer, SaleForRenconciliationSerializer,
) )
from .payments import ( from .payments import (
@@ -28,6 +30,8 @@ __all__ = [
"CatalogSaleLineSerializer", "CatalogSaleLineSerializer",
"SummarySaleLineSerializer", "SummarySaleLineSerializer",
"SaleSummarySerializer", "SaleSummarySerializer",
"CatalogSummarySaleLineSerializer",
"CatalogSaleSummarySerializer",
"SaleForRenconciliationSerializer", "SaleForRenconciliationSerializer",
# Payments # Payments
"ReconciliationJarSerializer", "ReconciliationJarSerializer",

View File

@@ -87,6 +87,23 @@ class SaleSummarySerializer(serializers.ModelSerializer):
fields = ["id", "date", "customer", "payment_method", "lines"] fields = ["id", "date", "customer", "payment_method", "lines"]
class CatalogSummarySaleLineSerializer(serializers.ModelSerializer):
product = ListProductSerializer()
class Meta:
model = CatalogSaleLine
fields = ["product", "quantity", "unit_price", "description"]
class CatalogSaleSummarySerializer(serializers.ModelSerializer):
customer = ListCustomerSerializer()
lines = CatalogSummarySaleLineSerializer(many=True, source="catalogsaleline_set")
class Meta:
model = CatalogSale
fields = ["id", "date", "customer", "lines"]
class SaleForRenconciliationSerializer(serializers.Serializer): class SaleForRenconciliationSerializer(serializers.Serializer):
id = serializers.IntegerField() id = serializers.IntegerField()
date = serializers.DateTimeField() date = serializers.DateTimeField()

View File

@@ -86,6 +86,49 @@ class TestAPI(APITestCase, LoginMixin):
self.assertIn("csv", json_response) self.assertIn("csv", json_response)
self.assertGreater(len(json_response["csv"]), 0) self.assertGreater(len(json_response["csv"]), 0)
def test_catalog_sale_summary(self):
# Create a catalog sale
response = self._create_catalog_sale()
content = json.loads(response.content.decode("utf-8"))
catalog_sale_id = content["id"]
# Get the summary
url = f"/don_confiao/resumen_compra_catalogo_json/{catalog_sale_id}"
response = self.client.get(url)
# Verify response
self.assertEqual(response.status_code, status.HTTP_200_OK)
json_response = json.loads(response.content.decode("utf-8"))
# Verify structure
self.assertIn("id", json_response)
self.assertIn("date", json_response)
self.assertIn("customer", json_response)
self.assertIn("lines", json_response)
# Verify customer details
self.assertEqual(json_response["customer"]["id"], self.customer.id)
self.assertEqual(json_response["customer"]["name"], self.customer.name)
# Verify lines
self.assertEqual(len(json_response["lines"]), 2)
# Verify first line
line1 = json_response["lines"][0]
self.assertIn("product", line1)
self.assertIn("quantity", line1)
self.assertIn("unit_price", line1)
self.assertEqual(line1["product"]["id"], self.product.id)
self.assertEqual(line1["product"]["name"], self.product.name)
self.assertEqual(line1["quantity"], "2.00")
self.assertEqual(line1["unit_price"], "3000.00")
# Verify second line
line2 = json_response["lines"][1]
self.assertEqual(line2["product"]["id"], self.product.id)
self.assertEqual(line2["quantity"], "3.00")
self.assertEqual(line2["unit_price"], "5000.00")
def test_csv_structure_in_sales_for_tryton(self): def test_csv_structure_in_sales_for_tryton(self):
url = "/don_confiao/api/sales/for_tryton" url = "/don_confiao/api/sales/for_tryton"
self._create_sale() self._create_sale()

View File

@@ -13,6 +13,7 @@ from .api import (
SaleView, SaleView,
CatalogSaleView, CatalogSaleView,
SaleSummary, SaleSummary,
CatalogSaleSummary,
SalesForTrytonView, SalesForTrytonView,
SalesToTrytonView, SalesToTrytonView,
# Payments # Payments
@@ -44,6 +45,11 @@ urlpatterns = [
SaleSummary.as_view(), SaleSummary.as_view(),
name="purchase_json_summary", name="purchase_json_summary",
), ),
path(
"resumen_compra_catalogo_json/<int:id>",
CatalogSaleSummary.as_view(),
name="catalog_purchase_json_summary",
),
path( path(
"payment_methods/all/select_format", "payment_methods/all/select_format",
PaymentMethodView.as_view(), PaymentMethodView.as_view(),