Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Order export csv #990

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ and this project adheres to
to `Product`model
- Add admin api endpoints to CRUD `Teacher` and `Skill` resources.
- Add certification section in back office product detail view
- Add order export to CSV in back office

### Changed

Expand Down
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,6 @@ clean: ## restore repository state as it was freshly cloned
.PHONY: clean

tunnel: ## Run a proxy through localtunnel
@$(MAKE) run
@echo
npx localtunnel -s $(LOCALTUNNEL_SUBDOMAIN) -h $(LOCALTUNNEL_HOST) --port $(LOCALTUNNEL_PORT) --print-requests
.PHONY: tunnel
Expand Down
29 changes: 27 additions & 2 deletions src/backend/joanie/core/api/admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

from django.core.cache import cache
from django.core.exceptions import ValidationError
from django.http import JsonResponse
from django.http import JsonResponse, StreamingHttpResponse
from django.utils import timezone

from django_filters.rest_framework import DjangoFilterBackend
from drf_spectacular.types import OpenApiTypes
Expand Down Expand Up @@ -614,7 +615,9 @@ class OrderViewSet(
permission_classes = [permissions.IsAdminUser & permissions.DjangoModelPermissions]
serializer_classes = {
"list": serializers.AdminOrderLightSerializer,
"export": serializers.AdminOrderExportSerializer,
}
serializer_class = serializers.AdminOrderSerializer
default_serializer_class = serializers.AdminOrderSerializer
filterset_class = filters.OrderAdminFilterSet
queryset = models.Order.objects.all().select_related(
Expand All @@ -632,7 +635,6 @@ class OrderViewSet(
"credit_card",
)
filter_backends = [DjangoFilterBackend, OrderingFilter]
ordering_fields = ["created_on"]

def destroy(self, request, *args, **kwargs):
"""Cancels an order."""
Expand Down Expand Up @@ -689,6 +691,29 @@ def refund(self, request, pk=None): # pylint:disable=unused-argument

return Response(status=HTTPStatus.ACCEPTED)

@extend_schema(
request=None,
responses={
(200, "text/csv"): OpenApiTypes.OBJECT,
404: serializers.ErrorResponseSerializer,
},
)
@action(methods=["GET"], detail=False)
def export(self, request):
"""
Export orders to a CSV file.
"""
queryset = self.filter_queryset(self.get_queryset())
serializer = serializers.AdminOrderListExportSerializer(
queryset.iterator(), child=self.get_serializer()
)
now = timezone.now().strftime("%d-%m-%Y_%H-%M-%S")
return StreamingHttpResponse(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the time needed to Stream the whole file, I emit some reserve about that as this will block a worker. If you are able to connect your local env to the preproduction database this is something to check IMO.

serializer.csv_stream(),
content_type="text/csv",
headers={"Content-Disposition": f'attachment; filename="orders_{now}.csv"'},
)
jbpenrath marked this conversation as resolved.
Show resolved Hide resolved


class OrganizationAddressViewSet(
mixins.CreateModelMixin,
Expand Down
2 changes: 2 additions & 0 deletions src/backend/joanie/core/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ class Meta:
model = settings.AUTH_USER_MODEL
django_get_or_create = ("username",)

# In our database, first_name is set by authtoken with the user's full name
first_name = factory.Faker("name")
username = factory.Sequence(lambda n: f"user{n!s}")
email = factory.Faker("email")
language = factory.fuzzy.FuzzyChoice([lang[0] for lang in settings.LANGUAGES])
Expand Down
7 changes: 7 additions & 0 deletions src/backend/joanie/core/models/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ def __init__(self, *args, **kwargs):
def __str__(self):
return self.username

@property
def name(self):
"""
Return the full name of the user if available, otherwise the username.
"""
return self.get_full_name() or self.username

def clean(self):
"""
Normalize the `phone_number` value for consistency in database.
Expand Down
2 changes: 1 addition & 1 deletion src/backend/joanie/core/models/certifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ def get_document_context(self, language_code=None):
"delivery_stamp": timezone.now(),
"verification_link": self.verification_uri,
"student": {
"name": self.owner.get_full_name() or self.owner.username,
"name": self.owner.name,
},
"site": {
"name": settings.JOANIE_CATALOG_NAME,
Expand Down
Loading