admin.py 58.1 KB
Newer Older
Patrick Colmant's avatar
Patrick Colmant committed
1
# -*- coding: utf-8 -*-
2
import re
pi's avatar
pi committed
3
import uuid
Patrick's avatar
Patrick committed
4 5 6 7 8
import thread
try:
    from urllib.parse import parse_qsl
except ImportError:
    from urlparse import parse_qsl
9

Patrick Colmant's avatar
Patrick Colmant committed
10
from const import *
pi's avatar
pi committed
11
from tools import *
Patrick Colmant's avatar
Patrick Colmant committed
12
from django.conf import settings
13
from django.conf.urls import patterns, url
Patrick Colmant's avatar
Patrick Colmant committed
14
from django.contrib import admin
Patrick's avatar
Patrick committed
15
from django.contrib import messages
Patrick Colmant's avatar
Patrick Colmant committed
16
from django.contrib.auth import get_user_model
17
from django.contrib.auth.models import User
18
from django.core import urlresolvers
Patrick's avatar
Patrick committed
19
import datetime
Patrick's avatar
Patrick committed
20
from django.utils import timezone
Patrick's avatar
Patrick committed
21 22
from django.utils.timezone import utc
from django import forms
23 24

from django.http import HttpResponse
Patrick Colmant's avatar
Patrick Colmant committed
25
from django.utils.translation import ugettext_lazy as _
Patrick's avatar
Patrick committed
26
from django.utils.http import urlencode
27 28 29
from django.core import validators
from django.core.exceptions import ValidationError
from django.db import models
Patrick Colmant's avatar
Patrick Colmant committed
30
from django.db.models import Q, F
31
from django import forms
pi's avatar
pi committed
32
from django.contrib.sites.models import get_current_site
Patrick's avatar
Patrick committed
33
from django.shortcuts import get_object_or_404
34

pi's avatar
pi committed
35
# from adminsortable.admin import SortableAdminMixin
Patrick's avatar
Patrick committed
36
# from repanier.adminsortable import SortableAdminMixin
Patrick Colmant's avatar
Patrick Colmant committed
37 38 39 40

from repanier.models import LUT_ProductionMode
from repanier.models import LUT_DepartmentForCustomer
from repanier.models import LUT_PermanenceRole
Patrick Colmant's avatar
Patrick Colmant committed
41 42

from repanier.models import Producer
43
from repanier.models import Permanence
Patrick Colmant's avatar
Patrick Colmant committed
44
from repanier.models import Customer
pi's avatar
pi committed
45
from repanier.models import Staff
Patrick Colmant's avatar
Patrick Colmant committed
46
from repanier.models import Product
Patrick Colmant's avatar
Patrick Colmant committed
47 48
from repanier.models import PermanenceBoard
from repanier.models import OfferItem
Patrick's avatar
Patrick committed
49
from repanier.models import CustomerOrder
Patrick Colmant's avatar
Patrick Colmant committed
50 51
from repanier.models import PermanenceInPreparation
from repanier.models import PermanenceDone
Patrick Colmant's avatar
Patrick Colmant committed
52
from repanier.models import Purchase
Patrick Colmant's avatar
Patrick Colmant committed
53
from repanier.models import BankAccount
pi's avatar
pi committed
54 55
from repanier.models import CustomerInvoice
from repanier.models import ProducerInvoice
Patrick's avatar
Patrick committed
56
from repanier.views import render_response
pi's avatar
pi committed
57 58

from repanier.admin_export_xlsx import export_permanence_planified_xlsx
Patrick's avatar
Patrick committed
59
from repanier.admin_export_xlsx import export_orders_xlsx
pi's avatar
pi committed
60
from repanier.admin_export_xlsx import export_product_xlsx
Patrick's avatar
Patrick committed
61
from repanier.admin_export_xlsx import export_invoices_xlsx
pi's avatar
pi committed
62 63 64
from repanier.admin_export_xlsx import export_permanence_done_xlsx
from repanier.admin_import_xlsx import import_product_xlsx
from repanier.admin_import_xlsx import import_permanence_done_xlsx
Patrick's avatar
Patrick committed
65 66
# from repanier.admin_export_docx import export_mymodel_docx
from repanier.admin_send_mail import send_alert_email
pi's avatar
pi committed
67 68 69 70

from menus.base import Menu, NavigationNode
from menus.menu_pool import menu_pool

Patrick's avatar
Patrick committed
71
from repanier import tasks
Patrick Colmant's avatar
Patrick Colmant committed
72 73 74 75

# Filters in the right sidebar of the change list page of the admin
from django.contrib.admin import SimpleListFilter

pi's avatar
pi committed
76
class ProductFilterByProducer(SimpleListFilter):
77 78
	# Human-readable title which will be displayed in the
	# right admin sidebar.
Patrick Colmant's avatar
Patrick Colmant committed
79
	title = _("producers")
80
	# Parameter for the filter that will be used in the URL query.
pi's avatar
pi committed
81
	parameter_name = 'producer'
Patrick Colmant's avatar
Patrick Colmant committed
82 83 84 85 86 87 88 89 90

	def lookups(self, request, model_admin):
		"""
		Returns a list of tuples. The first element in each
		tuple is the coded value for the option that will
		appear in the URL query. The second element is the
		human-readable name for the option that will appear
		in the right sidebar.
		"""
pi's avatar
pi committed
91
		# This list is a collection of producer.id, .name
Patrick Colmant's avatar
Patrick Colmant committed
92
		return [(c.id, c.short_profile_name) for c in 
pi's avatar
pi committed
93
			Producer.objects.all().active()
94
			]
Patrick Colmant's avatar
Patrick Colmant committed
95 96 97 98 99 100 101 102 103

	def queryset(self, request, queryset):
		"""
		Returns the filtered queryset based on the value
		provided in the query string and retrievable via
		`self.value()`.
		"""
		# This query set is a collection of products
		if self.value():
pi's avatar
pi committed
104
			return queryset.producer_is(self.value())
Patrick Colmant's avatar
Patrick Colmant committed
105 106 107
		else:
			return queryset

Patrick's avatar
Patrick committed
108 109 110
class ProductFilterByDepartmentForThisProducer(SimpleListFilter):
	title = _("departments for customer")
	parameter_name = 'department_for_customer'
Patrick Colmant's avatar
Patrick Colmant committed
111 112

	def lookups(self, request, model_admin):
Patrick's avatar
Patrick committed
113 114 115 116 117 118 119 120 121
		producer = request.GET.get('producer')
		if producer:
			inner_qs = Product.objects.all().active().producer_is(
				producer).order_by().distinct(
				'department_for_customer__id')
		else:
			inner_qs = Product.objects.all().active().order_by().distinct(
				'department_for_customer__id')

Patrick Colmant's avatar
Patrick Colmant committed
122
		return [(c.id, c.short_name) for c in 
Patrick's avatar
Patrick committed
123
			LUT_DepartmentForCustomer.objects.all().active().filter(product__in=inner_qs)
124
			]
Patrick Colmant's avatar
Patrick Colmant committed
125 126 127 128

	def queryset(self, request, queryset):
		# This query set is a collection of products
		if self.value():
Patrick's avatar
Patrick committed
129
			return queryset.department_for_customer_is(self.value())
Patrick Colmant's avatar
Patrick Colmant committed
130 131 132
		else:
			return queryset

Patrick's avatar
Patrick committed
133 134 135
class PurchaseFilterByCustomerForThisPermanence(SimpleListFilter):
	title = _("customer")
	parameter_name = 'customer'
136 137

	def lookups(self, request, model_admin):
Patrick's avatar
Patrick committed
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
		permanence = request.GET.get('permanence')
		if permanence:
			return [(c.id, c.short_basket_name) for c in 
				Customer.objects.filter(purchase__permanence_id=permanence).distinct()
				]
		else:
			return [(c.id, c.short_basket_name) for c in 
				Customer.objects.all().may_order()
				]

	def queryset(self, request, queryset):
		# This query set is a collection of permanence
		if self.value():
			return queryset.customer(self.value())
		else:
			return queryset

class PurchaseFilterByProducerForThisPermanence(SimpleListFilter):
	title = _("producer")
	parameter_name = 'producer'
158

Patrick's avatar
Patrick committed
159 160 161 162 163 164 165 166 167 168
	def lookups(self, request, model_admin):
		permanence = request.GET.get('permanence')
		if permanence:
			return [(c.id, c.short_profile_name) for c in 
				Producer.objects.filter(permanence=permanence).distinct()
				]
		else:
			return [(c.id, c.short_profile_name) for c in 
				Producer.objects.all().active()
				]
169 170

	def queryset(self, request, queryset):
Patrick's avatar
Patrick committed
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
		# This query set is a collection of permanence
		if self.value():
			return queryset.producer(self.value())
		else:
			return queryset

class PurchaseFilterByPermanence(SimpleListFilter):
	title = _("permanences")
	parameter_name = 'permanence'

	def lookups(self, request, model_admin):
		# This list is a collection of permanence.id, .name
		return [(c.id, c.__unicode__()) for c in 
			Permanence.objects.filter(status__in=[PERMANENCE_OPENED, PERMANENCE_SEND])
			]

	def queryset(self, request, queryset):
		# This query set is a collection of permanence
		if self.value():
			return queryset.permanence(self.value())
191
		else:
Patrick's avatar
Patrick committed
192 193
			return queryset

194

