Commit 62ad9f2c authored by Patrick's avatar Patrick
Browse files

WIP

parent 8975f63a
......@@ -19,7 +19,7 @@ class ProductFilterByProducer(SimpleListFilter):
# right admin sidebar.
title = _("producers")
# Parameter for the filter that will be used in the URL query.
parameter_name = 'producer_id'
parameter_name = 'producer'
template = 'admin/producer_filter.html'
def lookups(self, request, model_admin):
......@@ -157,23 +157,20 @@ class PurchaseFilterByCustomer(SimpleListFilter):
class PurchaseFilterByProducerForThisPermanence(SimpleListFilter):
title = _("producer")
title = _("producers")
parameter_name = 'producer'
template = 'admin/producer_filter.html'
def lookups(self, request, model_admin):
permanence_id = request.GET.get('permanence', None)
if permanence_id is not None:
list_filter = []
for p in Producer.objects.filter(permanence=permanence_id):
pi = ProducerInvoice.objects.filter(permanence=permanence_id, producer_id=p.id).order_by('?').first()
if pi is not None:
list_filter.append((p.id, "%s (%s)" % (p.short_profile_name, pi.total_price_with_tax,)))
else:
list_filter.append((p.id, p.short_profile_name))
return list_filter
else:
return []
list_filter = []
for p in Producer.objects.filter(permanence=permanence_id):
pi = ProducerInvoice.objects.filter(permanence=permanence_id, producer_id=p.id).order_by('?').first()
if pi is not None:
list_filter.append((p.id, "%s (%s)" % (p.short_profile_name, pi.total_price_with_tax,)))
else:
list_filter.append((p.id, p.short_profile_name))
return list_filter
def queryset(self, request, queryset):
if self.value():
......
......@@ -49,10 +49,10 @@ class OfferItemClosedAdmin(admin.ModelAdmin):
ordering = ('translations__long_name',)
def get_queryset(self, request):
queryset = super(OfferItemClosedAdmin, self).get_queryset(request).filter(
qs = super(OfferItemClosedAdmin, self).get_queryset(request)
return qs.filter(
translations__language_code=translation.get_language()
).distinct()
return queryset
def get_list_display(self, request):
producer_id = sint(request.GET.get('producer', 0))
......
......@@ -362,7 +362,7 @@ class ProductAdmin(ImportExportMixin, TranslatableAdmin):
duplicate_product.short_description = _('duplicate product')
def get_list_display(self, request):
producer_id = sint(request.GET.get('producer_id', 0))
producer_id = sint(request.GET.get('producer', 0))
if producer_id != 0:
producer_queryset = Producer.objects.filter(id=producer_id).order_by('?')
producer = producer_queryset.first()
......@@ -425,8 +425,8 @@ class ProductAdmin(ImportExportMixin, TranslatableAdmin):
preserved_filters = request.GET.get('_changelist_filters', None)
if preserved_filters:
param = dict(parse_qsl(preserved_filters))
if 'producer_id' in param:
producer_id = param['producer_id']
if 'producer' in param:
producer_id = param['producer']
if producer_id:
producer_queryset = Producer.objects.filter(id=producer_id).order_by('?')
if 'department_for_customer' in param:
......
......@@ -208,7 +208,7 @@ class OfferItemSendAdmin(admin.ModelAdmin):
qs = super(OfferItemSendAdmin, self).get_queryset(request)
return qs.filter(
translations__language_code=translation.get_language()
)
).distinct()
def get_form(self, request, obj=None, **kwargs):
if obj.is_resale_price_fixed:
......
......@@ -68,7 +68,7 @@ class RepanierSettings(AppConfig):
db_started = connection.cursor() is not None
except:
time.sleep(1)
from models import Configuration, LUT_DepartmentForCustomer, Staff, Purchase
from models import Configuration, LUT_DepartmentForCustomer, Staff, Purchase, CustomerInvoice
from const import DECIMAL_ONE, PERMANENCE_NAME_PERMANENCE, CURRENCY_EUR, ORDER_GROUP, \
INVOICE_GROUP, CONTRIBUTOR_GROUP, COORDINATION_GROUP, WEBMASTER_GROUP
try:
......@@ -92,10 +92,14 @@ class RepanierSettings(AppConfig):
# Purchase.objects.filter(customer_charged__isnull=True).update(
# customer_charged=F('customer_invoice__customer_charged')
# )
for purchase in Purchase.objects.filter(
customer_charged__isnull=True).select_related("customer_invoice").order_by('?'):
purchase.customer_charged = purchase.customer_invoice.customer_charged
purchase.save(update_fields=["customer_charged",])
# for purchase in Purchase.objects.filter(
# customer_charged__isnull=True).select_related("customer_invoice").order_by('?'):
# purchase.customer_charged = purchase.customer_invoice.customer_charged
# purchase.save(update_fields=["customer_charged",])
CustomerInvoice.objects.filter(
customer__is_group=True,
customer_id=F('customer_charged_id')
).update(is_group=True)
Staff.objects.rebuild()
# Create groups with correct rights
order_group = Group.objects.filter(name=ORDER_GROUP).only('id').order_by('?').first()
......
......@@ -74,21 +74,21 @@ class PermanenceMenu(Menu):
submenu_id = self.append_permanence(is_anonymous, permanence, nodes, master_id, submenu_id)
if displayed_permanence_counter > 4:
break
if displayed_permanence_counter < 4:
max_counter = 4 - displayed_permanence_counter
for permanence in Permanence.objects.filter(status__in=[PERMANENCE_INVOICED, PERMANENCE_ARCHIVED]) \
.only("id", "permanence_date") \
.order_by('-permanence_date'):
if permanence.permanence_date >= (
timezone.now() - datetime.timedelta(weeks=LIMIT_DISPLAYED_PERMANENCE)).date():
if first_pass and closed_separator:
submenu_id = self.append_separator(nodes, master_id, submenu_id)
first_pass = False
separator = True
submenu_id = self.append_permanence(is_anonymous, permanence, nodes, master_id, submenu_id)
max_counter -= 1
if max_counter <= 0:
break
# if displayed_permanence_counter < 4:
# max_counter = 4 - displayed_permanence_counter
# for permanence in Permanence.objects.filter(status__in=[PERMANENCE_INVOICED, PERMANENCE_ARCHIVED]) \
# .only("id", "permanence_date") \
# .order_by('-permanence_date'):
# if permanence.permanence_date >= (
# timezone.now() - datetime.timedelta(weeks=LIMIT_DISPLAYED_PERMANENCE)).date():
# if first_pass and closed_separator:
# submenu_id = self.append_separator(nodes, master_id, submenu_id)
# first_pass = False
# separator = True
# submenu_id = self.append_permanence(is_anonymous, permanence, nodes, master_id, submenu_id)
# max_counter -= 1
# if max_counter <= 0:
# break
# if REPANIER_SETTINGS_INVOICE and not request.user.is_staff:
# if separator:
......
......@@ -87,7 +87,8 @@ def send_invoice(permanence_id):
).order_by('?'):
long_basket_name = customer.long_basket_name if customer.long_basket_name is not None else customer.short_basket_name
if Purchase.objects.filter(
permanence_id=permanence.id, customer_charged_id=customer.id
permanence_id=permanence.id,
customer_invoice__customer_charged_id=customer.id
).order_by('?').exists():
to_email_customer = [customer.user.email]
if customer.email2 is not None and len(customer.email2.strip()) > 0:
......
This diff is collapsed.
# -*- coding: utf-8 -*-
from django.core.management.base import BaseCommand
from django.db.models import Sum
from repanier.models import BankAccount
from repanier.models import LUT_DeliveryPoint, DeliveryBoard
from repanier.models import CustomerInvoice, ProducerInvoice
from repanier.const import PERMANENCE_CLOSED, \
PERMANENCE_INVOICED, PERMANENCE_ARCHIVED, PERMANENCE_SEND, DECIMAL_ZERO
from repanier.const import PERMANENCE_CLOSED
from repanier.models import Permanence
from repanier.tools import reorder_offer_items, recalculate_order_amount
from repanier.task import task_invoice
from repanier.tools import recalculate_order_amount
class Command(BaseCommand):
......@@ -18,8 +10,15 @@ class Command(BaseCommand):
help = 'Recalculate permanence profit'
def handle(self, *args, **options):
for permanence in Permanence.objects.filter(status__gte=PERMANENCE_CLOSED).order_by('?'):
for permanence in Permanence.objects.filter(
# id__in=[59, 58],
status__gte=PERMANENCE_CLOSED
).order_by('?'):
print ("%s %s" % (permanence.permanence_date, permanence.get_status_display()))
# recalculate_order_amount(
# permanence_id=permanence.id,
# re_init=True
# )
permanence.recalculate_profit()
permanence.save()
......@@ -104,7 +104,7 @@ class Customer(models.Model):
verbose_name=_("delivery point"),
blank=True, null=True, default=None)
is_active = models.BooleanField(_("is_active"), default=True)
is_group = models.BooleanField(_("is_group"), default=False)
is_group = models.BooleanField(_("is a group"), default=False)
may_order = models.BooleanField(_("may_order"), default=True)
valid_email = models.NullBooleanField(_("valid_email"), default=None)
subscribe_to_email = models.BooleanField(_("subscribe to email"), default=True)
......
......@@ -120,6 +120,7 @@ class CustomerInvoice(models.Model):
related_name='child_customer_invoice',
blank=True, null=True, default=None,
on_delete=models.PROTECT, db_index=True)
is_group = models.BooleanField(_("is a group"), default=False)
def get_delta_price_with_tax(self):
return self.delta_price_with_tax.amount
......@@ -149,6 +150,14 @@ class CustomerInvoice(models.Model):
@transaction.atomic
def set_delivery(self, delivery):
# May not use delivery_id because it won't reload customer_invoice.delivery
# Important
# Si c'est une facture du membre d'un groupe :
# self.customer_charged_id != self.customer_id
# self.customer_charged_id == owner of the group
# price_list_multiplier = DECIMAL_ONE
# Si c'est une facture lambda ou d'un groupe :
# self.customer_charged_id = self.customer_id
# price_list_multiplier may vary
from repanier.apps import REPANIER_SETTINGS_TRANSPORT, REPANIER_SETTINGS_MIN_TRANSPORT
self.delivery = delivery
if delivery is None:
......@@ -190,7 +199,8 @@ class CustomerInvoice(models.Model):
price_list_multiplier=delivery_point.price_list_multiplier,
transport=delivery_point.transport,
min_transport=delivery_point.min_transport,
is_order_confirm_send=True
is_order_confirm_send=True,
is_group=True
)
@transaction.atomic
......@@ -232,11 +242,58 @@ class CustomerInvoice(models.Model):
def calculate_delta_price(self, confirm_order=False):
getcontext().rounding = ROUND_HALF_UP
if self.customer_charged is None or confirm_order:
# confirm_order : the customer confirm his/her order
self.delta_price_with_tax.amount = DECIMAL_ZERO
self.delta_vat.amount = DECIMAL_ZERO
# Important
# Si c'est une facture du membre d'un groupe :
# self.customer_charged_id == purchase.customer_charged_id != self.customer_id
# self.customer_charged_id == purchase.customer_charged_id == owner of the group
# self.price_list_multiplier = DECIMAL_ONE
# Si c'est une facture lambda ou d'un groupe :
# self.customer_charged_id == purchase.customer_charged_id = self.customer_id
# self.price_list_multiplier may vary
if self.customer_id == self.customer_charged_id:
if self.price_list_multiplier != DECIMAL_ONE:
result_set = purchase.Purchase.objects.filter(
permanence_id=self.permanence_id,
customer_invoice__customer_charged_id=self.customer_id,
is_resale_price_fixed=False
).order_by('?').aggregate(
Sum('customer_vat'),
Sum('deposit'),
Sum('selling_price')
)
if result_set["customer_vat__sum"] is not None:
total_vat = result_set["customer_vat__sum"]
else:
total_vat = DECIMAL_ZERO
if result_set["deposit__sum"] is not None:
total_deposit = result_set["deposit__sum"]
else:
total_deposit = DECIMAL_ZERO
if result_set["selling_price__sum"] is not None:
total_price_with_tax = result_set["selling_price__sum"]
else:
total_price_with_tax = DECIMAL_ZERO
total_price_with_tax_wo_deposit = total_price_with_tax - total_deposit
self.delta_price_with_tax.amount = -(
total_price_with_tax_wo_deposit - (
total_price_with_tax_wo_deposit * self.price_list_multiplier
).quantize(TWO_DECIMALS)
)
self.delta_vat.amount = -(
total_vat - (
total_vat * self.price_list_multiplier
).quantize(FOUR_DECIMALS)
)
result_set = purchase.Purchase.objects.filter(
permanence_id=self.permanence_id,
customer_id=self.customer_id,
customer_invoice__customer_charged_id=self.customer_id,
).order_by('?').aggregate(
Sum('customer_vat'),
Sum('deposit'),
......@@ -245,7 +302,7 @@ class CustomerInvoice(models.Model):
else:
result_set = purchase.Purchase.objects.filter(
permanence_id=self.permanence_id,
customer_charged_id=self.customer_id,
customer_id=self.customer_id,
).order_by('?').aggregate(
Sum('customer_vat'),
Sum('deposit'),
......@@ -264,45 +321,6 @@ class CustomerInvoice(models.Model):
else:
self.total_price_with_tax.amount = DECIMAL_ZERO
if self.price_list_multiplier != DECIMAL_ONE:
result_set = purchase.Purchase.objects.filter(
permanence_id=self.permanence_id,
customer_id=self.customer_id,
is_resale_price_fixed=True
).order_by('?').aggregate(
Sum('customer_vat'),
Sum('deposit'),
Sum('selling_price')
)
if result_set["customer_vat__sum"] is not None:
total_vat = result_set["customer_vat__sum"]
else:
total_vat = DECIMAL_ZERO
if result_set["deposit__sum"] is not None:
total_deposit = result_set["deposit__sum"]
else:
total_deposit = DECIMAL_ZERO
if result_set["selling_price__sum"] is not None:
total_price_with_tax = result_set["selling_price__sum"]
else:
total_price_with_tax = DECIMAL_ZERO
total_price_with_tax_wo_deposit = total_price_with_tax - total_deposit
self.delta_price_with_tax.amount = -(
total_price_with_tax_wo_deposit - (
total_price_with_tax_wo_deposit * self.price_list_multiplier
).quantize(TWO_DECIMALS)
)
self.delta_vat.amount = -(
total_vat - (
total_vat * self.price_list_multiplier
).quantize(FOUR_DECIMALS)
)
else:
self.delta_price_with_tax.amount = DECIMAL_ZERO
self.delta_vat.amount = DECIMAL_ZERO
def calculate_delta_transport(self):
self.delta_transport.amount = DECIMAL_ZERO
......@@ -310,7 +328,7 @@ class CustomerInvoice(models.Model):
# Calculate transport only on master customer invoice
# But take into account the children customer invoices
result_set = CustomerInvoice.objects.filter(
master_permanence=self.permanence
master_permanence_id=self.permanence_id
).order_by('?').aggregate(
Sum('total_price_with_tax'),
Sum('delta_price_with_tax')
......@@ -347,11 +365,26 @@ class CustomerInvoice(models.Model):
return False
def create_child(self, new_permanence):
if self.customer_id != self.customer_charged_id:
# TODO : Créer la customer invoice du groupe
customer_invoice = CustomerInvoice.objects.filter(
permanence_id=self.permanence_id,
customer_id=self.customer_charged_id
).only("id").order_by('?')
if not customer_invoice.exists():
customer_invoice = CustomerInvoice.objects.create(
permanence_id=self.permanence_id,
customer_id=self.customer_charged_id,
customer_charged_id=self.customer_charged_id,
status=self.status
)
customer_invoice.set_delivery(delivery=None)
customer_invoice.save()
return CustomerInvoice.objects.create(
permanence_id=new_permanence.id,
customer_id=self.customer_id,
master_permanence_id=self.permanence_id,
customer_charged_id=self.customer_id,
customer_charged_id=self.customer_charged_id,
status=self.status
)
......@@ -396,6 +429,7 @@ class CustomerInvoice(models.Model):
class ProducerInvoice(models.Model):
producer = models.ForeignKey(
'Producer', verbose_name=_("producer"),
related_name='producer_invoice',
on_delete=models.PROTECT)
permanence = models.ForeignKey(
'Permanence', verbose_name=permanence_verbose_name(),
......
......@@ -10,7 +10,6 @@ from django.db import models
from django.db.models import F, Sum
from django.utils import timezone, translation
from django.utils.encoding import python_2_unicode_compatible
from django.utils.formats import number_format
from django.utils.translation import ugettext_lazy as _
from djangocms_text_ckeditor.fields import HTMLField
from menus.menu_pool import menu_pool
......@@ -102,30 +101,22 @@ class Permanence(TranslatableModel):
blank=True
)
# Calculated with Purchase
invoiced_with_tax = ModelMoneyField(
total_purchase_with_tax = ModelMoneyField(
_("Total amount"),
help_text=_('Total purchase amount vat included'),
default=DECIMAL_ZERO, max_digits=8, decimal_places=2)
vat = ModelMoneyField(
total_selling_with_tax = ModelMoneyField(
_("Total amount"),
help_text=_('Total purchase amount vat included'),
default=DECIMAL_ZERO, max_digits=8, decimal_places=2)
total_purchase_vat = ModelMoneyField(
_("Total vat"),
help_text=_('Vat part of the total purchased'),
default=DECIMAL_ZERO, max_digits=9, decimal_places=4)
total_selling_vat = ModelMoneyField(
_("Total vat"),
help_text=_('Vat part of the total purchased'),
default=DECIMAL_ZERO, max_digits=9, decimal_places=4)
deposit = ModelMoneyField(
_("deposit"),
help_text=_('deposit to add to the original unit price'),
default=DECIMAL_ZERO, max_digits=8, decimal_places=2)
transport = ModelMoneyField(
_("Delivery point transport"),
help_text=_("transport to add"),
default=DECIMAL_ZERO, max_digits=5, decimal_places=2)
# total_price_wo_tax = ModelMoneyField(
# _("Total amount"),
# help_text=_('Total purchase amount vat excluded'),
# default=DECIMAL_ZERO, max_digits=8, decimal_places=2)
profit = ModelMoneyField(
_("Total profit"),
help_text=_('Total profit'),
default=DECIMAL_ZERO, max_digits=8, decimal_places=2)
with_delivery_point = models.BooleanField(
_("with_delivery_point"), default=False)
......@@ -294,20 +285,19 @@ class Permanence(TranslatableModel):
link = []
for ci in invoice.CustomerInvoice.objects.filter(permanence_id=self.id).select_related(
"customer").order_by('customer'):
ci_customer = ci.customer
if ci.is_order_confirm_send:
label = '%s%s (%s) %s%s' % (
"<b><i>" if ci_customer.is_group else EMPTY_STRING,
ci.customer.short_basket_name, ci.get_total_price_with_tax(customer_charged=True),
"<b><i>" if ci.is_group else EMPTY_STRING,
ci.customer.short_basket_name, "-" if ci.is_group else ci.get_total_price_with_tax(customer_charged=True),
ci.get_is_order_confirm_send_display(),
"</i></b>" if ci_customer.is_group else EMPTY_STRING,
"</i></b>" if ci.is_group else EMPTY_STRING,
)
else:
label = '%s%s (%s) %s%s' % (
"<b><i>" if ci_customer.is_group else EMPTY_STRING,
ci.customer.short_basket_name, ci.total_price_with_tax,
"<b><i>" if ci.is_group else EMPTY_STRING,
ci.customer.short_basket_name, "-" if ci.is_group else ci.total_price_with_tax,
ci.get_is_order_confirm_send_display(),
"</i></b>" if ci_customer.is_group else EMPTY_STRING,
"</i></b>" if ci.is_group else EMPTY_STRING,
)
# Important : no target="_blank"
link.append(
......@@ -318,13 +308,12 @@ class Permanence(TranslatableModel):
link = []
for ci in invoice.CustomerInvoice.objects.filter(permanence_id=self.id).select_related(
"customer").order_by('customer'):
ci_customer = ci.customer
label = "%s%s (%s) %s%s" % (
"<b><i>" if ci_customer.is_group else EMPTY_STRING,
ci_customer.short_basket_name,
"<b><i>" if ci.is_group else EMPTY_STRING,
ci.customer.short_basket_name,
ci.get_total_price_with_tax(customer_charged=True),
ci.get_is_order_confirm_send_display(),
"</i></b>" if ci_customer.is_group else EMPTY_STRING,
"</i></b>" if ci.is_group else EMPTY_STRING,
)
# Important : target="_blank" because the invoices must be displayed without the cms_toolbar
# Such that they can be accessed by the customer and by the staff
......@@ -593,63 +582,80 @@ class Permanence(TranslatableModel):
)
def recalculate_profit(self):
getcontext().rounding = ROUND_HALF_UP
result_set = invoice.CustomerInvoice.objects.filter(
permanence_id=self.id
permanence_id=self.id,
is_group=True,
).order_by('?').aggregate(
Sum('total_price_with_tax'),
Sum('delta_price_with_tax'),
Sum('total_vat'),
Sum('delta_vat'),
Sum('total_deposit'),
Sum('delta_transport')
)
if result_set["total_price_with_tax__sum"] is not None:
ci_sum_total_price_with_tax = result_set["total_price_with_tax__sum"]
else:
ci_sum_total_price_with_tax = DECIMAL_ZERO
if result_set["delta_price_with_tax__sum"] is not None:
ci_sum_delta_price_with_tax = result_set["delta_price_with_tax__sum"]
else:
ci_sum_delta_price_with_tax = DECIMAL_ZERO
if result_set["total_vat__sum"] is not None:
ci_sum_total_vat = result_set["total_vat__sum"]
else:
ci_sum_total_vat = DECIMAL_ZERO
if result_set["delta_vat__sum"] is not None:
ci_sum_delta_vat = result_set["delta_vat__sum"]
else:
ci_sum_delta_vat = DECIMAL_ZERO
if result_set["total_deposit__sum"] is not None:
ci_sum_total_deposit = result_set["total_deposit__sum"]
else:
ci_sum_total_deposit = DECIMAL_ZERO
if result_set["delta_transport__sum"] is not None:
ci_sum_delta_transport = result_set["delta_transport__sum"]
else:
ci_sum_delta_transport = DECIMAL_ZERO
self.invoiced_with_tax.amount = ci_sum_total_price_with_tax + ci_sum_delta_price_with_tax + ci_sum_delta_transport
self.vat.amount = ci_sum_total_vat + ci_sum_delta_vat
self.deposit.amount = ci_sum_total_deposit
result_set = invoice.ProducerInvoice.objects.filter(
permanence_id=self.id
result_set = purchase.Purchase.objects.filter(
permanence_id=self.id,
offer_item__price_list_multiplier__gte=DECIMAL_ONE
).order_by('?').aggregate(
Sum('total_price_with_tax'),
Sum('total_vat'),
Sum('total_deposit')
Sum('purchase_price'),
Sum('selling_price'),
Sum('producer_vat'),
Sum('customer_vat'),
)
if result_set["total_price_with_tax__sum"] is not None:
pi_sum_total_price_with_tax = result_set["total_price_with_tax__sum"]
if result_set["purchase_price__sum"] is not None:
purchase_price = result_set["purchase_price__sum"]
else:
purchase_price = DECIMAL_ZERO
if result_set["selling_price__sum"] is not None:
selling_price = result_set["selling_price__sum"]
else:
selling_price = DECIMAL_ZERO
selling_price += ci_sum_delta_price_with_tax + ci_sum_delta_transport
if result_set["producer_vat__sum"] is not None:
producer_vat = result_set["producer_vat__sum"]
else:
pi_sum_total_price_with_tax = DECIMAL_ZERO
if result_set["total_vat__sum"] is not None:
pi_sum_total_vat = result_set["total_vat__sum"]
producer_vat = DECIMAL_ZERO
if result_set["customer_vat__sum"] is not None:
customer_vat = result_set["customer_vat__sum"]
else:
pi_sum_total_vat = DECIMAL_ZERO
if result_set["total_deposit__sum"] is not None:
pi_sum_total_deposit = result_set["total_deposit__sum"]
customer_vat = DECIMAL_ZERO
customer_vat += ci_sum_delta_vat
self.total_purchase_with_tax = purchase_price
self.total_selling_with_tax = selling_price
self.total_purchase_vat = producer_vat
self.total_selling_vat = customer_vat
result_set = purchase.Purchase.objects.filter(
permanence_id=self.id,
offer_item__price_list_multiplier__lt=DECIMAL_ONE
).order_by('?').aggregate(
Sum('selling_price'),
Sum('customer_vat'),
)
if result_set["selling_price__sum"] is not None:
selling_price = result_set["selling_price__sum"]
else:
selling_price = DECIMAL_ZERO
if result_set["customer_vat__sum"] is not None: