from decimal import Decimal import pytest from django.urls import reverse from django.utils import timezone from rest_framework import status from commerce.models import Cost, Product, Sale, SaleLine, SourceSystem, StockSnapshot pytestmark = pytest.mark.django_db def test_commerce_api_requires_authentication(api_client): response = api_client.get(reverse("api:v1:commerce:product-list")) assert response.status_code == status.HTTP_401_UNAUTHORIZED def test_employee_can_read_but_cannot_create_product(api_client, user_factory): user = user_factory() Product.objects.create(sku="FISHKA", name="Фишка") api_client.force_authenticate(user=user) list_response = api_client.get(reverse("api:v1:commerce:product-list")) create_response = api_client.post( reverse("api:v1:commerce:product-list"), {"sku": "NEW", "name": "Новый товар", "kind": "product"}, format="json", ) assert list_response.status_code == status.HTTP_200_OK assert list_response.data["count"] == 1 assert create_response.status_code == status.HTTP_403_FORBIDDEN def test_staff_can_create_product(api_client, user_factory): user = user_factory(staff=True) api_client.force_authenticate(user=user) response = api_client.post( reverse("api:v1:commerce:product-list"), {"sku": "NEW", "name": "Новый товар", "kind": "product"}, format="json", ) assert response.status_code == status.HTTP_201_CREATED assert Product.objects.filter(sku="NEW").exists() def test_staff_can_manage_normalized_commerce_facts(api_client, user_factory): user = user_factory(staff=True) source = SourceSystem.objects.create(code="moysklad", name="МойСклад") product = Product.objects.create(sku="FISHKA", name="Фишка") api_client.force_authenticate(user=user) sale_response = api_client.post( reverse("api:v1:commerce:sale-list"), { "source": source.pk, "external_id": "order-1", "occurred_at": timezone.now().isoformat(), }, format="json", ) assert sale_response.status_code == status.HTTP_201_CREATED line_response = api_client.post( reverse("api:v1:commerce:saleline-list"), { "sale": sale_response.data["id"], "product": product.pk, "external_id": "line-1", "quantity": "2", "gross_amount": "500.00", "discount_amount": "50.00", "cost_amount": "200.00", }, format="json", ) assert line_response.status_code == status.HTTP_201_CREATED cost_response = api_client.post( reverse("api:v1:commerce:cost-list"), { "source": source.pk, "product": product.pk, "cost_type": "commission", "amount": "25.00", "occurred_at": timezone.now().isoformat(), }, format="json", ) assert cost_response.status_code == status.HTTP_201_CREATED, cost_response.data stock_response = api_client.post( reverse("api:v1:commerce:stocksnapshot-list"), { "source": source.pk, "product": product.pk, "warehouse_external_id": "main", "quantity": "10", "reserved": "2", "captured_at": timezone.now().isoformat(), }, format="json", ) assert stock_response.status_code == status.HTTP_201_CREATED assert SaleLine.objects.filter(pk=line_response.data["id"]).exists() assert Cost.objects.filter(pk=cost_response.data["id"]).exists() assert StockSnapshot.objects.filter(pk=stock_response.data["id"]).exists() def test_product_analytics_endpoint(api_client, user_factory): user = user_factory() source = SourceSystem.objects.create(code="insales", name="InSales") product = Product.objects.create(sku="FISHKA", name="Фишка") sale = Sale.objects.create( source=source, external_id="order-1", occurred_at=timezone.now(), channel="site", ) SaleLine.objects.create( sale=sale, product=product, external_id="line-1", quantity=Decimal("1"), gross_amount=Decimal("500"), cost_amount=Decimal("200"), ) api_client.force_authenticate(user=user) response = api_client.get( reverse("api:v1:commerce:product-analytics", args=[product.pk]) ) assert response.status_code == status.HTTP_200_OK assert response.data["product_id"] == product.pk assert response.data["monetary"][0]["net_revenue"] == Decimal("500") assert response.data["monetary"][0]["contribution_margin"] == Decimal("300")