Patrick Colmant's avatar
Patrick Colmant committed
195 196 197 198
# LUT
class LUT_ProductionModeAdmin(admin.ModelAdmin):
	list_display = ('short_name', 'is_active')
	list_display_links = ('short_name',)
Patrick's avatar
Patrick committed
199 200
	list_per_page = 17
	list_max_show_all = 17
Patrick Colmant's avatar
Patrick Colmant committed
201 202 203 204 205 206

admin.site.register(LUT_ProductionMode, LUT_ProductionModeAdmin)

class LUT_DepartmentForCustomerAdmin(admin.ModelAdmin):
	list_display = ('short_name', 'is_active')
	list_display_links = ('short_name',)
Patrick's avatar
Patrick committed
207 208
	list_per_page = 17
	list_max_show_all = 17
Patrick Colmant's avatar
Patrick Colmant committed
209 210 211 212 213 214

admin.site.register(LUT_DepartmentForCustomer, LUT_DepartmentForCustomerAdmin)

class LUT_PermanenceRoleAdmin(admin.ModelAdmin):
	list_display = ('short_name', 'is_active')
	list_display_links = ('short_name',)
Patrick's avatar
Patrick committed
215 216
	list_per_page = 17
	list_max_show_all = 17
Patrick Colmant's avatar
Patrick Colmant committed
217 218 219

admin.site.register(LUT_PermanenceRole, LUT_PermanenceRoleAdmin)

pi's avatar
pi committed
220 221
class ProducerAdmin(admin.ModelAdmin):
	fields = [ 
Patrick's avatar
Patrick committed
222 223 224
		('short_profile_name', 'long_profile_name'),
		('email', 'fax'),
		('phone1', 'phone2',), 
Patrick's avatar
Patrick committed
225 226 227 228 229
		# 'order_description',
		# 'invoice_description',
		('price_list_multiplier', 'vat_level'),
		('initial_balance', 'date_balance', 'balance'),
		('invoice_by_basket', 'represent_this_buyinggroup'), 
Patrick's avatar
Patrick committed
230 231
		'address',
		'is_active']
pi's avatar
pi committed
232
	readonly_fields = (
Patrick's avatar
Patrick committed
233
		# 'represent_this_buyinggroup',
pi's avatar
pi committed
234 235 236
		'date_balance', 
		'balance',
	)
Patrick's avatar
Patrick committed
237 238
	search_fields = ('short_profile_name', 'email')
	list_display = ('short_profile_name', 'get_products', 'get_balance', 'phone1', 'email', 'represent_this_buyinggroup',
pi's avatar
pi committed
239
		'is_active')
Patrick's avatar
Patrick committed
240 241
	list_per_page = 17
	list_max_show_all = 17
pi's avatar
pi committed
242 243 244 245 246 247 248 249 250 251 252 253 254
	actions = [
		'export_xlsx',
		'import_xlsx',
	]

	def export_xlsx(self, request, queryset):
		return export_product_xlsx(request, queryset)
	export_xlsx.short_description = _("Export products of selected producer(s) as XSLX file")

	def import_xlsx(self, request, queryset):
		return import_product_xlsx(self, admin, request, queryset)
	import_xlsx.short_description = _("Import products of selected producer(s) from a XLSX file")

Patrick's avatar
Patrick committed
255

pi's avatar
pi committed
256 257 258 259 260 261 262 263 264
	# def get_producer_phone1(self, obj):
	# 	if obj.producer:
	# 		return '%s'%(obj.producer.phone1)
	# 	else:
	# 		return ''
	# get_producer_phone1.short_description = _("phone1") 

admin.site.register(Producer, ProducerAdmin)

265 266 267 268 269 270 271 272 273 274
# Custom User
class UserDataForm(forms.ModelForm):

	username = forms.CharField(label=_('Username'), max_length=30, 
			help_text=_(
				'Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters'
			),
			validators=[
				validators.RegexValidator(re.compile('^[\w.@+-]+$'), _('Enter a valid username.'), 'invalid')
			])
pi's avatar
pi committed
275 276
	# password1 = forms.CharField(label=_('Password1'), max_length=128, required=False)
	# password2 = forms.CharField(label=_('Password2'), max_length=128, required=False)
277 278 279 280 281 282
	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)

	def __init__(self, *args, **kwargs):
		super(UserDataForm, self).__init__(*args, **kwargs)
283
		self.user = None
284

285 286 287 288
	def error(self,field, msg):
		if field not in self._errors:
			self._errors[field]= self.error_class([msg])

289
	def clean(self, *args, **kwargs):
pi's avatar
pi committed
290 291 292 293
		# 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 funcition. 
		cleaned_data = super(UserDataForm, self).clean(*args, **kwargs)
		customer_form = 'short_basket_name' in self.fields
294
		if any(self.errors):
pi's avatar
pi committed
295 296 297 298 299 300 301
			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
		username_field_name = 'username'
Patrick's avatar
Patrick committed
302 303 304 305 306
		initial_username  = None
		try:
			initial_username = self.instance.user.username
		except:
			pass
pi's avatar
pi committed
307 308 309 310 311 312 313 314 315 316 317 318 319
		if 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:
			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
320
		if not username:
pi's avatar
pi committed
321
			self.error(username_field_name ,user_error1)
322
		# Check that the email is set
323 324
		email = self.cleaned_data.get("email")
		if not email:
325 326
			self.error('email',_('The given email must be set'))
		# Check that the email is not already used
327 328
		user=None
		email = User.objects.normalize_email(email)
pi's avatar
pi committed
329 330
		if email:
			# Only if a email is given
331
			try:
pi's avatar
pi committed
332
				user = User.objects.get(email=email)
333 334
			except User.DoesNotExist:
				pass
pi's avatar
pi committed
335 336 337 338 339 340 341 342 343 344 345 346 347 348
		# Check that the username is not already used
		if user != 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 != None:
			if initial_username!=user.username:
				self.error(username_field_name,user_error2)
		print self.errors
		return cleaned_data
349 350

	def save(self, *args, **kwargs):
351
		super(UserDataForm, self).save(*args, **kwargs)
352 353 354
		change = (self.instance.id != None)
		username = self.data['username']
		email = self.data['email']
pi's avatar
pi committed
355
		# password = self.data['password1']
356 357 358 359
		first_name = self.data['first_name']
		last_name = self.data['last_name']
		user = None
		if change:
360
			user=User.objects.get(id=self.instance.user_id)
361 362 363 364
			user.username = username
			user.email = email
			user.first_name = first_name
			user.last_name = last_name
pi's avatar
pi committed
365 366
			# if password:
			# 	user.set_password(password)
367 368
			user.save()
		else:
369
			user = User.objects.create_user(
pi's avatar
pi committed
370
				username=username, email=email, password=uuid.uuid1().hex,
371 372
				first_name=first_name, last_name=last_name)
		self.user = user
373 374
		return self.instance

Patrick Colmant's avatar
Patrick Colmant committed
375 376

# Customer
377
class CustomerWithUserDataForm(UserDataForm):
378 379 380 381 382 383

	class Meta:
		model = Customer

class CustomerWithUserDataAdmin(admin.ModelAdmin):
	form = CustomerWithUserDataForm
pi's avatar
pi committed
384
	fields = [
Patrick's avatar
Patrick committed
385 386 387 388
		('short_basket_name', 'long_basket_name'),
		('email','email2'), 
		('phone1', 'phone2'),
		'address', 'vat_id',
Patrick's avatar
Patrick committed
389
		('initial_balance', 'date_balance', 'balance'),
Patrick's avatar
Patrick committed
390 391
		('represent_this_buyinggroup', 'may_order','is_active')
	]
pi's avatar
pi committed
392
	readonly_fields = (
Patrick's avatar
Patrick committed
393
		# 'represent_this_buyinggroup',
pi's avatar
pi committed
394 395 396
		'date_balance', 
		'balance',
	)
Patrick's avatar
Patrick committed
397
	search_fields = ('short_basket_name', 'user__email', 'email2')
Patrick's avatar
Patrick committed
398 399 400
	list_display = ('__unicode__', 'get_balance', 'may_order', 'phone1', 'phone2', 'get_email', 'email2', 'represent_this_buyinggroup')
	list_per_page = 17
	list_max_show_all = 17
Patrick Colmant's avatar
Patrick Colmant committed
401

pi's avatar
pi committed
402 403 404 405 406 407 408
	def get_email(self, obj):
		if obj.user:
			return '%s'%(obj.user.email)
		else:
			return ''
	get_email.short_description = _("email")

Patrick Colmant's avatar
Patrick Colmant committed
409
	def get_form(self,request, obj=None, **kwargs):
410 411 412 413 414
		form = super(CustomerWithUserDataAdmin,self).get_form(request, obj, **kwargs)
		username = form.base_fields['username']
		email = form.base_fields['email']
		first_name= form.base_fields['first_name']
		last_name= form.base_fields['last_name']
pi's avatar
pi committed
415

Patrick Colmant's avatar
Patrick Colmant committed
416
		if obj:
417
			user_model = get_user_model()
418
			user = user_model.objects.get(id=obj.user_id)
419
			username.initial = getattr(user, user_model.USERNAME_FIELD)
pi's avatar
pi committed
420
			# username.widget.attrs['readonly'] = True
421 422 423
			email.initial = user.email
			first_name.initial = user.first_name
			last_name.initial = user.last_name
424 425 426 427 428
		else:
			# Clean data displayed
			username.initial = ''
			# username.widget.attrs['readonly'] = False
			email.initial = ''
pi's avatar
pi committed
429 430
			first_name.initial = 'N/A'
			last_name.initial = 'N/A'
Patrick Colmant's avatar
Patrick Colmant committed
431 432
		return form

Patrick's avatar
Patrick committed
433 434
	def save_model(self, request, customer, form, change):
		customer.user = form.user
pi's avatar
pi committed
435
		form.user.is_staff = False
Patrick's avatar
Patrick committed
436
		form.user.is_active = customer.is_active
pi's avatar
pi committed
437
		form.user.save()
438
		super(CustomerWithUserDataAdmin,self).save_model(
Patrick's avatar
Patrick committed
439
			request, customer, form, change)
440

441
admin.site.register(Customer, CustomerWithUserDataAdmin)
Patrick Colmant's avatar
Patrick Colmant committed
442

pi's avatar
pi committed
443 444
# Staff
class StaffWithUserDataForm(UserDataForm):
445 446

	class Meta:
pi's avatar
pi committed
447 448 449 450 451 452 453 454 455 456
		model = Staff

class StaffWithUserDataAdmin(admin.ModelAdmin):
	form = StaffWithUserDataForm
	fields = ['username',
		# 'password1', 'password2',
		'email', 
		'is_reply_to_order_email', 'is_reply_to_invoice_email',
		'customer_responsible','long_name', 'function_description', 'is_active']
	list_display = ('__unicode__', 'customer_responsible', 'get_customer_phone1', 'is_active')
Patrick's avatar
Patrick committed
457 458 459
	list_select_related = ('customer_responsible',)
	list_per_page = 17
	list_max_show_all = 17
Patrick Colmant's avatar
Patrick Colmant committed
460 461

	def get_form(self,request, obj=None, **kwargs):
pi's avatar
pi committed
462
		form = super(StaffWithUserDataAdmin,self).get_form(request, obj, **kwargs)
463 464 465 466
		username = form.base_fields['username']
		email = form.base_fields['email']
		first_name= form.base_fields['first_name']
		last_name= form.base_fields['last_name']
Patrick Colmant's avatar
Patrick Colmant committed
467 468 469 470
		customer_responsible = form.base_fields["customer_responsible"]
		customer_responsible.widget.can_add_related = False

		if obj:
471
			user_model = get_user_model()
472
			user = user_model.objects.get(id=obj.user_id)
473 474 475 476 477
			username.initial = getattr(user, user_model.USERNAME_FIELD)
			# username.widget.attrs['readonly'] = True
			email.initial = user.email
			first_name.initial = user.first_name
			last_name.initial = user.last_name
Patrick Colmant's avatar
Patrick Colmant committed
478 479 480
			customer_responsible.empty_label = None
			customer_responsible.initial = obj.customer_responsible
		else:
481 482 483 484 485 486
			# Clean data displayed
			username.initial = ''
			# username.widget.attrs['readonly'] = False
			email.initial = ''
			first_name.initial = 'N/A'
			last_name.initial = 'N/A'
pi's avatar
pi committed
487 488
		customer_responsible.queryset = Customer.objects.all(
			).active().order_by(
489
			"short_basket_name")
Patrick Colmant's avatar
Patrick Colmant committed
490 491
		return form

Patrick's avatar
Patrick committed
492
	def save_model(self, request, staff, form, change):
pi's avatar
pi committed
493 494
		# TODO Check there is not more that one is_reply_to_order_email set to True
		# TODO Check there is not more that one is_reply_to_invoice_email set to True
Patrick's avatar
Patrick committed
495
		staff.user = form.user
496
		form.user.is_staff = True
Patrick's avatar
Patrick committed
497
		form.user.is_active = staff.is_active
498
		form.user.save()
pi's avatar
pi committed
499
		super(StaffWithUserDataAdmin,self).save_model(
Patrick's avatar
Patrick committed
500
			request, staff, form, change)
Patrick Colmant's avatar
Patrick Colmant committed
501

pi's avatar
pi committed
502
admin.site.register(Staff, StaffWithUserDataAdmin)
Patrick Colmant's avatar
Patrick Colmant committed
503

Patrick's avatar
Patrick committed
504 505
class ProductAdmin(admin.ModelAdmin):
	list_display = (
506
		'is_into_offer',
Patrick's avatar
Patrick committed
507
		'producer',
Patrick's avatar
Patrick committed
508
		'department_for_customer',
Patrick's avatar
Patrick committed
509
		'long_name',
Patrick's avatar
Patrick committed
510 511
		'original_unit_price',
		'unit_deposit',
512
		'customer_alert_order_quantity',
Patrick's avatar
Patrick committed
513
		'get_order_unit',
514
		'is_active')
Patrick Colmant's avatar
Patrick Colmant committed
515
	list_display_links = ('long_name',)
Patrick's avatar
Patrick committed
516
	list_editable = ('original_unit_price',)
Patrick Colmant's avatar
Patrick Colmant committed
517 518
	readonly_fields = ('is_created_on', 
		'is_updated_on')
pi's avatar
pi committed
519
	fields = (
Patrick's avatar
Patrick committed
520 521 522 523 524 525
		('producer', 'long_name', 'picture'),
		('original_unit_price', 'unit_deposit', 'vat_level'),
		# ('order_by_kg_pay_by_kg', 'order_by_piece_pay_by_piece', 'order_by_piece_pay_by_kg', 'producer_must_give_order_detail_per_customer', 'automatically_added'),
	 	# 'usage_description', 
		('order_unit', 'order_average_weight', 'customer_minimum_order_quantity', 'customer_increment_order_quantity', 'customer_alert_order_quantity'),
		('production_mode', 'department_for_customer', 'placement'),
pi's avatar
pi committed
526 527 528
		'offer_description', 
		('is_into_offer', 'is_active', 'is_created_on', 'is_updated_on')
	)
Patrick's avatar
Patrick committed
529 530 531 532 533 534
	list_select_related = ('producer', 'department_for_customer')
	list_per_page = 100
	list_max_show_all = 100
	ordering = ('producer', 
		'department_for_customer',
		'long_name',)
Patrick Colmant's avatar
Patrick Colmant committed
535 536
	search_fields = ('long_name',)
	list_filter = ('is_active',
Patrick's avatar
Patrick committed
537 538 539
		'is_into_offer',
		ProductFilterByDepartmentForThisProducer,
		ProductFilterByProducer,)
540
	actions = ['flip_flop_select_for_offer_status', 'duplicate_product'	]
541

Patrick's avatar
Patrick committed
542 543 544 545
	def get_order_unit(self, obj):
		return obj.get_order_unit_display()
	get_order_unit.short_description = _("order unit")

546
	def flip_flop_select_for_offer_status(self, request, queryset):
pi's avatar
pi committed
547 548
		for product in queryset.order_by():
			product.is_into_offer = not product.is_into_offer
Patrick's avatar
Patrick committed
549
			product.save(update_fields=['is_into_offer'])
550 551 552

	flip_flop_select_for_offer_status.short_description = _(
		'flip_flop_select_for_offer_status for offer')
Patrick Colmant's avatar
Patrick Colmant committed
553 554

	def duplicate_product(self, request, queryset):
Patrick's avatar
Patrick committed
555 556 557 558
		user_message = _("The product is duplicated.")
		user_message_level = messages.INFO
		product_count = 0
		duplicate_count = 0
Patrick Colmant's avatar
Patrick Colmant committed
559
		for product in queryset:
Patrick's avatar
Patrick committed
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
			product_count += 1
			long_name_postfix = unicode(_(" (COPY)"))
			max_length = Product._meta.get_field('long_name').max_length - len(long_name_postfix)
			product.long_name = cap(product.long_name, max_length).decode("utf8") + long_name_postfix
			product_set = Product.objects.filter(
				producer_id = product.producer_id,
				long_name = product.long_name).order_by()[:1]
			if product_set:
				# avoid to break the unique index : producer_id, long_name
				pass
			else:
				product.id = None
				product.save()
				duplicate_count += 1
		if product_count == duplicate_count:
			if product_count > 1:
				user_message = _("The products are duplicated.")
		else:
			if product_count == 1:
				user_message = _("The product has not been duplicated because a product with the same long name already exists.")
				user_message_level = messages.ERROR
			else:
				user_message = _("At least one product has not been duplicated because a product with the same long name already exists.")
				user_message_level = messages.WARNING

		self.message_user(request, user_message, user_message_level)
Patrick Colmant's avatar
Patrick Colmant committed
586 587 588 589 590

	duplicate_product.short_description = _('duplicate product')

	def get_form(self,request, obj=None, **kwargs):
		form = super(ProductAdmin,self).get_form(request, obj, **kwargs)
Patrick's avatar
Patrick committed
591 592
		# If we are coming from a list screen, use the filter to pre-fill the form

Patrick's avatar
Patrick committed
593
		# print form.base_fields
pi's avatar
pi committed
594
		producer = form.base_fields["producer"]
Patrick Colmant's avatar
Patrick Colmant committed
595 596
		department_for_customer = form.base_fields["department_for_customer"]
		production_mode = form.base_fields["production_mode"]
Patrick's avatar
Patrick committed
597

pi's avatar
pi committed
598
		producer.widget.can_add_related = False
Patrick Colmant's avatar
Patrick Colmant committed
599 600 601 602
		department_for_customer.widget.can_add_related = False
		production_mode.widget.can_add_related = False

		if obj:
pi's avatar
pi committed
603
			producer.empty_label = None
Patrick's avatar
Patrick committed
604 605
			producer.queryset = Producer.objects.all(
				).active()
Patrick Colmant's avatar
Patrick Colmant committed
606
			department_for_customer.empty_label = None
Patrick's avatar
Patrick committed
607 608
			department_for_customer.queryset = LUT_DepartmentForCustomer.objects.all(
				).active()
Patrick Colmant's avatar
Patrick Colmant committed
609
			production_mode.empty_label = None
Patrick's avatar
Patrick committed
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
		else:
			producer_id = None
			department_for_customer_id = None
			is_actif_value = None
			is_into_offer_value = None
			preserved_filters = request.GET.get('_changelist_filters', None)
			if preserved_filters:
				param = dict(parse_qsl(preserved_filters))
				if 'producer' in param:
					producer_id = param['producer']
				if 'department_for_customer' in param:
					department_for_customer_id = param['department_for_customer']
				if 'is_active__exact' in param:
					is_actif_value = param['is_active__exact']
				if 'is_into_offer__exact' in param:
					is_into_offer_value = param['is_into_offer__exact']
			is_active = form.base_fields["is_active"]
			is_into_offer = form.base_fields["is_into_offer"]
			vat_level = form.base_fields["vat_level"]
			if producer_id:
				vat_level.initial = get_object_or_404(Producer, id=producer_id).vat_level
				producer.empty_label = None
				producer.queryset = Producer.objects.all(
					).id(producer_id)
			else:
				producer.queryset = Producer.objects.all(
					).active()
			if department_for_customer_id:
				department_for_customer.empty_label = None
				department_for_customer.queryset = LUT_DepartmentForCustomer.objects.filter(
					id=department_for_customer_id
				)
			else:
				department_for_customer.queryset = LUT_DepartmentForCustomer.objects.all(
				).active()
			if is_actif_value:
				if is_actif_value == '0':
					is_active.initial = False
				else:
					is_active.initial = True
			if is_into_offer_value:
				if is_into_offer_value == '0':
					is_into_offer.initial = False
				else:
					is_into_offer.initial = True
Patrick Colmant's avatar
Patrick Colmant committed
655 656 657 658
		production_mode.queryset = LUT_ProductionMode.objects.all(
			).active()
		return form

659
admin.site.register(Product, ProductAdmin)
Patrick Colmant's avatar
Patrick Colmant committed
660 661 662 663

# Permanence
class PermanenceBoardInline(admin.TabularInline):
	model = PermanenceBoard
pi's avatar
pi committed
664
	fields = ['permanence_role', 'customer']
Patrick Colmant's avatar
Patrick Colmant committed
665 666 667
	extra = 1

	def formfield_for_foreignkey(self, db_field, request, **kwargs):
pi's avatar
pi committed
668 669
		if db_field.name == "customer":
			kwargs["queryset"] = Customer.objects.all(
Patrick's avatar
Patrick committed
670
				).active()  # .not_the_buyinggroup()
Patrick Colmant's avatar
Patrick Colmant committed
671 672 673 674 675
		if db_field.name == "permanence_role":
			kwargs["queryset"] = LUT_PermanenceRole.objects.all(
				).active()
		return super(PermanenceBoardInline, self).formfield_for_foreignkey(db_field, request, **kwargs)

Patrick's avatar
Patrick committed
676 677
	# def save_formset(self, request, form, formset, change):
	# 	-> replaced by pre_save signal in model
pi's avatar
pi committed
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702

class PermanenceDataForm(forms.ModelForm):
	def __init__(self, *args, **kwargs):
		super(PermanenceDataForm, self).__init__(*args, **kwargs)
		self.user = None

	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(PermanenceDataForm, self).clean(*args, **kwargs)
		initial_distribution_date = self.instance.distribution_date
		distribution_date = self.cleaned_data.get("distribution_date")
		initial_short_name = self.instance.short_name
		short_name = self.cleaned_data.get("short_name")
		if(initial_distribution_date != distribution_date or initial_short_name != short_name):
			permanence_already_exist = False
			try:
				Permanence.objects.get(distribution_date=distribution_date, short_name=short_name)
				permanence_already_exist = True
			except Permanence.DoesNotExist:
				pass
			if permanence_already_exist:
				self.error('short_name',_('A permanence with the same distribution date and the same short_name already exist. You must either change te distribution_date or the name.'))
Patrick's avatar
Patrick committed
703 704 705
			else:
				# Empty menu cache to eventually display the modified Permanence Label
				menu_pool.clear()
pi's avatar
pi committed
706 707 708 709 710
		return cleaned_data

	class Meta:
		model = Permanence

Patrick Colmant's avatar
Patrick Colmant committed
711
class PermanenceInPreparationAdmin(admin.ModelAdmin):
pi's avatar
pi committed
712
	form = PermanenceDataForm
Patrick's avatar
Patrick committed
713 714 715 716 717 718
	fields = (
 		'distribution_date',
 		'short_name', 
		# ('status', 'automaticaly_closed'), 
		'automaticaly_closed',
		'offer_description',
Patrick's avatar
Patrick committed
719
		# 'order_description', 
Patrick's avatar
Patrick committed
720 721
		'producers'
	)
722
	# readonly_fields = ('status', 'is_created_on', 'is_updated_on')
pi's avatar
pi committed
723
	exclude = ['invoice_description']
Patrick's avatar
Patrick committed
724 725
	list_per_page = 10
	list_max_show_all = 10
726
	filter_horizontal = ('producers',)
Patrick's avatar
Patrick committed
727 728
	# inlines = [PermanenceBoardInline, OfferItemInline]
	inlines = [PermanenceBoardInline]
Patrick Colmant's avatar
Patrick Colmant committed
729
	date_hierarchy = 'distribution_date'
pi's avatar
pi committed
730
	list_display = ('__unicode__', 'get_producers', 'get_customers', 'get_board', 'status')
Patrick Colmant's avatar
Patrick Colmant committed
731
	ordering = ('distribution_date',)
pi's avatar
pi committed
732 733 734
	actions = [
		'download_planified', 
		'open_and_send_offers',
Patrick's avatar
Patrick committed
735
		'download_orders', 
pi's avatar
pi committed
736 737 738
		'close_and_send_orders',
		'delete_purchases', 
		'back_to_planified',
Patrick's avatar
Patrick committed
739
		'generate_calendar'
Patrick Colmant's avatar
Patrick Colmant committed
740 741
	]

Patrick's avatar
Patrick committed
742 743 744 745 746 747 748
	def get_readonly_fields(self, request, obj=None):
		if obj:
			status = obj.status
			if status>PERMANENCE_PLANIFIED:
				return('status', 'is_created_on', 'is_updated_on','producers')
		return ('status', 'is_created_on', 'is_updated_on')

pi's avatar
pi committed
749 750 751
	# def export_docx(self, request, queryset):
	# 	return export_mymodel_docx(request, queryset)
	# export_docx.short_description = _("Export DOCX")
752

pi's avatar
pi committed
753 754 755
	def download_planified(self, request, queryset):
		return export_permanence_planified_xlsx(request, queryset)
	download_planified.short_description = _("Export planified XLSX")
756 757


Patrick's avatar
Patrick committed
758
	def download_orders(self, request, queryset):
pi's avatar
pi committed
759
		for permanence in queryset[:1]:
Patrick's avatar
Patrick committed
760
			if permanence.status >=PERMANENCE_OPENED:
Patrick's avatar
Patrick committed
761
				response = HttpResponse(mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
Patrick's avatar
Patrick committed
762 763
				filename = (unicode(_("Check")) + u" - " + permanence.__unicode__() + u'.xlsx').encode('latin-1', errors='ignore')
				response['Content-Disposition'] = 'attachment; filename=' + filename
Patrick's avatar
Patrick committed
764 765 766 767 768 769 770 771 772 773 774 775
				wb = export_orders_xlsx(permanence)
				wb.save(response)
				return response
	download_orders.short_description = _("Export orders XLSX")

	def open_and_send_offers(self, request, queryset):
		user_message = _("Action canceled by the user.")
		user_message_level = messages.WARNING
		if 'apply' in request.POST:
			current_site = get_current_site(request)
			user_message = _("The status of this permanence prohibit you to open and send offers.")
			user_message_level = messages.ERROR
Patrick's avatar
Patrick committed
776
			now = timezone.now()
Patrick's avatar
Patrick committed
777 778 779
			for permanence in queryset[:1]:
				if permanence.status==PERMANENCE_PLANIFIED:
					permanence.status = PERMANENCE_WAIT_FOR_OPEN
Patrick's avatar
Patrick committed
780 781 782
					permanence.is_updated_on = now
					permanence.save(update_fields=['status','is_updated_on'])
					thread.start_new_thread( tasks.open_offers, (permanence.id, current_site.name) )
Patrick's avatar
Patrick committed
783 784 785 786
					user_message = _("The offers are being generated.")
					user_message_level = messages.INFO
				elif permanence.status==PERMANENCE_WAIT_FOR_OPEN:
					# On demand 15 minutes after the previous attempt, go back to previous status and send alert email
Patrick's avatar
Patrick committed
787
					# use only timediff, -> timezone conversion not needed
Patrick's avatar
Patrick committed
788
					timediff = now - permanence.is_updated_on
Patrick's avatar
Patrick committed
789 790
					if timediff.total_seconds() > (30 * 60):
						thread.start_new_thread( send_alert_email, (permanence, current_site.name) )
Patrick's avatar
Patrick committed
791 792 793
						permanence.status = PERMANENCE_PLANIFIED
						permanence.save(update_fields=['status'])
						user_message = _("The action has been canceled by the system and an email send to the site administrator.")
Patrick's avatar
Patrick committed
794
						user_message_level = messages.WARNING
Patrick's avatar
Patrick committed
795
					else:
Patrick's avatar
Patrick committed
796
						user_message = _("Action refused by the system. Please, retry in %d minutes.") % (31 - (int(timediff.total_seconds()) / 60))
Patrick's avatar
Patrick committed
797 798 799 800 801 802 803 804 805 806 807 808 809 810
						user_message_level = messages.WARNING
		elif 'cancel' not in request.POST:
			opts = self.model._meta
			app_label = opts.app_label
			return render_response(request, 'repanier/confirm_admin_action.html', {
				'title': _("Please, confirm the action : open and send offers"),
				'action' : 'open_and_send_offers',
				'queryset': queryset[:1],
				"app_label": app_label,
				'action_checkbox_name': admin.ACTION_CHECKBOX_NAME,
			})
		self.message_user(request, user_message, user_message_level)
		return None

pi's avatar
pi committed
811 812 813
	open_and_send_offers.short_description = _('open and send offers')

	def close_and_send_orders(self, request, queryset):
Patrick's avatar
Patrick committed
814 815 816 817 818 819
		user_message = _("Action canceled by the user.")
		user_message_level = messages.WARNING
		if 'apply' in request.POST:
			user_message = _("The status of this permanence prohibit you to close it.")
			user_message_level = messages.ERROR
			current_site = get_current_site(request)
Patrick's avatar
Patrick committed
820
			now = timezone.now()
Patrick's avatar
Patrick committed
821 822 823
			for permanence in queryset[:1]:
				if permanence.status==PERMANENCE_OPENED:
					permanence.status = PERMANENCE_WAIT_FOR_SEND
Patrick's avatar
Patrick committed
824 825 826 827
					permanence.is_updated_on = now
					permanence.save(update_fields=['status','is_updated_on'])
					thread.start_new_thread( tasks.close_orders, (permanence.id, current_site.name) )
					# tasks.close_orders(permanence.id, current_site.name)
Patrick's avatar
Patrick committed
828 829 830 831
					user_message = _("The orders are being closed.")
					user_message_level = messages.INFO
				elif permanence.status==PERMANENCE_WAIT_FOR_SEND:
					# On demand 30 minutes after the previous attempt, go back to previous status and send alert email
Patrick's avatar
Patrick committed
832
					# use only timediff, -> timezone conversion not needed
Patrick's avatar
Patrick committed
833 834
					timediff = now - permanence.is_updated_on
					if timediff.total_seconds() > (30 * 60):
Patrick's avatar
Patrick committed
835
						thread.start_new_thread( send_alert_email, (permanence, current_site.name) )
Patrick's avatar
Patrick committed
836 837 838
						permanence.status = PERMANENCE_OPENED
						permanence.save(update_fields=['status'])
						user_message = _("The action has been canceled by the system and an email send to the site administrator.")
Patrick's avatar
Patrick committed
839
						user_message_level = messages.WARNING
Patrick's avatar
Patrick committed
840
					else:
Patrick's avatar
Patrick committed
841
						user_message = _("Action refused by the system. Please, retry in %d minutes.") % (31 - (int(timediff.total_seconds()) / 60))
Patrick's avatar
Patrick committed
842 843 844 845 846 847 848 849 850 851 852 853 854 855
						user_message_level = messages.WARNING
		elif 'cancel' not in request.POST:
			opts = self.model._meta
			app_label = opts.app_label
			return render_response(request, 'repanier/confirm_admin_action.html', {
				'title': _("Please, confirm the action : close and send orders"),
				'action' : 'close_and_send_orders',
				'queryset': queryset[:1],
				"app_label": app_label,
				'action_checkbox_name': admin.ACTION_CHECKBOX_NAME,
			})
		self.message_user(request, user_message, user_message_level)
		return None

Patrick Colmant's avatar
Patrick Colmant committed
856

pi's avatar
pi committed
857
	close_and_send_orders.short_description = _('close and send orders')
Patrick Colmant's avatar
Patrick Colmant committed
858

pi's avatar
pi committed
859
	def back_to_planified(self, request, queryset):
Patrick's avatar
Patrick committed
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
		user_message = _("Action canceled by the user.")
		user_message_level = messages.WARNING
		if 'apply' in request.POST:
			user_message = _("The status of this permanence prohibit you to go back to planified.")
			user_message_level = messages.ERROR
			for permanence in queryset[:1]:
				if PERMANENCE_OPENED <= permanence.status <= PERMANENCE_SEND:
					OfferItem.objects.all().permanence(permanence).update(is_active=False)
					permanence.status=PERMANENCE_PLANIFIED
					permanence.save(update_fields=['status'])
					menu_pool.clear()
					user_message = _("The permanence is back to planified.")
					user_message_level = messages.INFO
		elif 'cancel' not in request.POST:
			opts = self.model._meta
			app_label = opts.app_label
			return render_response(request, 'repanier/confirm_admin_action.html', {
				'title': _("Please, confirm the action : back to planified"),
				'action' : 'back_to_planified',
				'queryset': queryset[:1],
				"app_label": app_label,
				'action_checkbox_name': admin.ACTION_CHECKBOX_NAME,
			})
		self.message_user(request, user_message, user_message_level)
		return None
Patrick Colmant's avatar
Patrick Colmant committed
885

pi's avatar
pi committed
886 887 888
	back_to_planified.short_description = _('back to planified')

	def delete_purchases(self, request, queryset):
Patrick's avatar
Patrick committed
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
		user_message = _("Action canceled by the user.")
		user_message_level = messages.WARNING
		if 'apply' in request.POST:
			user_message = _("The status of this permanence prohibit you to delete the purchases.")
			user_message_level = messages.ERROR
			is_something_deleted = False
			for permanence in queryset.filter(status=PERMANENCE_SEND)[:1]:
				Purchase.objects.all().permanence(permanence).delete()
				OfferItem.objects.all().permanence(permanence).delete()
				CustomerOrder.objects.filter(permanence=permanence).delete()
				user_message = _("The purchases of this permanence have been deleted. There is no way to restore them automaticaly.")
				user_message_level = messages.INFO
		elif 'cancel' not in request.POST:
			opts = self.model._meta
			app_label = opts.app_label
			return render_response(request, 'repanier/confirm_admin_action.html', {
				'title': _("Please, confirm the action : delete purchases. Be carefull : !!! THERE IS NO WAY TO RESTORE THEM AUTOMATICALY !!!!"),
				'action' : 'delete_purchases',
				'queryset': queryset[:1],
				"app_label": app_label,
				'action_checkbox_name': admin.ACTION_CHECKBOX_NAME,
			})
		self.message_user(request, user_message, user_message_level)
		return None
pi's avatar
pi committed
913 914

	delete_purchases.short_description = _('delete purchases')
Patrick Colmant's avatar
Patrick Colmant committed
915

Patrick's avatar
Patrick committed
916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936
	def generate_calendar(self, request, queryset):
		for permanence in queryset[:1]:
			starting_date = permanence.distribution_date
			for i in xrange(1,13):
				# PermanenceInPreparation used to generate PermanenceBoard when post_save
				try:
					PermanenceInPreparation.objects.create(distribution_date=starting_date+datetime.timedelta(days=7*i))
				except:
					pass
	generate_calendar.short_description = _("Generate 12 weekly permanences starting from this")

	# def get_actions(self, request):
	# 	actions = super(PermanenceInPreparationAdmin, self).get_actions(request)
	# 	if 'delete_selected' in actions:
	# 		del actions['delete_selected']
	# 	if not actions:
	# 		try:
	# 			self.list_display.remove('action_checkbox')
	# 		except ValueError:
	# 			pass
	# 	return actions
Patrick Colmant's avatar
Patrick Colmant committed
937

pi's avatar
pi committed
938 939 940 941 942 943 944
	def formfield_for_manytomany(self, db_field, request, **kwargs):
		if db_field.name == "producers":
			kwargs["queryset"] = Producer.objects.all().active(
				)
		return super(PermanenceInPreparationAdmin, self).formfield_for_manytomany(
			db_field, request, **kwargs)

Patrick Colmant's avatar
Patrick Colmant committed
945 946
	def queryset(self, request):
		qs = super(PermanenceInPreparationAdmin, self).queryset(request)
pi's avatar
pi committed
947
		return qs.filter(status__lte=PERMANENCE_SEND)
Patrick's avatar
Patrick committed
948 949 950 951 952 953 954 955 956

	# save_model() is called before the inlines are saved
	def save_model(self, request, permanence, form, change):
		if change and ('distribution_date' in form.changed_data):
			PermanenceBoard.objects.filter(permanence=permanence.id).update(distribution_date=permanence.distribution_date)
			Purchase.objects.filter(permanence=permanence.id).update(distribution_date=permanence.distribution_date)
		super(PermanenceInPreparationAdmin,self).save_model(
			request, permanence, form, change)

Patrick Colmant's avatar
Patrick Colmant committed
957 958 959
admin.site.register(PermanenceInPreparation, PermanenceInPreparationAdmin)

class PermanenceDoneAdmin(admin.ModelAdmin):
Patrick's avatar
Patrick committed
960 961 962 963 964 965 966
	fields = (
		'distribution_date',
		'short_name',
		'invoice_description',
		# 'status'
	)
	readonly_fields = ('status', 'is_created_on', 'is_updated_on', 'automaticaly_closed')
Patrick's avatar
Patrick committed
967 968 969
	exclude = ['offer_description',]
	list_per_page = 10
	list_max_show_all = 10
Patrick's avatar
Patrick committed
970 971
	# inlines = [PermanenceBoardInline, OfferItemInline]
	inlines = [PermanenceBoardInline]
Patrick Colmant's avatar
Patrick Colmant committed
972
	date_hierarchy = 'distribution_date'
pi's avatar
pi committed
973
	list_display = ('__unicode__', 'get_producers', 'get_customers', 'get_board', 'status')
Patrick's avatar
Patrick committed
974
	ordering = ('-distribution_date',)
pi's avatar
pi committed
975 976 977
	actions = [
		'export_xlsx',
		'import_xlsx',
Patrick's avatar
Patrick committed
978
		'generate_invoices',
Patrick's avatar
Patrick committed
979
		'preview_invoices',
Patrick's avatar
Patrick committed
980
		'send_invoices',
pi's avatar
pi committed
981 982 983 984 985 986 987 988 989 990
		'cancel_invoices',
	]

	def export_xlsx(self, request, queryset):
		return export_permanence_done_xlsx(request, queryset)
	export_xlsx.short_description = _("Export orders prepared as XSLX file")

	def import_xlsx(self, request, queryset):
		return import_permanence_done_xlsx(self, admin, request, queryset)
	import_xlsx.short_description = _("Import orders prepared from a XLSX file")
Patrick Colmant's avatar
Patrick Colmant committed
991

Patrick's avatar
Patrick committed
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
	def preview_invoices(self, request, queryset):
		current_site = get_current_site(request)
		for permanence in queryset[:1]:
			if permanence.status==PERMANENCE_DONE:
				response = HttpResponse(mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
				filename = (unicode(_("Invoice")) + u" - " + permanence.__unicode__() + u'.xlsx').encode('latin-1', errors='ignore')
				response['Content-Disposition'] = 'attachment; filename=' + filename
				wb = export_invoices_xlsx(permanence=permanence, wb=None, sheet_name=current_site.name)
				wb.save(response)
				return response
			else:
				user_message = _("You can only preview invoices when the permanence status is 'done'.")
				user_message_level = messages.WARNING
	preview_invoices.short_description = _("Preview invoices before sending them by email")
1006

Patrick's avatar
Patrick committed
1007 1008 1009 1010 1011
	def generate_invoices(self, request, queryset):
		user_message = _("Action canceled by the user.")
		user_message_level = messages.WARNING
		if 'apply' in request.POST:
			current_site = get_current_site(request)
Patrick's avatar
Patrick committed
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
			# user_message = _("The status of another permanence prohibit you to close invoices of this permanence.")
			# user_message_level = messages.ERROR
			# permanence_done_pending_set = Permanence.objects.filter(status__in= [PERMANENCE_WAIT_FOR_DONE, PERMANENCE_INVOICES_VALIDATION_FAILED]).order_by()[:1]
			# if permanence_done_pending_set:
			# 	pass
			# else:
			# Accept to close only one at the same time because the order of execution is important.
			for permanence in queryset[:1]:
				if permanence.status==PERMANENCE_SEND:
					# permanence.status = PERMANENCE_WAIT_FOR_DONE
					# permanence.save(update_fields=['status'])
					# thread.start_new_thread( tasks.done, (permanence.id, permanence.distribution_date, current_site.name) )
					tasks.done(permanence.id, permanence.distribution_date, current_site.name)
					user_message = _("Action performed.")
					user_message_level = messages.INFO
				else:
					if permanence.status == PERMANENCE_INVOICES_VALIDATION_FAILED:
						user_message = _("The permanence status says there is an error. You must cancel the invoice then correct, before retrying.")
						user_message_level = messages.WARNING
					else:
						user_message = _("You can only generate invoices when the permanence status is 'send'.")
						user_message_level = messages.WARNING
Patrick's avatar
Patrick committed
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
		elif 'cancel' not in request.POST:
			opts = self.model._meta
			app_label = opts.app_label
			return render_response(request, 'repanier/confirm_admin_action.html', {
				'title': _("Please, confirm the action : generate the invoices"),
				'action' : 'generate_invoices',
				'queryset': queryset[:1],
				"app_label": app_label,
				'action_checkbox_name': admin.ACTION_CHECKBOX_NAME,
			})
		self.message_user(request, user_message, user_message_level)
		return None

	generate_invoices.short_description = _('generate invoices')

	def send_invoices(self, request, queryset):
		user_message = _("Action canceled by the user.")
		user_message_level = messages.WARNING
		if 'apply' in request.POST:
			current_site = get_current_site(request)
			for permanence in queryset[:1]:
				if permanence.status==PERMANENCE_DONE:
Patrick's avatar
Patrick committed
1056 1057
					thread.start_new_thread( tasks.email_invoices, (permanence.id, current_site.name) )
					# tasks.email_invoices(permanence.id, current_site.name)
Patrick's avatar
Patrick committed
1058
					user_message = _("Emails containing the invoices will be send to the customers and the producers.")
Patrick's avatar
Patrick committed
1059
					user_message_level = messages.INFO
Patrick's avatar
Patrick committed
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
				else:
					user_message = _("The status of this permanence prohibit you to send invoices.")
					user_message_level = messages.ERROR
		elif 'cancel' not in request.POST:
			opts = self.model._meta
			app_label = opts.app_label
			return render_response(request, 'repanier/confirm_admin_action.html', {
				'title': _("Please, confirm the action : send the invoices"),
				'action' : 'send_invoices',
				'queryset': queryset[:1],
				"app_label": app_label,
				'action_checkbox_name': admin.ACTION_CHECKBOX_NAME,
			})
		self.message_user(request, user_message, user_message_level)
		return None
pi's avatar
pi committed
1075
	
Patrick's avatar
Patrick committed
1076
	send_invoices.short_description = _('send invoices')
Patrick Colmant's avatar
Patrick Colmant committed
1077

pi's avatar
pi committed
1078
	def cancel_invoices(self, request, queryset):
Patrick's avatar
Patrick committed
1079 1080 1081
		user_message = _("Action canceled by the user.")
		user_message_level = messages.WARNING
		if 'apply' in request.POST:
Patrick's avatar
Patrick committed
1082
			# TODO : Use the bank account total record
Patrick's avatar
Patrick committed
1083 1084 1085 1086 1087
			latest_customer_invoice_set=CustomerInvoice.objects.order_by('-id')[:1]
			if latest_customer_invoice_set:
				user_message = _("The status of this permanence prohibit you to close invoices.")
				user_message_level = messages.ERROR
				for permanence in queryset[:1]:
Patrick's avatar
Patrick committed
1088
					if permanence.status in [PERMANENCE_WAIT_FOR_DONE, PERMANENCE_INVOICES_VALIDATION_FAILED, PERMANENCE_DONE] :
Patrick's avatar
Patrick committed
1089 1090 1091 1092 1093
						if latest_customer_invoice_set[0].permanence.id == permanence.id:
							# This is well the latest closed permanence. The invoices can be cancelled without damages.
							self.cancel(permanence.id)
							user_message = _("The selected invoice has been canceled.")
							user_message_level = messages.INFO
Patrick's avatar
Patrick committed
1094 1095 1096
							# else:
							# 	user_message = _("Please retry later, an operation on the bank account is ongoing.")
							# 	user_message_level = messages.WARNING
Patrick's avatar
Patrick committed
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115
						else:
							user_message = _("The selected invoice is not the latest invoice.")
							user_message_level = messages.ERROR
			# else:
			# 	for permanence in queryset:
			# 		if permanence.status == PERMANENCE_DONE:
			# 			self.cancel(permanence.id)
		elif 'cancel' not in request.POST:
			opts = self.model._meta
			app_label = opts.app_label
			return render_response(request, 'repanier/confirm_admin_action.html', {
				'title': _("Please, confirm the action : cancel the invoices"),
				'action' : 'cancel_invoices',
				'queryset': queryset[:1],
				"app_label": app_label,
				'action_checkbox_name': admin.ACTION_CHECKBOX_NAME,
			})
		self.message_user(request, user_message, user_message_level)
		return None
Patrick Colmant's avatar
Patrick Colmant committed
1116

pi's avatar
pi committed
1117 1118
	cancel_invoices.short_description = _('cancel latest invoices')

Patrick's avatar
Patrick committed
1119 1120
	def cancel(self, permanence_id):

Patrick's avatar
Patrick committed
1121 1122 1123 1124 1125 1126 1127
		# Lock BankAccount for update
		# lock = BankAccount.objects.filter(
		# 	operation_status=BANK_LATEST_TOTAL).order_by().update(
		# 	operation_status=BANK_CALCULTAING_LATEST_TOTAL)
		# if lock != 1 :
		# 	return False

Patrick's avatar
Patrick committed
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160
		for customer_invoice in CustomerInvoice.objects.filter(
			permanence_id=permanence_id).order_by().distinct():
			customer = Customer.objects.get(id=customer_invoice.customer_id)
			customer.balance = customer_invoice.previous_balance
			customer.date_balance = customer_invoice.date_previous_balance
			customer.save(update_fields=['balance', 'date_balance'])
			Purchase.objects.all().filter(
				is_recorded_on_customer_invoice_id=customer_invoice.id
				).update(
				is_recorded_on_customer_invoice=None
				)
			BankAccount.objects.all().filter(
				is_recorded_on_customer_invoice_id=customer_invoice.id
				).update(
				is_recorded_on_customer_invoice=None
				)
		for producer_invoice in ProducerInvoice.objects.filter(
			permanence_id=permanence_id).order_by().distinct():
			producer = Producer.objects.get(id=producer_invoice.producer_id)
			producer.balance = producer_invoice.previous_balance
			producer.date_balance = producer_invoice.date_previous_balance
			producer.save(update_fields=['balance', 'date_balance'])
			Purchase.objects.all().filter(
				is_recorded_on_producer_invoice_id=producer_invoice.id
				).update(
				is_recorded_on_producer_invoice=None
				)
			BankAccount.objects.all().filter(
				is_recorded_on_producer_invoice_id=producer_invoice.id
				).update(
				is_recorded_on_producer_invoice=None
				)
		CustomerInvoice.objects.filter(
Patrick's avatar
Patrick committed
1161
			permanence_id=permanence_id).order_by().delete()
Patrick's avatar
Patrick committed
1162
		ProducerInvoice.objects.filter(
Patrick's avatar
Patrick committed
1163 1164
			permanence_id=permanence_id).order_by().delete()
		BankAccount.objects.filter(operation_status=BANK_LATEST_TOTAL).order_by().delete()
Patrick's avatar
Patrick committed
1165
		bank_account_set= BankAccount.objects.all().filter(
Patrick's avatar
Patrick committed
1166 1167
			customer = None,
			producer = None).order_by('-id')[:1]
Patrick's avatar
Patrick committed
1168
		if bank_account_set:
Patrick's avatar
Patrick committed
1169 1170 1171 1172 1173
			bank_account = bank_account_set[0]
			bank_account.operation_status=BANK_LATEST_TOTAL
			bank_account.save(update_fields=[
		      'operation_status' 
    		])
Patrick's avatar
Patrick committed
1174
		Permanence.objects.filter(id=permanence_id).update(status = PERMANENCE_SEND,is_done_on = None)
pi's avatar
pi committed
1175
		menu_pool.clear()
Patrick's avatar
Patrick committed
1176
		# return True
pi's avatar
pi committed
1177 1178 1179

	def has_add_permission(self, request):
		return False
Patrick Colmant's avatar
Patrick Colmant committed
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193

	def get_actions(self, request):
		actions = super(PermanenceDoneAdmin, self).get_actions(request)
		if 'delete_selected' in actions:
			del actions['delete_selected']
		if not actions:
			try:
				self.list_display.remove('action_checkbox')
			except ValueError:
				pass
		return actions

	def queryset(self, request):
		qs = super(PermanenceDoneAdmin, self).queryset(request)
pi's avatar
pi committed
1194
		return qs.filter(status__gte=PERMANENCE_SEND)
Patrick's avatar
Patrick committed
1195 1196 1197 1198 1199 1200 1201

	def save_model(self, request, permanence, form, change):
		if change and ('distribution_date' in form.changed_data):
			PermanenceBoard.objects.filter(permanence=permanence.id).update(distribution_date=permanence.distribution_date)
			Purchase.objects.filter(permanence=permanence.id).update(distribution_date=permanence.distribution_date)
		super(PermanenceDoneAdmin,self).save_model(
			request, permanence, form, change)
Patrick Colmant's avatar
Patrick Colmant committed
1202 1203 1204
admin.site.register(PermanenceDone, PermanenceDoneAdmin)

class PurchaseAdmin(admin.ModelAdmin):
Patrick's avatar
Patrick committed
1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216
	fields = (
		'permanence',
		'customer',
		'product',
		'long_name',
		'quantity',
		'original_unit_price',
		'unit_deposit',
		# 'original_price',
		'comment'
	)
	readonly_fields  = ('long_name',)
pi's avatar
pi committed
1217
	exclude = ['offer_item']	
Patrick's avatar
Patrick committed
1218 1219 1220 1221 1222 1223 1224 1225 1226
	list_display = [
		'permanence',
		'producer', 
		'long_name',
		'customer', 
		'quantity', 
		'original_unit_price',
		'unit_deposit',
		'original_price',
Patrick's avatar
Patrick committed
1227
		'comment',
Patrick's avatar
Patrick committed
1228
	]
Patrick's avatar
Patrick committed
1229 1230 1231 1232
	list_select_related = ('producer', 'permanence', 'customer')
	list_per_page = 17
	list_max_show_all = 17
	ordering = ('-distribution_date','customer', 'product')
1233
	date_hierarchy = 'distribution_date'
Patrick's avatar
Patrick committed
1234 1235 1236
	list_filter = (PurchaseFilterByPermanence,PurchaseFilterByCustomerForThisPermanence, PurchaseFilterByProducerForThisPermanence)
	list_display_links = ('long_name',)
	search_fields = ('customer__short_basket_name', 'long_name')
Patrick Colmant's avatar
Patrick Colmant committed
1237 1238
	actions = []

Patrick's avatar
Patrick committed
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
	def get_readonly_fields(self, request, obj=None):
		if obj:
			status = obj.permanence.status
			if status == PERMANENCE_SEND:
				return('long_name',)
		else:
			preserved_filters = request.GET.get('_changelist_filters', None)
			if preserved_filters:
				param = dict(parse_qsl(preserved_filters))
				if 'permanence' in param:
					permanence_id = param['permanence']
					permanence_set = Permanence.objects.filter(
						id = permanence_id).order_by()[:1]
					if permanence_set:
						if permanence_set[0].status == PERMANENCE_SEND:
							return('long_name',)
		return('long_name', 'original_unit_price',	'unit_deposit')
pi's avatar
pi committed
1256 1257 1258 1259

	def queryset(self, request):
		queryset = super(PurchaseAdmin, self).queryset(request)
		return queryset.exclude(producer__isnull=True)
Patrick Colmant's avatar
Patrick Colmant committed
1260 1261 1262

	def get_form(self,request, obj=None, **kwargs):
		form = super(PurchaseAdmin,self).get_form(request, obj, **kwargs)
Patrick's avatar
Patrick committed
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
		# /purchase/add/?_changelist_filters=permanence%3D6%26customer%3D3
		# If we are coming from a list screen, use the filter to pre-fill the form
		permanence_id = None
		customer_id = None
		producer_id = None
		preserved_filters = request.GET.get('_changelist_filters', None)
		if preserved_filters:
			param = dict(parse_qsl(preserved_filters))
			if 'permanence' in param:
				permanence_id = param['permanence']
			if 'customer' in param:
				customer_id = param['customer']
			if 'producer' in param:
				producer_id = param['producer']
1277
		permanence = form.base_fields["permanence"]
pi's avatar
pi committed
1278
		customer = form.base_fields["customer"]
1279 1280
		product = form.base_fields["product"]
		permanence.widget.can_add_related = False
pi's avatar
pi committed
1281
		customer.widget.can_add_related = False
1282
		product.widget.can_add_related = False
Patrick's avatar
Patrick committed
1283
		# self.a_previous_price_with_tax = 0
Patrick Colmant's avatar
Patrick Colmant committed
1284 1285

		if obj:
Patrick's avatar
Patrick committed
1286
			# self.a_previous_price_with_tax = obj.price_with_tax
1287 1288 1289
			permanence.empty_label = None
			permanence.queryset = Permanence.objects.filter(
				id = obj.permanence_id)
pi's avatar
pi committed
1290 1291 1292
			customer.empty_label = None
			customer.queryset = Customer.objects.filter(
				id = obj.customer_id)
1293 1294 1295
			product.empty_label = None
			product.queryset = Product.objects.filter(
				id = obj.product_id)
Patrick Colmant's avatar
Patrick Colmant committed
1296
		else:
Patrick's avatar
Patrick committed
1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312

			if permanence_id:
				permanence.empty_label = None
				permanence.queryset = Permanence.objects.all().filter(
					id = permanence_id,
					status__in=[PERMANENCE_OPENED, PERMANENCE_SEND]
				)
				if producer_id:
					product.queryset = Product.objects.filter(offeritem__permanence=permanence_id).producer(producer_id).active()
				else:
					product.queryset = Product.objects.filter(offeritem__permanence=permanence_id).active()
			else:
				permanence.queryset = Permanence.objects.all().filter(
					status__in=[PERMANENCE_OPENED, PERMANENCE_SEND]
				)
				if producer_id:
Patrick's avatar
Patrick committed
1313
					product.queryset = Product.objects.all().producer(producer_id).active().is_selected_for_offer()
Patrick's avatar
Patrick committed
1314
				else:
Patrick's avatar
Patrick committed
1315
					product.queryset = Product.objects.all().active().is_selected_for_offer()
Patrick's avatar
Patrick committed
1316 1317 1318 1319 1320
			if customer_id:
				customer.empty_label = None
				customer.queryset = Customer.objects.filter(id=customer_id).active().may_order()
			else:
				customer.queryset = Customer.objects.all().active().may_order()
Patrick Colmant's avatar
Patrick Colmant committed
1321 1322 1323
		return form

	def save_model(self, request, purchase, form, change):
1324 1325
		# obj.preformed_by = request.user
		# obj.ip_address = utils.get_client_ip(request)
Patrick's avatar
Patrick committed
1326 1327
		purchase.distribution_date = purchase.permanence.distribution_date
		if purchase.offer_item == None:
pi's avatar
pi committed
1328 1329 1330
			offer_item_set = OfferItem.objects.all().permanence(
				purchase.permanence).product(
				purchase.product).order_by()[:1]
Patrick's avatar
Patrick committed
1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
			if offer_item_set:
				purchase.offer_item = offer_item_set[0]
		previous_price_with_tax = purchase.price_with_vat
		if purchase.invoiced_price_with_compensation:
			previous_price_with_tax = purchase.price_with_compensation

		purchase.producer = purchase.product.producer
		purchase.long_name = purchase.product.long_name
		purchase.department_for_customer = purchase.product.department_for_customer
		purchase.order_unit = purchase.product.order_unit
		purchase.vat_level = purchase.product.vat_level
		unit_price_with_vat = 0
		unit_price_with_compensation = 0
		if purchase.permanence.status < PERMANENCE_SEND or (purchase.original_unit_price == 0 and purchase.unit_deposit == 0):
Patrick's avatar
Patrick committed
1345
			purchase.original_unit_price = purchase.product.original_unit_price
Patrick's avatar
Patrick committed
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394
			purchase.unit_deposit = purchase.product.unit_deposit
			unit_price_with_vat = purchase.product.unit_price_with_vat
			unit_price_with_compensation = purchase.product.unit_price_with_compensation
		else:
			unit_price_with_vat = (purchase.original_unit_price * purchase.producer.price_list_multiplier).quantize(DECIMAL_0_01, rounding=ROUND_UP)
			unit_price_with_compensation = unit_price_with_vat
			if purchase.product.vat_level == VAT_200:
				unit_price_with_compensation = (unit_price_with_vat * Decimal(1.02)).quantize(DECIMAL_0_01, rounding=ROUND_UP)
			elif purchase.product.vat_level == VAT_300:
				unit_price_with_compensation = (unit_price_with_vat * Decimal(1.06)).quantize(DECIMAL_0_01, rounding=ROUND_UP)

		purchase.original_price = purchase.quantity * purchase.original_unit_price
		purchase.price_with_vat = purchase.quantity * unit_price_with_vat
		purchase.price_with_compensation = purchase.quantity * unit_price_with_compensation
		purchase.invoiced_price_with_compensation = False
		if purchase.product.vat_level in [VAT_200, VAT_300] and purchase.customer.vat_id != None and len(purchase.customer.vat_id) > 0:
			purchase.invoiced_price_with_compensation = True
		if purchase.order_unit in [PRODUCT_ORDER_UNIT_LOOSE_PC_KG, PRODUCT_ORDER_UNIT_NAMED_PC_KG]:
			purchase.original_price *= purchase.product.order_average_weight
			purchase.price_with_vat *= purchase.product.order_average_weight
			purchase.price_with_compensation *= purchase.product.order_average_weight
		# RoundUp
		purchase.original_price = purchase.original_price.quantize(Decimal('.01'), rounding=ROUND_UP)
		purchase.price_with_vat = purchase.price_with_vat.quantize(Decimal('.01'), rounding=ROUND_UP)
		purchase.price_with_compensation = purchase.price_with_compensation.quantize(Decimal('.01'), rounding=ROUND_UP)
		purchase.unit_deposit = purchase.product.unit_deposit
		if purchase.unit_deposit != 0:
			purchase.original_price += ( purchase.quantity * purchase.unit_deposit )
			purchase.price_with_vat += ( purchase.quantity * purchase.unit_deposit )
			purchase.price_with_compensation += ( purchase.quantity * purchase.unit_deposit )
		purchase.vat_level = purchase.product.vat_level
		purchase.quantity_for_preparation_order = purchase.quantity if purchase.order_unit in [PRODUCT_ORDER_UNIT_LOOSE_KG] else 0
		# if send_to_producer:
		# 	purchase.quantity_send_to_producer = purchase.quantity
		# purchase.save()

		if purchase.permanence.status==PERMANENCE_OPENED:
			price_with_tax = purchase.price_with_vat
			if purchase.invoiced_price_with_compensation:
				price_with_tax = purchase.price_with_compensation
			save_order_delta_amount(
				purchase.permanence.id,
				purchase.customer.id,
				previous_price_with_tax,
				price_with_tax
			)
		purchase.permanence.producers.add(purchase.producer)
		purchase.save()

Patrick Colmant's avatar
Patrick Colmant committed
1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409

	def get_actions(self, request):
		actions = super(PurchaseAdmin, self).get_actions(request)
		if 'delete_selected' in actions:
			del actions['delete_selected']
		if not actions:
			try:
				self.list_display.remove('action_checkbox')
			except ValueError:
				pass
		return actions

admin.site.register(Purchase, PurchaseAdmin)

# Accounting
Patrick's avatar
Patrick committed
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445
class BankAccountDataForm(forms.ModelForm):
	def __init__(self, *args, **kwargs):
		super(BankAccountDataForm, self).__init__(*args, **kwargs)

	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(BankAccountDataForm, self).clean(*args, **kwargs)
		customer = self.cleaned_data.get("customer")
		producer = self.cleaned_data.get("producer")
		initial_id = self.instance.id
		initial_customer = self.instance.customer
		initial_producer = self.instance.producer
		if not customer and not producer:
			if initial_id != None:
				if initial_customer == None and initial_producer == None:
					pass
				else:
					self.error('customer',_('Either a customer or a producer must be given.'))
					self.error('producer',_('Either a customer or a producer must be given.'))
			else:
				bank_account_set = BankAccount.objects.filter(operation_status=BANK_LATEST_TOTAL).order_by()[:1]
				if bank_account_set:
					# You may only insert the first latest bank total at initialisation of the website
					self.error('customer',_('Either a customer or a producer must be given.'))
					self.error('producer',_('Either a customer or a producer must be given.'))
		if customer and producer:
			self.error('customer',_('Only one customer or one producer must be given.'))
			self.error('producer',_('Only one customer or one producer must be given.'))
		return cleaned_data

	class Meta:
		model = BankAccount

Patrick Colmant's avatar
Patrick Colmant committed
1446
class BankAccountAdmin(admin.ModelAdmin):
Patrick's avatar
Patrick committed
1447
	form = BankAccountDataForm
Patrick Colmant's avatar
Patrick Colmant committed
1448
	fields=('operation_date', 
pi's avatar
pi committed
1449
		('producer', 'customer'), 'operation_comment', 'bank_amount_in',
Patrick Colmant's avatar
Patrick Colmant committed
1450
		 'bank_amount_out', 
pi's avatar
pi committed
1451
		 ('is_recorded_on_customer_invoice', 'is_recorded_on_producer_invoice'), 
Patrick Colmant's avatar
Patrick Colmant committed
1452
		 ('is_created_on', 'is_updated_on') )
Patrick's avatar
Patrick committed
1453 1454 1455 1456 1457 1458
	list_per_page = 17
	list_max_show_all = 17
	list_display = ['operation_date', 'get_producer' , 'get_customer',
	 'get_bank_amount_in', 'get_bank_amount_out', 'operation_comment'] 
	date_hierarchy = 'operation_date'
	ordering = ('-operation_date', '-id')
Patrick's avatar
Patrick committed
1459
	search_fields = ('producer__short_profile_name', 'customer__short_basket_name', 'operation_comment')
Patrick Colmant's avatar
Patrick Colmant committed
1460 1461 1462
	actions = []

	def get_readonly_fields(self, request, obj=None):
Patrick's avatar
Patrick committed
1463 1464 1465 1466
		readonly = [
			'is_created_on', 'is_updated_on',
			'is_recorded_on_customer_invoice', 'is_recorded_on_producer_invoice'
		]
Patrick Colmant's avatar
Patrick Colmant committed
1467
		if obj:
Patrick's avatar
Patrick committed
1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479
			if (obj.is_recorded_on_customer_invoice != None or obj.is_recorded_on_producer_invoice != None) or (obj.customer==None and obj.producer==None):
				readonly.append('operation_date')
				readonly.append('bank_amount_in')
				readonly.append('bank_amount_out')
				if obj.customer==None:
					readonly.append('customer')
				if obj.producer==None:
					readonly.append('producer')
				if obj.customer==None and obj.producer==None:
					readonly.append('operation_comment')
				return readonly
		return readonly
Patrick Colmant's avatar
Patrick Colmant committed
1480 1481 1482 1483

	def get_form(self,request, obj=None, **kwargs):
		form = super(BankAccountAdmin,self).get_form(request, obj, **kwargs)
		if obj:
pi's avatar
pi committed
1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495
			if obj.customer:
				customer = form.base_fields["customer"]
				customer.widget.can_add_related = False
				customer.empty_label = None
				customer.queryset = Customer.objects.id(
					obj.customer_id)
			if obj.producer:
				producer = form.base_fields["producer"]
				producer.widget.can_add_related = False
				producer.empty_label = None
				producer.queryset = Producer.objects.id(
					obj.producer_id)
Patrick Colmant's avatar
Patrick Colmant committed
1496
		else:
pi's avatar
pi committed
1497 1498 1499 1500