Commit dbf0653b authored by Skia's avatar Skia

Add support for product buying groups + many cosmetics and form pimping

parent 00f05c71
Pipeline #130 failed with stage
in 2 minutes and 9 seconds
from ajax_select import register, LookupChannel
from core.views.site import search_user
from core.models import User
from core.models import User, Group
from club.models import Club
from counter.models import Product, Counter
@register('users')
......@@ -17,6 +18,32 @@ class UsersLookup(LookupChannel):
def format_item_display(self, item):
return item.get_display_name()
@register('groups')
class GroupsLookup(LookupChannel):
model = Group
def get_query(self, q, request):
return self.model.objects.filter(name__icontains=q)[:50]
def format_match(self, obj):
return obj.name
def format_item_display(self, item):
return item.name
@register('clubs')
class ClubLookup(LookupChannel):
model = Club
def get_query(self, q, request):
return self.model.objects.filter(name__icontains=q)[:50]
def format_match(self, obj):
return obj.name
def format_item_display(self, item):
return item.name
@register('counters')
class CountersLookup(LookupChannel):
model = Counter
......
......@@ -368,7 +368,7 @@ class User(AbstractBaseUser):
<em>%s</em>
</a>
""" % (
self.profile_pict.get_download_url() if self.profile_pict else staticfiles_storage.url("core/img/na.gif"),
self.profile_pict.get_download_url() if self.profile_pict else staticfiles_storage.url("core/img/unknown.jpg"),
_("Profile"),
escape(self.get_display_name()),
)
......
......@@ -183,10 +183,10 @@ tbody>tr:hover {
}
#user_profile h4 { border-bottom: 1px solid grey; max-width: 60%; }
#user_profile #left_column {
max-width: 59%;
width: 59%;
}
#user_profile #right_column {
max-width: 40%;
width: 40%;
float: right;
font-style: italic;
}
......
......@@ -25,7 +25,7 @@
<a href="{{ url('core:user_tools') }}">{% trans %}Tools{% endtrans %}</a> |
<a href="{{ url('core:logout') }}">{% trans %}Logout{% endtrans %}</a>
<form action="{{ url('core:search') }}" method="GET">
<input type="text" placeholder="{% trans %}Search{% endtrans %}" name="query" />
<input type="text" placeholder="{% trans %}Search{% endtrans %}" name="query" id="search" />
<input type="submit" value="{% trans %}Search{% endtrans %}" style="display: none;" />
</form>
{% endif %}
......@@ -94,6 +94,13 @@ $('.select_date').datepicker({
monthNamesShort: $.datepicker.regional[ "{{ request.LANGUAGE_CODE }}" ].monthNamesShort,
monthNames: $.datepicker.regional[ "{{ request.LANGUAGE_CODE }}" ].monthNames,
}).datepicker( $.datepicker.regional[ "{{ request.LANGUAGE_CODE }}"] );
$(document).keydown(function (e) {
if ($(e.target).is('input')) { return }
if (e.keyCode == 83) {
$("#search").focus();
return false;
}
});
</script>
{% endblock %}
</body>
......
......@@ -11,7 +11,9 @@
<div id="right_column">
<div id="pictures">
{% if profile.profile_pict %}
<img src="{{ profile.profile_pict.get_download_url() }}" alt="{% trans %}Profile{% endtrans %}" />
<img src="{{ profile.profile_pict.get_download_url() }}" alt="{% trans %}Profile{% endtrans %}" id="picture" />
{% else %}
<img src="{{ static('core/img/unknown.jpg') }}" alt="{% trans %}Profile{% endtrans %}" id="picture" />
{% endif %}
</div>
<p id="quote"><em>{{ profile.quote }}</em></p>
......@@ -53,4 +55,23 @@
{% endblock %}
{% block script %}
{{ super() }}
<script>
$( function() {
var keys = [];
var pattern = "71,85,89,71,85,89";
$(document).keydown(function (e) {
keys.push(e.keyCode);
if (keys.toString()==pattern) {
keys = [];
$("#right_column img").attr("src", "{{ static('core/img/yug.jpg') }}");
}
if (keys.length==6) {
keys.shift();
}
});
} );
</script>
{% endblock %}
......@@ -7,7 +7,7 @@
{% block infos %}
{% if profile.permanencies %}
<div>
<h3>Permanencies</h3>
<h3>{% trans %}Permanencies{% endtrans %}</h3>
<p>Total: {{ total_perm_time }}</p>
<p>Foyer: {{ total_foyer_time }}</p>
<p>MDE: {{ total_mde_time }}</p>
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('core', '0007_auto_20160813_0522'),
('counter', '0015_auto_20160820_0158'),
]
operations = [
migrations.AddField(
model_name='product',
name='buying_group',
field=models.ForeignKey(blank=True, on_delete=django.db.models.deletion.SET_NULL, verbose_name='buying group', related_name='products', to='core.Group', null=True),
),
migrations.AlterField(
model_name='product',
name='club',
field=models.ForeignKey(verbose_name='club', to='club.Club', related_name='products'),
),
migrations.AlterField(
model_name='product',
name='icon',
field=models.ImageField(blank=True, null=True, upload_to='products', verbose_name='icon'),
),
migrations.AlterField(
model_name='product',
name='product_type',
field=models.ForeignKey(blank=True, on_delete=django.db.models.deletion.SET_NULL, verbose_name='parent product', related_name='children_products', to='counter.Product', null=True),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('counter', '0016_auto_20160820_1923'),
]
operations = [
migrations.AddField(
model_name='product',
name='parent_product',
field=models.ForeignKey(to='counter.Product', null=True, related_name='children_products', on_delete=django.db.models.deletion.SET_NULL, verbose_name='parent product', blank=True),
),
migrations.AlterField(
model_name='product',
name='product_type',
field=models.ForeignKey(to='counter.ProductType', null=True, related_name='products', on_delete=django.db.models.deletion.SET_NULL, verbose_name='product type', blank=True),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0007_auto_20160813_0522'),
('counter', '0017_auto_20160820_2047'),
]
operations = [
migrations.RemoveField(
model_name='product',
name='buying_group',
),
migrations.AddField(
model_name='product',
name='buying_group',
field=models.ManyToManyField(related_name='products', to='core.Group', verbose_name='buying group'),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('counter', '0018_auto_20160820_2051'),
]
operations = [
migrations.RenameField(
model_name='product',
old_name='buying_group',
new_name='buying_groups',
),
]
......@@ -76,15 +76,19 @@ class Product(models.Model):
"""
name = models.CharField(_('name'), max_length=64)
description = models.TextField(_('description'), blank=True)
product_type = models.ForeignKey(ProductType, related_name='products', null=True, blank=True)
product_type = models.ForeignKey(ProductType, related_name='products', verbose_name=_("product type"), null=True, blank=True,
on_delete=models.SET_NULL)
code = models.CharField(_('code'), max_length=16, blank=True)
purchase_price = CurrencyField(_('purchase price'))
selling_price = CurrencyField(_('selling price'))
special_selling_price = CurrencyField(_('special selling price'))
icon = models.ImageField(upload_to='products', null=True, blank=True)
club = models.ForeignKey(Club, related_name="products")
icon = models.ImageField(upload_to='products', null=True, blank=True, verbose_name=_("icon"))
club = models.ForeignKey(Club, related_name="products", verbose_name=_("club"))
limit_age = models.IntegerField(_('limit age'), default=0)
tray = models.BooleanField(_('tray price'), default=False)
parent_product = models.ForeignKey('self', related_name='children_products', verbose_name=_("parent product"), null=True,
blank=True, on_delete=models.SET_NULL)
buying_groups = models.ManyToManyField(Group, related_name='products', verbose_name=_("buying groups"))
class Meta:
verbose_name = _('product')
......
......@@ -46,6 +46,9 @@
{% if request.session['too_young'] %}
<p><strong>{% trans %}Too young for that product{% endtrans %}</strong></p>
{% endif %}
{% if request.session['not_allowed'] %}
<p><strong>{% trans %}Not allowed for that product{% endtrans %}</strong></p>
{% endif %}
{% if request.session['not_enough'] %}
<p><strong>{% trans %}Not enough money{% endtrans %}</strong></p>
{% endif %}
......@@ -79,11 +82,16 @@
<input type="hidden" name="action" value="cancel">
<input type="submit" value="{% trans %}Cancel{% endtrans %}" />
</form>
<p><strong>{% trans %}Products: {% endtrans %}</strong>
{% for p in counter.products.all() %}
{{ add_product(p.id, p.name) }}
<div><strong>{% trans %}Products: {% endtrans %}</strong>
{% for t in categories %}
{% if counter.products.filter(product_type=t).exists() %}
<h5>{{ t }}</h5>
{% for p in counter.products.filter(product_type=t).all() %}
{{ add_product(p.id, p.name) }}
{% endfor %}
{% endif %}
{% endfor %}
</p>
</div>
</div>
{% endblock %}
......
......@@ -123,6 +123,7 @@ class CounterClick(DetailView):
request.session['basket_total'] = 0
request.session['not_enough'] = False
request.session['too_young'] = False
request.session['not_allowed'] = 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
......@@ -145,6 +146,7 @@ class CounterClick(DetailView):
request.session['basket_total'] = 0
request.session['not_enough'] = False
request.session['too_young'] = False
request.session['not_allowed'] = False
if self.object.type != "BAR":
self.operator = request.user
elif self.is_barman_price():
......@@ -208,6 +210,13 @@ class CounterClick(DetailView):
price = self.get_price(pid)
total = self.sum_basket(request)
product = self.get_product(pid)
can_buy = False
for g in product.buying_groups.all():
if request.user.is_in_group(g.name):
can_buy = True
if not can_buy:
request.session['not_allowed'] = True
return False
bq = 0 # Bonus quantity, for trays
if product.tray: # Handle the tray to adjust the quantity q to add and the bonus quantity bq
total_qty_mod_6 = self.get_total_quantity_for_pid(request, pid) % 6
......@@ -224,8 +233,6 @@ class CounterClick(DetailView):
request.session['basket'][pid]['bonus_qty'] += bq
else: # or create if not
request.session['basket'][pid] = {'qty': q, 'price': int(price*100), 'bonus_qty': bq}
request.session['not_enough'] = False # Reset not_enough to save the session
request.session['too_young'] = False
request.session.modified = True
return True
......@@ -321,6 +328,7 @@ class CounterClick(DetailView):
kwargs['customer'] = self.customer
kwargs['basket_total'] = self.sum_basket(self.request)
kwargs['refill_form'] = self.refill_form or RefillForm()
kwargs['categories'] = ProductType.objects.all()
return kwargs
class CounterLogin(RedirectView):
......@@ -451,23 +459,42 @@ class ProductListView(CanEditPropMixin, ListView):
model = Product
template_name = 'counter/product_list.jinja'
class ProductEditForm(forms.ModelForm):
class Meta:
model = Product
fields = ['name', 'description', 'product_type', 'code', 'parent_product', 'buying_groups', 'purchase_price',
'selling_price', 'special_selling_price', 'icon', 'club', 'limit_age', 'tray']
parent_product = AutoCompleteSelectField('products', show_help_text=False, label=_("Parent product"), required=False)
buying_groups = AutoCompleteSelectMultipleField('groups', show_help_text=False, help_text="", label=_("Buying groups"))
club = AutoCompleteSelectField('clubs', show_help_text=False)
counters = AutoCompleteSelectMultipleField('counters', show_help_text=False, help_text="", label=_("Counters"), required=False)
def __init__(self, *args, **kwargs):
super(ProductEditForm, self).__init__(*args, **kwargs)
if self.instance.id:
self.fields['counters'].initial = [str(c.id) for c in self.instance.counters.all()]
def save(self, *args, **kwargs):
ret = super(ProductEditForm, self).save(*args, **kwargs)
if self.fields['counters'].initial:
for cid in self.fields['counters'].initial:
c = Counter.objects.filter(id=int(cid)).first()
c.products.remove(self.instance)
c.save()
for cid in self.cleaned_data['counters']:
c = Counter.objects.filter(id=int(cid)).first()
c.products.add(self.instance)
c.save()
return ret
class ProductCreateView(CanCreateMixin, CreateView):
"""
A create view for the admins
"""
model = Product
fields = ['name', 'description', 'product_type', 'code', 'purchase_price',
'selling_price', 'special_selling_price', 'icon', 'club']
form_class = ProductEditForm
template_name = 'core/create.jinja'
class ProductEditForm(forms.ModelForm):
class Meta:
model = Product
fields = ['name', 'description', 'product_type', 'code', 'purchase_price',
'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
class ProductEditView(CanEditPropMixin, UpdateView):
"""
An edit view for the admins
......@@ -476,8 +503,6 @@ class ProductEditView(CanEditPropMixin, UpdateView):
form_class = ProductEditForm
pk_url_kwarg = "product_id"
template_name = 'core/edit.jinja'
# TODO: add management of the 'counters' ForeignKey
class RefillingDeleteView(CanEditPropMixin, DeleteView):
"""
......
......@@ -55,9 +55,12 @@ class EbouticMain(TemplateView):
""" Add a product to the basket """
try:
p = Product.objects.filter(id=int(request.POST['product_id'])).first()
self.basket.add_product(p)
except:
pass
for g in p.buying_groups.all():
if request.user.is_in_group(g.name):
self.basket.add_product(p)
break
except Exception as e:
print(repr(e))
def del_product(self, request):
""" Delete a product from the basket """
......
This diff is collapsed.
......@@ -83,7 +83,6 @@ def migrate_users():
}
def get_random_free_email():
id = random.randrange(4000)
email = "no_email_%s@git.an" % random.randrange(4000, 40000)
while User.objects.filter(email=email).exists():
email = "no_email_%s@git.an" % random.randrange(4000, 40000)
......@@ -602,10 +601,10 @@ def main():
migrate_products()
migrate_products_to_counter()
# reset_customer_amount()
migrate_invoices()
migrate_refillings()
migrate_invoices()
migrate_sellings()
# reset_index('core', 'counter', 'subscription')
reset_index('core', 'club', 'subscription', 'accounting', 'eboutic', 'launderette', 'counter')
if __name__ == "__main__":
main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment