Commit 1cbb1ca9 authored by Patrick's avatar Patrick
Browse files

Version 1.7

parent 8fe68081
# -*- coding: utf-8
from __future__ import unicode_literals
default_app_config = 'repanier.apps.RepanierConfig'
\ No newline at end of file
# -*- coding: utf-8 -*-
# -*- coding: utf-8
from __future__ import unicode_literals
from collections import OrderedDict
import uuid
from django.forms import Textarea
from django.utils.timezone import utc
import parler
from fkey_choice_cache_mixin import ForeignKeyCacheMixin
from widget import SelectAdminOrderUnitWidget, PreviewProductOrderWidget
try:
from urllib.parse import parse_qsl
......@@ -12,22 +19,23 @@ from admin_filter import *
from django.contrib import admin
from django.contrib import messages
from django.contrib.auth import get_user_model
from django.contrib.auth.models import User
import datetime
from django.utils.translation import ugettext_lazy as _
from django.utils import translation
from django.core import validators
from django.db.models import Q, F
from django import forms
from django.shortcuts import get_object_or_404
from django.db import transaction
from django_mptt_admin.admin import DjangoMpttAdmin
from parler.admin import TranslatableAdmin, TranslatableModelForm
from models import LUT_ProductionMode
from models import LUT_ProductionMode, OfferItemSend, PurchaseClosedForUpdate, \
PurchaseOpenedForUpdate, CustomerSend, OfferItemClosed, CustomerInvoice, ProducerInvoice
from models import Configuration
from models import LUT_DepartmentForCustomer
from models import LUT_PermanenceRole
from models import LUT_DeliveryPoint
from models import Producer
from models import Permanence
......@@ -47,6 +55,7 @@ from xslx import xslx_order
from xslx import xslx_product
from xslx import xslx_invoice
from xslx import xslx_purchase
from xslx import xslx_stock
from menus.menu_pool import menu_pool
......@@ -56,34 +65,6 @@ from task import task_product
from task import task_purchase
# Filters in the right sidebar of the change list page of the admin
class ReadOnlyAdmin(admin.ModelAdmin):
# ModelAdmin with ReadOnly
def save_model(self, request, obj, form, change):
if request.user.groups.filter(name=READ_ONLY_GROUP).count() == 0:
obj.save()
return super(ReadOnlyAdmin, self).save_model(request, obj, form, change)
def has_add_permission(self, request):
if request.user.groups.filter(name=READ_ONLY_GROUP).count() != 0:
return False
return super(ReadOnlyAdmin, self).has_add_permission(request)
def has_delete_permission(self, request, obj=None):
if request.user.groups.filter(name=READ_ONLY_GROUP).count() != 0:
return False
return super(ReadOnlyAdmin, self).has_delete_permission(request, obj=obj)
def get_actions(self, request):
actions = super(ReadOnlyAdmin, self).get_actions(request)
if request.user.groups.filter(name=READ_ONLY_GROUP).count() != 0:
actions_copied = actions.copy()
for key in actions_copied:
if key not in ['export_xlsx', 'export_xlsx_offer', 'export_xlsx_order']:
del actions[key]
return actions
# LUT
class LUTProductionModeAdmin(TranslatableAdmin, DjangoMpttAdmin):
# fields = [
......@@ -99,6 +80,16 @@ class LUTProductionModeAdmin(TranslatableAdmin, DjangoMpttAdmin):
admin.site.register(LUT_ProductionMode, LUTProductionModeAdmin)
class LUTDeliveryPointAdmin(TranslatableAdmin, DjangoMpttAdmin):
list_display = ('short_name', 'is_active')
list_display_links = ('short_name',)
list_per_page = 17
list_max_show_all = 17
admin.site.register(LUT_DeliveryPoint, LUTDeliveryPointAdmin)
class LUTDepartmentForCustomerAdmin(TranslatableAdmin, DjangoMpttAdmin):
list_display = ('short_name', 'is_active')
list_display_links = ('short_name',)
......@@ -119,30 +110,80 @@ class LUTPermanenceRoleAdmin(TranslatableAdmin, DjangoMpttAdmin):
admin.site.register(LUT_PermanenceRole, LUTPermanenceRoleAdmin)
class ProducerAdmin(ReadOnlyAdmin):
fields = [
('short_profile_name', 'long_profile_name', 'language'),
('email', 'fax'),
('phone1', 'phone2',),
('price_list_multiplier', 'vat_level'),
('initial_balance', 'date_balance', 'balance'),
('invoice_by_basket', 'represent_this_buyinggroup', 'limit_to_alert_order_quantity'),
'address',
'is_active']
readonly_fields = (
'date_balance',
'balance',
)
def create__producer_action(year):
def action(modeladmin, request, queryset):
queryset = queryset.order_by()
return xslx_purchase.admin_export_in(year, queryset)
# user_message = _("Action performed.")
# user_message_level = messages.INFO
# modeladmin.message_user(request, user_message, user_message_level)
name = "export_producer_%d" % (year,)
return (name, (action, name, _("Export purchases of %s") % (year,)))
class ConfigurationAdmin(TranslatableAdmin):
fieldsets = [
(None, {
'fields':
(('test_mode', 'group_name', 'name'),
'display_anonymous_order_form',
('display_producer_on_order_form', 'max_week_wo_participation'),
('display_vat', 'invoice', 'bank_account', 'vat_id')),
}),
(_('Opening mails'), {
'classes': ('collapse',),
'fields':
(
'send_opening_mail_to_customer', 'offer_customer_mail',
),
}),
(_('Ordering mails'), {
'classes': ('collapse',),
'fields':
(
'send_order_mail_to_customer', 'order_customer_mail',
'send_order_mail_to_producer', 'order_producer_mail',
'send_order_mail_to_board', 'order_staff_mail',
),
}),
(_('Invoicing mails'), {
'classes': ('collapse',),
'fields':
(
'send_invoice_mail_to_customer', 'invoice_customer_mail',
'send_invoice_mail_to_producer', 'invoice_producer_mail',
# 'invoice_staff_mail',
),
}),
(_('Advanced options'), {
'classes': ('collapse',),
'fields':
(('accept_child_group', 'delivery_point'),
'page_break_on_customer_check',
('stock', 'producer_order_rounded',),
'producer_pre_opening', 'offer_producer_mail'),
}),
]
def get_readonly_fields(self, request, configuration=None):
permanence = Permanence.objects.all().order_by().first()
if permanence is None:
return []
else:
return ['bank_account']
admin.site.register(Configuration, ConfigurationAdmin)
class ProducerAdmin(admin.ModelAdmin):
search_fields = ('short_profile_name', 'email')
list_display = (
'short_profile_name', 'get_products', 'get_balance', 'phone1', 'email', 'represent_this_buyinggroup',
'is_active')
list_per_page = 17
list_max_show_all = 17
actions = [
'export_xlsx',
'import_xlsx'
]
list_filter = ('is_active', 'invoice_by_basket', 'manage_stock', 'is_resale_price_fixed')
actions = ['export_xlsx', 'import_xlsx', 'recalculate_prices']
def export_xlsx(self, request, queryset):
return xslx_product.admin_export(request, queryset)
......@@ -150,10 +191,94 @@ class ProducerAdmin(ReadOnlyAdmin):
export_xlsx.short_description = _("Export products of selected producer(s) as XSLX file")
def import_xlsx(self, request, queryset):
return xslx_product.admin_import(self, admin, request, queryset)
return xslx_product.admin_import(self, admin, request, queryset, action='import_xlsx')
import_xlsx.short_description = _("Import products of selected producer(s) from a XLSX file")
def recalculate_prices(self, request, queryset):
for producer in queryset:
for product in Product.objects.filter(producer_id=producer.id).order_by():
product.save()
for permanence in Permanence.objects.filter(
status__in=[PERMANENCE_CLOSED, PERMANENCE_SEND]
):
offer_item_queryset = OfferItem.objects\
.filter(
permanence_id=permanence.id,
product_id=product.id,
is_active=True
).order_by()
clean_offer_item(permanence, offer_item_queryset, reorder=False)
recalculate_order_amount(permanence_id=permanence.id,
permanence_status=permanence.status,
offer_item_queryset=offer_item_queryset,
send_to_producer=False)
self.message_user(request, _("The prices have been recalculated."), level=messages.INFO)
recalculate_prices.short_description = _('recalculate prices')
def get_actions(self, request):
actions = super(ProducerAdmin, self).get_actions(request)
this_year = datetime.datetime.utcnow().replace(tzinfo=utc).year
actions.update(OrderedDict(create__producer_action(y) for y in [this_year, this_year-1, this_year-2]))
return actions
def get_list_display(self, request):
if repanier_settings['STOCK']:
return ('short_profile_name', 'get_products', 'get_balance', 'phone1', 'email', 'manage_stock', 'is_active')
else:
return ('short_profile_name', 'get_products', 'get_balance', 'phone1', 'email', 'is_active')
def get_fields(self, request, producer=None):
fields = [
('short_profile_name', 'long_profile_name', 'language'),
('email', 'fax'),
('phone1', 'phone2',)
]
if repanier_settings['DISPLAY_VAT']:
fields += [
('price_list_multiplier', 'producer_price_are_wo_vat', 'is_resale_price_fixed', 'vat_level'),
]
else:
fields += [
('price_list_multiplier', 'is_resale_price_fixed'),
]
if repanier_settings['STOCK']:
fields += [
('invoice_by_basket', 'manage_stock',),
]
else:
fields += [
('invoice_by_basket',),
]
fields += [
('address', 'memo'),
]
if repanier_settings['INVOICE']:
fields += [
('initial_balance', 'date_balance', 'balance', 'represent_this_buyinggroup'),
]
fields += [
('is_active', 'uuid')
]
return fields
def get_readonly_fields(self, request, producer=None):
if repanier_settings['INVOICE']:
if producer is not None:
producer_invoice = ProducerInvoice.objects.filter(producer_id=producer.id).order_by().first()
if producer_invoice is not None:
# Do not modify the initial balance, an invoice already exist
return ['represent_this_buyinggroup', 'date_balance', 'balance', 'uuid', 'initial_balance']
else:
return ['represent_this_buyinggroup', 'date_balance', 'balance', 'uuid']
else:
return ['uuid',]
return ['represent_this_buyinggroup', 'date_balance', 'balance', 'uuid']
else:
return ['represent_this_buyinggroup', 'uuid',]
admin.site.register(Producer, ProducerAdmin)
......@@ -169,179 +294,242 @@ class UserDataForm(forms.ModelForm):
'invalid')
])
email = forms.EmailField(label=_('Email'))
first_name = forms.CharField(label=_('First_name'), max_length=30)
last_name = forms.CharField(label=_('Last_name'), max_length=30)
user = None
read_only = True
def __init__(self, *args, **kwargs):
super(UserDataForm, self).__init__(*args, **kwargs)
# self.user = None
# self.read_only = True
def error(self, field, msg):
if field not in self._errors:
self._errors[field] = self.error_class([msg])
def clean(self, *args, **kwargs):
cleaned_data = super(UserDataForm, self).clean(*args, **kwargs)
def clean_phone1(self):
# do something that validates your data
i = 0
k = 0
phone1 = self.cleaned_data['phone1']
while i < len(phone1):
if '0' <= phone1[i] <= '9':
k += 1
if k == 4:
break
i += 1
# print ('----------------------')
# print k
if k < 4:
self.add_error(
'phone1',
_('The phone number must ends with 4 digits, eventually separated'))
return phone1
def clean(self):
cleaned_data = super(UserDataForm, self).clean()
# The Staff has no first_name or last_name because it's a function with login/pwd.
# A Customer with a first_name and last_name is responsible of this function.
customer_form = 'short_basket_name' in self.fields
if any(self.errors):
if 'first_name' in self._errors:
del self._errors['first_name']
self.data['first_name'] = self.fields['first_name'].initial
if 'last_name' in self._errors:
del self._errors['last_name']
self.data['last_name'] = self.fields['last_name'].initial
is_customer_form = 'short_basket_name' in self.fields
is_staff_form = not is_customer_form
username_field_name = 'username'
initial_username = None
try:
initial_username = self.instance.user.username
except:
pass
if customer_form:
if is_customer_form:
# Customer
username_field_name = 'short_basket_name'
# initial_username = self.fields[username_field_name].initial
username = self.cleaned_data.get(username_field_name)
user_error1 = _('The given username must be set')
user_error2 = _('The given username is used by another user')
if customer_form:
if is_customer_form:
user_error1 = _('The given short_basket_name must be set')
user_error2 = _('The given short_basket_name is used by another user')
if 'username' in self._errors:
del self._errors['username']
self.data['username'] = username
if not username:
self.error(username_field_name, user_error1)
self.add_error(username_field_name, user_error1)
# Check that the email is set
email = self.cleaned_data.get("email")
if not email:
self.error('email', _('The given email must be set'))
# Check that the email is not already used
user = None
email = User.objects.normalize_email(email)
if email:
# Only if a email is given
try:
user = User.objects.get(email=email)
except User.DoesNotExist:
pass
# Check that the username is not already used
if user is not None:
if initial_username != user.username:
self.error('email', _('The given email is used by another user'))
user = None
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
pass
if user is not None:
if initial_username != user.username:
self.error(username_field_name, user_error2)
if not "email" in self.cleaned_data:
self.add_error('email', _('The given email must be set'))
else:
email = self.cleaned_data["email"]
if is_staff_form:
is_reply_to_order_email = self.cleaned_data["is_reply_to_order_email"]
is_reply_to_invoice_email = self.cleaned_data["is_reply_to_invoice_email"]
if is_reply_to_order_email or is_reply_to_invoice_email:
allowed_mail_extension = get_allowed_mail_extension()
if not email.endswith(allowed_mail_extension):
self.add_error(
'email',
_('The given email must end with %(allowed_extension)s') %
{'allowed_extension': allowed_mail_extension}
)
user_model = get_user_model()
user = user_model.objects.filter(email=email).order_by("id").first()
# Check that the username is not already used
if user is not None:
if initial_username != user.username:
self.add_error('email', _('The given email is used by another user'))
user = user_model.objects.filter(username=username).order_by("id").first()
if user is not None:
if initial_username != user.username:
self.add_error(username_field_name, user_error2)
return cleaned_data
def save(self, *args, **kwargs):
super(UserDataForm, self).save(*args, **kwargs)
change = (self.instance.id is not None)
username = self.data['username']
email = self.data['email']
# password = self.data['password1']
first_name = self.data['first_name']
last_name = self.data['last_name']
user = None
if not self.read_only:
# Update allowed, this is not a read only user
if change:
user = User.objects.get(id=self.instance.user_id)
user.username = username
user.email = email
user.first_name = first_name
user.last_name = last_name
# if password:
# user.set_password(password)
user.save()
else:
user = User.objects.create_user(
username=username, email=email, password=uuid.uuid1().hex,
first_name=first_name, last_name=last_name)
email = self.data['email'].lower()
user_model = get_user_model()
if change:
user = user_model.objects.get(id=self.instance.user_id)
user.username = username
user.email = email
user.save()
else:
user = user_model.objects.create_user(
username=username, email=email, password=uuid.uuid1().hex,
first_name="", last_name=username)
self.user = user
return self.instance
# Customer
class CustomerWithUserDataForm(UserDataForm):
class Meta:
widgets = {
'address': Textarea(attrs={'rows': 4, 'cols': 80}),
'memo': Textarea(attrs={'rows': 4, 'cols': 80}),
}
model = Customer
fields = "__all__"
class CustomerWithUserDataAdmin(ReadOnlyAdmin):
class CustomerWithUserDataAdmin(admin.ModelAdmin):
form = CustomerWithUserDataForm
fields = [
('short_basket_name', 'long_basket_name', 'language'),
('email', 'email2'),
('phone1', 'phone2'),
'address', 'vat_id',
('initial_balance', 'date_balance', 'balance'),
('represent_this_buyinggroup', 'may_order', 'is_active')
]
readonly_fields = (
'date_balance',
'balance',
)
search_fields = ('short_basket_name', 'user__email', 'email2')
list_display = (
'__unicode__', 'get_balance', 'may_order', 'phone1', 'phone2', 'get_email', 'email2',
'represent_this_buyinggroup')
'short_basket_name', 'get_balance', 'may_order', 'long_basket_name', 'phone1', 'get_email',
'get_last_login')
search_fields = ('short_basket_name', 'long_basket_name', 'user__email', 'email2')
list_per_page = 17
list_max_show_all = 17
list_filter = ('is_active',
'may_order',
'delivery_point')
def get_email(self, obj):
if obj.user:
return '%s' % (obj.user.email)
def get_email(self, customer):
if customer.user is not None:
return customer.user.email
else:
return ''
get_email.short_description = _("email")
get_email.admin_order_field = 'user__email'
def get_form(self, request, obj=None, **kwargs):
form = super(CustomerWithUserDataAdmin, self).get_form(request, obj, **kwargs)
def get_date_joined(self, customer):
if customer.user is not None:
return customer.user.date_joined.strftime('%d-%m-%Y')
else:
return ''
get_date_joined.short_description = _("date joined")
def get_last_login(self, customer):
if customer.user is not None:
return customer.user.last_login.strftime('%d-%m-%Y')
else:
return ''
get_last_login.short_description = _("last login")
get_last_login.admin_order_field = 'user__last_login'
def get_fields(self, request, customer=None):
fields = [
('short_basket_name', 'long_basket_name', 'language'),
('email', 'email2', 'accept_mails_from_members'),
('phone1', 'phone2', 'accept_phone_call_from_members'),
]
if repanier_settings['INVOICE']:
if repanier_settings['DELIVERY_POINT']:
fields += [
('delivery_point', 'vat_id'),
]
else:
fields += [
('vat_id',),
]
elif repanier_settings['DELIVERY_POINT']:
fields += [
('delivery_point',),
]
fields += [
('address', 'city'),
'memo',
]
if repanier_settings['INVOICE']:
if customer is not None:
customer_invoice = CustomerInvoice.objects.filter(customer_id=customer.id).order_by().first()
if customer_invoice is not None:
# Do not modify the initial balance, an invoice already exist
fields += [
('date_balance', 'balance', 'represent_this_buyinggroup'),
]
else:
fields += [
('initial_balance', 'represent_this_buyinggroup'),
]
else:
fields += [
('initial_balance',),
]
fields += [
('may_order', 'is_active'),
('get_last_login', 'get_date_joined')
]
return fields
def get_readonly_fields(self, request, customer=None):
if repanier_settings['INVOICE']:
if customer is not None:
customer_invoice = CustomerInvoice.objects.filter(customer_id=customer.id).order_by().first()