diff --git a/core/models.py b/core/models.py index c3135377..40323810 100644 --- a/core/models.py +++ b/core/models.py @@ -7,6 +7,8 @@ from django.core.exceptions import ValidationError from django.core.urlresolvers import reverse from django.conf import settings from django.db import transaction +from django.contrib.staticfiles.storage import staticfiles_storage +from django.utils.html import escape from phonenumber_field.modelfields import PhoneNumberField from datetime import datetime, timedelta, date @@ -281,6 +283,12 @@ class User(AbstractBaseUser): return "%s (%s)" % (self.get_full_name(), self.nick_name) return self.get_full_name() + def get_age(self): + """ + Returns the age + """ + return timezone.now().year - self.date_of_birth.year + def email_user(self, subject, message, from_email=None, **kwargs): """ Sends an email to this User. @@ -360,9 +368,9 @@ class User(AbstractBaseUser): %s """ % ( - self.profile_pict.get_download_url() if self.profile_pict else "/static/core/img/na.gif", + self.profile_pict.get_download_url() if self.profile_pict else staticfiles_storage.url("core/img/na.gif"), _("Profile"), - self.get_display_name(), + escape(self.get_display_name()), ) diff --git a/core/static/core/js/script.js b/core/static/core/js/script.js index ded1a1cb..1a36dee0 100644 --- a/core/static/core/js/script.js +++ b/core/static/core/js/script.js @@ -35,8 +35,4 @@ $( function() { popup.html('
'); popup.dialog({title: $(this).text()}).dialog( "open" ); }); - $('.select_date').datepicker({ - changeMonth: true, - changeYear: true - }); } ); diff --git a/core/static/core/js/ui/i18n/datepicker-fr.js b/core/static/core/js/ui/i18n/datepicker-fr.js new file mode 100644 index 00000000..9e39fbd6 --- /dev/null +++ b/core/static/core/js/ui/i18n/datepicker-fr.js @@ -0,0 +1,39 @@ +/* French initialisation for the jQuery UI date picker plugin. */ +/* Written by Keith Wood (kbwood{at}iinet.com.au), + Stéphane Nahmani (sholby@sholby.net), + Stéphane Raimbault */ +( function( factory ) { + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ "../widgets/datepicker" ], factory ); + } else { + + // Browser globals + factory( jQuery.datepicker ); + } +}( function( datepicker ) { + +datepicker.regional.fr = { + closeText: "Fermer", + prevText: "Précédent", + nextText: "Suivant", + currentText: "Aujourd'hui", + monthNames: [ "janvier", "février", "mars", "avril", "mai", "juin", + "juillet", "août", "septembre", "octobre", "novembre", "décembre" ], + monthNamesShort: [ "janv.", "févr.", "mars", "avr.", "mai", "juin", + "juil.", "août", "sept.", "oct.", "nov.", "déc." ], + dayNames: [ "dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi" ], + dayNamesShort: [ "dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam." ], + dayNamesMin: [ "D","L","M","M","J","V","S" ], + weekHeader: "Sem.", + dateFormat: "dd/mm/yy", + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: "" }; +datepicker.setDefaults( datepicker.regional.fr ); + +return datepicker.regional.fr; + +} ) ); diff --git a/core/templates/core/base.jinja b/core/templates/core/base.jinja index 39fe6ca0..832ea758 100644 --- a/core/templates/core/base.jinja +++ b/core/templates/core/base.jinja @@ -69,6 +69,7 @@ {% block script %} + @@ -85,6 +86,14 @@ $('.select_multiple').multipleSelect({ position: 'top', {% endif %} }); +$('.select_date').datepicker({ + changeMonth: true, + changeYear: true, + dayNamesShort: $.datepicker.regional[ "{{ request.LANGUAGE_CODE }}" ].dayNamesShort, + dayNames: $.datepicker.regional[ "{{ request.LANGUAGE_CODE }}" ].dayNames, + monthNamesShort: $.datepicker.regional[ "{{ request.LANGUAGE_CODE }}" ].monthNamesShort, + monthNames: $.datepicker.regional[ "{{ request.LANGUAGE_CODE }}" ].monthNames, +}).datepicker( $.datepicker.regional[ "{{ request.LANGUAGE_CODE }}"] ); {% endblock %} diff --git a/core/templates/core/macros.jinja b/core/templates/core/macros.jinja index 6cff32db..87d39c2f 100644 --- a/core/templates/core/macros.jinja +++ b/core/templates/core/macros.jinja @@ -4,15 +4,8 @@ {% macro user_link_with_pict(user) -%} - - {% if user.profile_pict %} - {% trans %}Profile{% endtrans %} - {% else %} - {% trans %}Profile{% endtrans %} - {% endif %} - - {{ user.get_display_name() }} - + {{ user.get_mini_item()|safe }} + {%- endmacro %} {% macro user_mini_profile(user) %} @@ -27,7 +20,7 @@

« {{ user.nick_name }} »

{% endif %} {% if user.date_of_birth %} -

{% trans %}Born: {% endtrans %}{{ user.date_of_birth|date("d/m/Y") }}

+

{% trans %}Born: {% endtrans %}{{ user.date_of_birth|date("d/m/Y") }} ({{ user.get_age() }})

{% endif %} {% if user.promo %}

Promo {{ user.promo }} diff --git a/counter/migrations/0015_auto_20160820_0158.py b/counter/migrations/0015_auto_20160820_0158.py new file mode 100644 index 00000000..5113297c --- /dev/null +++ b/counter/migrations/0015_auto_20160820_0158.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('counter', '0014_auto_20160819_1650'), + ] + + operations = [ + migrations.AddField( + model_name='product', + name='limit_age', + field=models.IntegerField(default=0, verbose_name='limit age'), + ), + migrations.AddField( + model_name='product', + name='tray', + field=models.BooleanField(default=False, verbose_name='tray price'), + ), + ] diff --git a/counter/models.py b/counter/models.py index ade72cd2..d835435d 100644 --- a/counter/models.py +++ b/counter/models.py @@ -83,6 +83,8 @@ class Product(models.Model): special_selling_price = CurrencyField(_('special selling price')) icon = models.ImageField(upload_to='products', null=True, blank=True) club = models.ForeignKey(Club, related_name="products") + limit_age = models.IntegerField(_('limit age'), default=0) + tray = models.BooleanField(_('tray price'), default=False) class Meta: verbose_name = _('product') diff --git a/counter/templates/counter/counter_click.jinja b/counter/templates/counter/counter_click.jinja index dcfb0d86..b6c93046 100644 --- a/counter/templates/counter/counter_click.jinja +++ b/counter/templates/counter/counter_click.jinja @@ -43,6 +43,9 @@ {% endif %}

{% trans %}Selling{% endtrans %}
+ {% if request.session['too_young'] %} +

{% trans %}Too young for that product{% endtrans %}

+ {% endif %} {% if request.session['not_enough'] %}

{% trans %}Not enough money{% endtrans %}

{% endif %} diff --git a/counter/templates/counter/counter_main.jinja b/counter/templates/counter/counter_main.jinja index 16e05c27..df903fe0 100644 --- a/counter/templates/counter/counter_main.jinja +++ b/counter/templates/counter/counter_main.jinja @@ -8,6 +8,10 @@ {% endmacro %} +{% block title %} +{% trans counter_name=counter %}{{ counter_name }} counter{% endtrans %} +{% endblock %} + {% block content %}

{% trans counter_name=counter %}{{ counter_name }} counter{% endtrans %}

diff --git a/counter/views.py b/counter/views.py index d44a5446..42d5cd53 100644 --- a/counter/views.py +++ b/counter/views.py @@ -117,6 +117,7 @@ class CounterClick(DetailView): request.session['basket'] = {} request.session['basket_total'] = 0 request.session['not_enough'] = False + request.session['too_young'] = False self.refill_form = None ret = super(CounterClick, self).get(request, *args, **kwargs) if ((self.object.type != "BAR" and not request.user.is_authenticated()) or @@ -138,6 +139,7 @@ class CounterClick(DetailView): request.session['basket'] = {} request.session['basket_total'] = 0 request.session['not_enough'] = False + request.session['too_young'] = False if self.object.type != "BAR": self.operator = request.user elif self.is_barman_price(): @@ -166,8 +168,11 @@ class CounterClick(DetailView): else: return False + def get_product(self, pid): + return Product.objects.filter(pk=int(pid)).first() + def get_price(self, pid): - p = Product.objects.filter(pk=pid).first() + p = self.get_product(pid) if self.is_barman_price(): price = p.special_selling_price else: @@ -181,7 +186,11 @@ class CounterClick(DetailView): return total / 100 def add_product(self, request, q = 1, p=None): - """ Add a product to the basket """ + """ + Add a product to the basket + q is the quantity passed as integer + p is the product id, passed as an integer + """ pid = p or request.POST['product_id'] pid = str(pid) price = self.get_price(pid) @@ -189,11 +198,15 @@ class CounterClick(DetailView): if self.customer.amount < (total + q*float(price)): request.session['not_enough'] = True return False + if self.customer.user.get_age() < self.get_product(pid).limit_age: + request.session['too_young'] = True + return False if pid in request.session['basket']: request.session['basket'][pid]['qty'] += q else: request.session['basket'][pid] = {'qty': q, 'price': int(price*100)} request.session['not_enough'] = False # Reset not_enough to save the session + request.session['too_young'] = False request.session.modified = True return True @@ -421,7 +434,7 @@ class ProductEditForm(forms.ModelForm): class Meta: model = Product fields = ['name', 'description', 'product_type', 'code', 'purchase_price', - 'selling_price', 'special_selling_price', 'icon', 'club'] + 'selling_price', 'special_selling_price', 'icon', 'club', 'limit_age', 'tray'] counters = make_ajax_field(Product, 'counters', 'counters', show_help_text=False, label='Counters', help_text="Guy", required=False) # TODO FIXME diff --git a/migrate.py b/migrate.py index 1622e19c..b54c5a55 100644 --- a/migrate.py +++ b/migrate.py @@ -452,6 +452,8 @@ def migrate_products(): selling_price=r['prix_vente_prod']/100, special_selling_price=r['prix_vente_barman_prod']/100, club=club, + limit_age=r['mineur'] or 0, + tray=bool(r['plateau']), ) new.save() except Exception as e: @@ -554,7 +556,9 @@ def migrate_sellings(): ) new.save() except ValidationError as e: - print(repr(e) + " for %s (%s)" % (customer, customer.user.id)) + print(repr(e) + " for %s (%s), assigning to root" % (customer, customer.user.id)) + new.customer = root.customer + new.save() except Exception as e: print("FAIL to migrate selling %s: %s" % (r['id_facture'], repr(e))) cur.close() @@ -592,12 +596,12 @@ def main(): # migrate_counters() # migrate_permanencies() # migrate_typeproducts() - # migrate_products() - # migrate_products_to_counter() + migrate_products() + migrate_products_to_counter() # reset_customer_amount() # migrate_invoices() - migrate_refillings() - migrate_sellings() + # migrate_refillings() + # migrate_sellings() reset_index('core', 'counter') if __name__ == "__main__":