Commit f4f1d070 authored by Patrick's avatar Patrick

Membership fee is calculated when the invoice is produced instead of

when the orders are closed and don't any more generate specific
bank account movement.
parent 136cb888
......@@ -244,9 +244,8 @@ class BankAccountFilterByStatus(SimpleListFilter):
return [
(1, _('not invoiced')),
(2, _('balance')),
(3, _('membership fees')),
(4, _('losts and profits')),
(5, _('taxes'))]
(3, _('loses and profits')),
(4, _('taxes'))]
def queryset(self, request, queryset):
value = self.value()
......@@ -259,8 +258,6 @@ class BankAccountFilterByStatus(SimpleListFilter):
elif value == "2":
return queryset.filter(permanence_id__isnull=False, customer_id__isnull=True, producer_id__isnull=True)
elif value == "3":
return queryset.filter(operation_status=BANK_MEMBERSHIP_FEE)
elif value == "4":
return queryset.filter(operation_status=BANK_PROFIT)
else:
return queryset.filter(operation_status=BANK_TAX)
......
......@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Repanier\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-04-30 04:23+0200\n"
"PO-Revision-Date: 2017-04-30 12:32+0100\n"
"POT-Creation-Date: 2017-05-01 10:05+0200\n"
"PO-Revision-Date: 2017-05-01 10:06+0100\n"
"Last-Translator: Patrick Colmant <pcolmant@gmail.com>\n"
"Language-Team: Patrick Colmant <pcolmant@gmail.com>\n"
"Language: fr\n"
......@@ -88,14 +88,10 @@ msgid "balance"
msgstr "Solde"
#: admin/admin_filter.py:247
msgid "membership fees"
msgstr "Cotisations"
#: admin/admin_filter.py:248
msgid "losts and profits"
msgid "loses and profits"
msgstr "Pertes et profits"
#: admin/admin_filter.py:249
#: admin/admin_filter.py:248
msgid "taxes"
msgstr "Taxes dues"
......@@ -1474,7 +1470,7 @@ msgstr "Commandes ouvertes"
msgid "wait for close"
msgstr "En cours de clôture"
#: const.py:74 models/deliveryboard.py:106 models/permanence.py:647
#: const.py:74 models/deliveryboard.py:106 models/permanence.py:649
msgid "orders closed"
msgstr "Commandes clôturées"
......@@ -1996,7 +1992,7 @@ msgstr "Distributions"
msgid "Distribution on "
msgstr "Distribution du "
#: models/configuration.py:407 task/task_invoice.py:339
#: models/configuration.py:407
msgid "Membership fee"
msgstr "Cotisation"
......@@ -2132,7 +2128,7 @@ msgstr "Commentaire"
msgid "delivery date"
msgstr "Date de livraison"
#: models/deliveryboard.py:37 models/permanence.py:95 models/permanence.py:579
#: models/deliveryboard.py:37 models/permanence.py:95 models/permanence.py:581
msgid "permanence_status"
msgstr "Statut"
......@@ -2639,35 +2635,35 @@ msgstr ""
msgid "No offer"
msgstr "Pas d'offre"
#: models/permanence.py:256 models/permanence.py:340 models/permanence.py:393
#: models/permanence.py:257 models/permanence.py:341 models/permanence.py:394
msgid "Show"
msgstr "Montrer"
#: models/permanence.py:256 models/permanence.py:340 models/permanence.py:393
#: models/permanence.py:257 models/permanence.py:341 models/permanence.py:394
msgid "Hide"
msgstr "Masquer"
#: models/permanence.py:266
#: models/permanence.py:267
msgid "producers in this permanence"
msgstr "Offres de"
#: models/permanence.py:344
#: models/permanence.py:345
msgid "No purchase"
msgstr "Pas d'achat"
#: models/permanence.py:346
#: models/permanence.py:347
msgid "customers in this permanence"
msgstr "Achats par"
#: models/permanence.py:397
#: models/permanence.py:398
msgid "Empty board"
msgstr "Tableau vide"
#: models/permanence.py:399 models/permanenceboard.py:28
#: models/permanence.py:400 models/permanenceboard.py:28
msgid "permanence board"
msgstr "Tableau des tâches"
#: models/permanence.py:599 models/permanence.py:604 models/permanence.py:607
#: models/permanence.py:601 models/permanence.py:606 models/permanence.py:609
#: models/producer.py:290 templates/repanier/confirm_admin_invoice.html:110
#: templates/repanier/pre_order_create_product_form.html:115
#: templates/repanier/pre_order_form.html:38
......@@ -2677,19 +2673,19 @@ msgstr "Tableau des tâches"
msgid "wo tax"
msgstr "HTVA"
#: models/permanence.py:654
#: models/permanence.py:656
msgid "order"
msgstr "Commande"
#: models/permanence.py:655
#: models/permanence.py:657
msgid "orders"
msgstr "Commandes"
#: models/permanence.py:665 models/permanence.py:666
#: models/permanence.py:667 models/permanence.py:668
msgid "In preparation"
msgstr "En préparation"
#: models/permanence.py:672 models/permanence.py:673
#: models/permanence.py:674 models/permanence.py:675
msgid "In billing"
msgstr "En facturation"
......@@ -2901,48 +2897,48 @@ msgstr " (COPIE)"
msgid "The boxes are duplicated."
msgstr "Les compositions sont dupliquées."
#: task/task_invoice.py:304
#: task/task_invoice.py:329
msgid "Profit"
msgstr "Profit"
#: task/task_invoice.py:304
#: task/task_invoice.py:329
msgid "Lost"
msgstr "Perte"
#: task/task_invoice.py:317
#: task/task_invoice.py:342
msgid "VAT to pay to the tax authorities"
msgstr "TVA à payer aux contributions"
#: task/task_invoice.py:318
#: task/task_invoice.py:343
msgid "VAT to receive from the tax authorities"
msgstr "TVA à recevoir des contributions"
#: task/task_invoice.py:363
#: task/task_invoice.py:367
msgid "Transport"
msgstr "Transport"
#: task/task_invoice.py:681 task/task_invoice.py:690
#: task/task_invoice.py:682 task/task_invoice.py:691
msgid "The selected invoice has been canceled."
msgstr "La facture a été annulée."
#: task/task_invoice.py:684 task/task_invoice.py:687
#: task/task_invoice.py:685 task/task_invoice.py:688
msgid "The selected invoice is not the latest invoice."
msgstr ""
"La permanence sélectionnée n'étant pas la dernière permanence facturée, "
"l'annulation de ses factures ne peut avoir lieu."
#: task/task_invoice.py:695
#: task/task_invoice.py:696
msgid "The selected invoice has been restored."
msgstr "L'archivage a été annulé."
#: task/task_invoice.py:698
#: task/task_invoice.py:699
#, python-format
msgid "The status of %(permanence)s prohibit you to cancel invoices."
msgstr ""
"Le status de la %(permanence)s n'est pas compatible avec l'action de "
"suppression des factures."
#: task/task_invoice.py:708
#: task/task_invoice.py:709
msgid ""
"Emails containing the invoices will be send to the customers and the "
"producers."
......@@ -2950,7 +2946,7 @@ msgstr ""
"Des ✉ reprenant le détail facturé en pièce jointe sont en train d'être "
"envoyés vers les consommateurs et les producteurs."
#: task/task_invoice.py:711
#: task/task_invoice.py:712
#, python-format
msgid "The status of %(permanence)s prohibit you to send invoices."
msgstr ""
......@@ -2979,11 +2975,11 @@ msgstr ""
msgid "The offers are being generated."
msgstr "Les commandes sont en train d'être ouvertes."
#: task/task_order.py:544
#: task/task_order.py:495
msgid "The orders are being closed."
msgstr "Les commandes sont en train d'être clôturées."
#: task/task_order.py:552
#: task/task_order.py:503
msgid "The orders are being send."
msgstr "Les commandes sont en train d'être envoyées."
......@@ -3006,7 +3002,7 @@ msgid ""
msgstr ""
"Livraisons %(current_site)s - jusqu'au %(payment_date)s (inclut). Merci!"
#: task/task_producer.py:88
#: task/task_producer.py:89
#, python-format
msgid "Correction %(producer)s"
msgstr "Correction %(producer)s"
......@@ -4708,6 +4704,9 @@ msgstr "Contrôle du stock"
msgid "Row %(row_num)d : A required column is missing."
msgstr "Ligne %(row_num)d : Une colonne requise est absente du fichier."
#~ msgid "membership fees"
#~ msgstr "Cotisations"
#~ msgid "New user"
#~ msgstr "Nouvel utilisateur ?"
......
......@@ -23,7 +23,8 @@ from repanier.tools import *
@transaction.atomic
def generate_invoice(permanence, payment_date):
initial_permanence = permanence
from repanier.apps import REPANIER_SETTINGS_MEMBERSHIP_FEE, REPANIER_SETTINGS_MEMBERSHIP_FEE_DURATION
today = timezone.now().date()
bank_account = BankAccount.objects.filter(operation_status=BANK_LATEST_TOTAL).order_by('?').first()
producer_buyinggroup = Producer.objects.filter(represent_this_buyinggroup=True).order_by('?').first()
customer_buyinggroup = Customer.objects.filter(represent_this_buyinggroup=True).order_by('?').first()
......@@ -84,8 +85,16 @@ def generate_invoice(permanence, payment_date):
)
new_customer_invoice.calculate_and_save_delta_buyinggroup()
membership_fee_product = Product.objects.filter(
order_unit=PRODUCT_ORDER_UNIT_MEMBERSHIP_FEE,
is_active=True
).order_by('?').first()
membership_fee_product.producer_unit_price = REPANIER_SETTINGS_MEMBERSHIP_FEE
# Update the prices
membership_fee_product.save()
for customer_invoice in CustomerInvoice.objects.filter(
permanence_id=permanence.id).order_by('?'):
permanence_id=permanence.id).select_related("customer").order_by('?'):
# In case of changed delivery conditions
customer_invoice.set_delivery(customer_invoice.delivery)
# Need to calculate delta_price_with_tax, delta_vat and delta_transport
......@@ -95,7 +104,30 @@ def generate_invoice(permanence, payment_date):
).order_by('?').update(
customer_charged_id=customer_invoice.customer_charged_id
)
# 4 - Add Membership fee Subscription
customer = customer_invoice.customer
if REPANIER_SETTINGS_MEMBERSHIP_FEE_DURATION > 0 and REPANIER_SETTINGS_MEMBERSHIP_FEE > 0 and not customer.represent_this_buyinggroup:
# There is a membership fee
if customer.membership_fee_valid_until < today:
membership_fee_offer_item = get_or_create_offer_item(
permanence,
membership_fee_product.id,
membership_fee_product.producer_id
)
permanence.producers.add(membership_fee_offer_item.producer_id)
create_or_update_one_purchase(
customer.id,
membership_fee_offer_item,
q_order=1,
permanence_date=permanence.permanence_date,
batch_job=True,
is_box_content=False
)
customer.membership_fee_valid_until = add_months(
customer.membership_fee_valid_until,
REPANIER_SETTINGS_MEMBERSHIP_FEE_DURATION
)
customer.save(update_fields=['membership_fee_valid_until', ])
# Important : linked to task_invoice.cancel
for delivery in DeliveryBoard.objects.filter(
......@@ -315,27 +347,6 @@ def generate_invoice(permanence, payment_date):
producer_invoice=None
)
for membership_fee in Purchase.objects.filter(
permanence_id=permanence.id,
producer_id=producer_buyinggroup.id,
offer_item__order_unit=PRODUCT_ORDER_UNIT_MEMBERSHIP_FEE
).order_by('?'):
# --> This bank movement is not a real entry
# making this, it will not be counted into the customer_buyinggroup movements twice
# because Repanier will see it has already been counted into the customer_buyinggroup movements
BankAccount.objects.create(
permanence_id=permanence.id,
producer=None,
customer_id=customer_buyinggroup.id,
operation_date=payment_date,
operation_status=BANK_MEMBERSHIP_FEE,
operation_comment="%s : %s" % (_("Membership fee"), membership_fee.customer),
bank_amount_in=membership_fee.selling_price,
bank_amount_out=DECIMAL_ZERO,
customer_invoice_id=customer_invoice_buyinggroup.id,
producer_invoice=None
)
for customer_invoice in CustomerInvoice.objects.filter(
permanence_id=permanence.id,
).exclude(
......@@ -495,9 +506,6 @@ def generate_invoice(permanence, payment_date):
producer_invoice=None
)
if permanence_partially_invoiced:
initial_permanence.set_status(PERMANENCE_SEND)
new_status = PERMANENCE_INVOICED if repanier.apps.REPANIER_SETTINGS_INVOICE else PERMANENCE_ARCHIVED
permanence.set_status(new_status, update_payment_date=True, payment_date=payment_date)
......
......@@ -309,7 +309,6 @@ def automatically_closed():
@transaction.atomic
def close_order_delivery(permanence, delivery, all_producers, producers_id=None):
from repanier.apps import REPANIER_SETTINGS_CUSTOMERS_MUST_CONFIRM_ORDERS
today = timezone.now().date()
getcontext().rounding = ROUND_HALF_UP
if REPANIER_SETTINGS_CUSTOMERS_MUST_CONFIRM_ORDERS:
# Cancel unconfirmed purchases whichever the producer is
......@@ -324,15 +323,6 @@ def close_order_delivery(permanence, delivery, all_producers, producers_id=None)
if all_producers:
# 1 - Do not round to multiple producer_order_by_quantity
# 2 - Do not add Transport
membership_fee_product = Product.objects.filter(
order_unit=PRODUCT_ORDER_UNIT_MEMBERSHIP_FEE,
is_active=True
).order_by('?').first()
membership_fee_product.producer_unit_price = repanier.apps.REPANIER_SETTINGS_MEMBERSHIP_FEE
# Update the prices
membership_fee_product.save()
membership_fee_offer_item = get_or_create_offer_item(permanence, membership_fee_product.id,
membership_fee_product.producer_id)
for customer in Customer.objects.filter(
is_active=True, may_order=True,
customerinvoice__permanence_id=permanence.id,
......@@ -341,25 +331,13 @@ def close_order_delivery(permanence, delivery, all_producers, producers_id=None)
represent_this_buyinggroup=False
).order_by('?'):
# 3 - Add Deposit
for offer_item in OfferItem.objects.filter(permanence_id=permanence.id, # is_active=False,
order_unit=PRODUCT_ORDER_UNIT_DEPOSIT).order_by('?'):
permanence.producers.add(offer_item.producer_id)
for offer_item in OfferItem.objects.filter(
permanence_id=permanence.id,
order_unit=PRODUCT_ORDER_UNIT_DEPOSIT
).order_by('?'):
create_or_update_one_purchase(customer.id, offer_item, q_order=1, permanence_date=permanence.permanence_date, batch_job=True, is_box_content=False)
create_or_update_one_purchase(customer.id, offer_item, q_order=0, permanence_date=permanence.permanence_date, batch_job=True, is_box_content=False)
# 4 - Add Membership fee Subscription
if repanier.apps.REPANIER_SETTINGS_MEMBERSHIP_FEE_DURATION > 0:
# There is a membership fee
if customer.membership_fee_valid_until < today:
permanence.producers.add(membership_fee_offer_item.producer_id)
create_or_update_one_purchase(customer.id, membership_fee_offer_item, q_order=1,
permanence_date=permanence.permanence_date,
batch_job=True,
is_box_content=False)
customer.membership_fee_valid_until = add_months(
customer.membership_fee_valid_until,
repanier.apps.REPANIER_SETTINGS_MEMBERSHIP_FEE_DURATION
)
customer.save(update_fields=['membership_fee_valid_until', ])
delivery.set_status(PERMANENCE_CLOSED, all_producers, producers_id)
......@@ -367,8 +345,6 @@ def close_order_delivery(permanence, delivery, all_producers, producers_id=None)
def close_order(permanence, all_producers, producers_id=None):
from repanier.apps import REPANIER_SETTINGS_CUSTOMERS_MUST_CONFIRM_ORDERS
getcontext().rounding = ROUND_HALF_UP
today = timezone.now().date()
if REPANIER_SETTINGS_CUSTOMERS_MUST_CONFIRM_ORDERS:
# Cancel unconfirmed purchases whichever the producer is
customer_invoice_qs = CustomerInvoice.objects.filter(
......@@ -411,17 +387,6 @@ def close_order(permanence, all_producers, producers_id=None):
create_or_update_one_purchase(buying_group.id, offer_item, q_order=1,
permanence_date=permanence.permanence_date,
batch_job=True, is_box_content=False)
membership_fee_product = Product.objects.filter(
order_unit=PRODUCT_ORDER_UNIT_MEMBERSHIP_FEE,
is_active=True
).order_by('?').first()
membership_fee_product.producer_unit_price = repanier.apps.REPANIER_SETTINGS_MEMBERSHIP_FEE
# Update the prices
membership_fee_product.save()
membership_fee_offer_item = get_or_create_offer_item(
permanence, membership_fee_product.id,
membership_fee_product.producer_id
)
for customer in Customer.objects.filter(
is_active=True,
may_order=True,
......@@ -439,21 +404,7 @@ def close_order(permanence, all_producers, producers_id=None):
for offer_item in offer_item_qs:
create_or_update_one_purchase(customer.id, offer_item, q_order=1, permanence_date=permanence.permanence_date, batch_job=True, is_box_content=False)
create_or_update_one_purchase(customer.id, offer_item, q_order=0, permanence_date=permanence.permanence_date, batch_job=True, is_box_content=False)
# 4 - Add Add Membership fee Subscription
if repanier.apps.REPANIER_SETTINGS_MEMBERSHIP_FEE_DURATION > 0:
# There is a membership fee
if customer.membership_fee_valid_until < today:
permanence.producers.add(membership_fee_offer_item.producer_id)
create_or_update_one_purchase(customer.id, membership_fee_offer_item, q_order=1, permanence_date=permanence.permanence_date, batch_job=True, is_box_content=False)
while customer.membership_fee_valid_until < today:
# Do not pay the membership fee if no order passed during a certain amount of time
customer.membership_fee_valid_until = add_months(
customer.membership_fee_valid_until,
repanier.apps.REPANIER_SETTINGS_MEMBERSHIP_FEE_DURATION
)
customer.save(update_fields=['membership_fee_valid_until', ])
# 5 - Add Common participation Subscription
if all_producers:
permanence.set_status(PERMANENCE_CLOSED, allow_downgrade=False)
if not repanier.apps.REPANIER_SETTINGS_INVOICE and repanier.apps.REPANIER_SETTINGS_BANK_ACCOUNT is None:
......
......@@ -85,42 +85,23 @@ def admin_generate_bank_account_movement(
delta = (producer.balance.amount - producer_invoice.to_be_invoiced_balance.amount).quantize(TWO_DECIMALS)
if delta != DECIMAL_ZERO:
# Profit or loss for the group
operation_comment = _("Correction %(producer)s") \
% {
'producer': producer.short_profile_name
}
if delta > DECIMAL_ZERO:
# Profit for the group : the producer ask less than what is sold
# --> This bank movement is not a real entry
# operation_status=BANK_PROFIT
# making this, it will not be removed from the new calculated bank account total
BankAccount.objects.create(
permanence_id=permanence.id,
producer=None,
customer_id=customer_buyinggroup.id,
operation_date=payment_date,
operation_status=BANK_PROFIT,
operation_comment=cap(operation_comment, 100),
bank_amount_in=delta,
customer_invoice_id=None,
producer_invoice=None
)
elif delta < DECIMAL_ZERO:
# Loss for the group : the producer ask more than what is sold
# --> This bank movement is not a real entry
# operation_status=BANK_PROFIT
# making this, it will not be removed from the new calculated bank account total
BankAccount.objects.create(
permanence_id=permanence.id,
producer=None,
customer_id=customer_buyinggroup.id,
operation_date=payment_date,
operation_status=BANK_PROFIT,
operation_comment=cap(operation_comment, 100),
bank_amount_out=-delta,
customer_invoice_id=None,
producer_invoice=None
)
BankAccount.objects.create(
permanence_id=permanence.id,
producer=None,
customer_id=customer_buyinggroup.id,
operation_date=payment_date,
operation_status=BANK_PROFIT,
operation_comment=cap(operation_comment, 100),
bank_amount_in=delta if delta > DECIMAL_ZERO else DECIMAL_ZERO,
bank_amount_out=-delta if delta < DECIMAL_ZERO else DECIMAL_ZERO,
customer_invoice_id=None,
producer_invoice=None
)
producer_invoice.balance.amount -= delta
producer_invoice.save(update_fields=['balance'])
producer.balance.amount -= delta
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment