forked from DGNum/gestioCOF
On utilise Scale
This commit is contained in:
parent
cecbb583c6
commit
ad8c3143b6
2 changed files with 49 additions and 72 deletions
|
@ -238,12 +238,7 @@ urlpatterns = [
|
|||
# -----
|
||||
# Sales history urls
|
||||
# -----
|
||||
path("purchases", views.purchases_csv, name="kfet.purchases"),
|
||||
path(
|
||||
"purchases/<int:start_year>-<int:start_month>/<int:end_year>-<int:end_month>",
|
||||
views.purchases_csv,
|
||||
name="kfet.purchases",
|
||||
),
|
||||
path("purchases", views.SalesStatList.as_view(), name="kfet.purchases"),
|
||||
# -----
|
||||
# JSON urls
|
||||
# -----
|
||||
|
|
114
kfet/views.py
114
kfet/views.py
|
@ -2,7 +2,7 @@ import csv
|
|||
import heapq
|
||||
import statistics
|
||||
from collections import defaultdict
|
||||
from datetime import date, datetime, timedelta
|
||||
from datetime import datetime, timedelta
|
||||
from decimal import Decimal
|
||||
from typing import List
|
||||
from urllib.parse import urlencode
|
||||
|
@ -13,12 +13,13 @@ from django.contrib.auth.decorators import login_required, permission_required
|
|||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||
from django.contrib.auth.models import Permission, User
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.core.exceptions import SuspiciousOperation, ValidationError
|
||||
from django.core.exceptions import SuspiciousOperation
|
||||
from django.db import transaction
|
||||
from django.db.models import Count, F, Max, OuterRef, Prefetch, Q, Subquery, Sum
|
||||
from django.forms import ValidationError, formset_factory
|
||||
from django.http import (
|
||||
Http404,
|
||||
HttpResponse,
|
||||
HttpResponseBadRequest,
|
||||
HttpResponseForbidden,
|
||||
JsonResponse,
|
||||
|
@ -30,6 +31,7 @@ from django.utils.decorators import method_decorator
|
|||
from django.views.generic import DetailView, FormView, ListView, TemplateView
|
||||
from django.views.generic.detail import BaseDetailView
|
||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||
from django.views.generic.list import BaseListView
|
||||
|
||||
from gestioncof.models import CofProfile
|
||||
from kfet import KFET_DELETED_TRIGRAMME, consumers
|
||||
|
@ -2456,81 +2458,61 @@ class ScaleMixin(object):
|
|||
# Export des ventes en CSV
|
||||
# ------------------------
|
||||
|
||||
MONTHS = (
|
||||
"_Janvier_Février_Mars_Avril_Mai_Juin_Juillet_Août_Septembre_Octobre"
|
||||
"_Novembre_Décembre"
|
||||
).split("_")
|
||||
|
||||
@teamkfet_required
|
||||
def purchases_csv(
|
||||
request, start_year=None, start_month=None, end_year=None, end_month=None
|
||||
):
|
||||
"""
|
||||
Renvoie un historique des achats en K-Fêt, par mois et sur une période donnée
|
||||
(Par défault les 12 mois précédents)
|
||||
"""
|
||||
# Si on ne spécifie pas tout l'intervalle, on prend les 12 derniers mois
|
||||
if (start_year and start_month and end_year and end_month) is None:
|
||||
# On utilise replace pour gérer le cas des années bissextiles sans
|
||||
# changer de mois
|
||||
end = date.today().replace(day=1)
|
||||
start = end - timedelta(days=365)
|
||||
start_year = start.year
|
||||
start_month = start.month
|
||||
end_year = end.year
|
||||
end_month = end.month
|
||||
|
||||
# On calcule la liste des premiers jours des mois dont on veut avoir les
|
||||
# ventes
|
||||
dates = []
|
||||
@method_decorator(teamkfet_required, name="dispatch")
|
||||
class SalesStatList(BaseListView):
|
||||
model = Operation
|
||||
|
||||
for year in range(start_year, end_year + 1):
|
||||
month_start = start_month if year == start_year else 1
|
||||
month_end = end_month if year == end_year else 12
|
||||
for month in range(month_start, month_end + 1):
|
||||
dates.append(date(year, month, 1))
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(type=Operation.PURCHASE, canceled_at=None)
|
||||
|
||||
# On rajoute le mois suivant
|
||||
dates.append((dates[-1] + timedelta(days=31)).replace(day=1))
|
||||
|
||||
# On récupère les données voulues
|
||||
articles_list = list(Article.objects.order_by("name"))
|
||||
nb_articles = len(articles_list)
|
||||
articles = {}
|
||||
for i in range(nb_articles):
|
||||
articles[articles_list[i].name] = i + 1
|
||||
|
||||
ventes = (
|
||||
Operation.objects.filter(
|
||||
type="purchase", canceled_by=None, group__at__range=[dates[0], dates[-1]]
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
scale = MonthScale(n_steps=12, last=True)
|
||||
qs = self.get_queryset()
|
||||
articles = list(Article.objects.order_by("name"))
|
||||
indexes = {a.name: index for index, a in enumerate(articles)}
|
||||
ventes = scale.chunkify_qs(
|
||||
qs.values_list(
|
||||
"article__name", "group__at__month", "group__at__year"
|
||||
).annotate(Sum("article_nb")),
|
||||
field="group__at",
|
||||
)
|
||||
.exclude(article=None)
|
||||
.order_by("group__at")
|
||||
.select_related("group", "article")
|
||||
)
|
||||
|
||||
# On crée le fichier CSV
|
||||
response = HttpResponse(content_type="text/csv")
|
||||
response["Content-Disposition"] = 'attachment; filename="historique_ventes.csv"'
|
||||
writer = csv.writer(response)
|
||||
ctx["header"] = ["Mois"] + [a.name for a in articles]
|
||||
ctx["ventes"] = []
|
||||
ctx["total"] = [0] * len(articles)
|
||||
for v in ventes:
|
||||
m_ventes = [0] * len(articles)
|
||||
for (a_name, month, year, nb_ventes) in v:
|
||||
index = indexes[a_name]
|
||||
m_ventes[index] = nb_ventes
|
||||
ctx["total"][index] += nb_ventes
|
||||
|
||||
# On met un article par colonne
|
||||
header = ["Mois"] + [a for a in articles]
|
||||
writer.writerow(header)
|
||||
ctx["ventes"].append(["{} {}".format(MONTHS[month], year)] + m_ventes)
|
||||
|
||||
# On calcule la consommation par mois sur la période donnée
|
||||
i_m = 0
|
||||
row = [f"{dates[i_m].month:02d}/{dates[i_m].year}"] + [0] * nb_articles
|
||||
last_row = ["Total"] + [0] * nb_articles
|
||||
for v in ventes:
|
||||
while v.group.at.date() > dates[i_m + 1]:
|
||||
writer.writerow(row)
|
||||
i_m += 1
|
||||
row = [f"{dates[i_m].month:02d}/{dates[i_m].year}"] + [0] * nb_articles
|
||||
return ctx
|
||||
|
||||
row[articles[v.article.name]] += v.article_nb
|
||||
last_row[articles[v.article.name]] += v.article_nb
|
||||
def render_to_response(self, context):
|
||||
response = HttpResponse(content_type="text/csv")
|
||||
response["Content-Disposition"] = 'attachment; filename="historique_ventes.csv"'
|
||||
|
||||
writer.writerow(row)
|
||||
writer.writerow(last_row)
|
||||
writer = csv.writer(response)
|
||||
writer.writerow(context["header"])
|
||||
|
||||
return response
|
||||
# On écrit chaque mois
|
||||
for line in context["ventes"]:
|
||||
writer.writerow(line)
|
||||
|
||||
writer.writerow([])
|
||||
writer.writerow(["Total"] + context["total"])
|
||||
|
||||
return response
|
||||
|
||||
|
||||
# -----------------------
|
||||
|
|
Loading…
Reference in a new issue