Revert "lingo: add generic cell handling all invoice categories (#10483)"
This reverts commit 58822107c8
.
This commit is contained in:
parent
fcc6cc2148
commit
34c5ee1281
|
@ -1,39 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import models, migrations
|
|
||||||
import multiselectfield.db.fields
|
|
||||||
import ckeditor.fields
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('auth', '0001_initial'),
|
|
||||||
('data', '0016_feedcell_limit'),
|
|
||||||
('lingo', '0017_auto_20160327_0831'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='InvoicesCell',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
|
||||||
('placeholder', models.CharField(max_length=20)),
|
|
||||||
('order', models.PositiveIntegerField()),
|
|
||||||
('slug', models.SlugField(verbose_name='Slug', blank=True)),
|
|
||||||
('public', models.BooleanField(default=True, verbose_name='Public')),
|
|
||||||
('restricted_to_unlogged', models.BooleanField(default=False, verbose_name='Restrict to unlogged users')),
|
|
||||||
('regie', models.CharField(max_length=50, verbose_name='Regie', blank=True)),
|
|
||||||
('title', models.CharField(max_length=200, verbose_name='Title', blank=True)),
|
|
||||||
('text', ckeditor.fields.RichTextField(null=True, verbose_name='Text', blank=True)),
|
|
||||||
('categories', multiselectfield.db.fields.MultiSelectField(max_length=11, verbose_name='Categories', choices=[(b'active', 'Active'), (b'past', 'Past')])),
|
|
||||||
('groups', models.ManyToManyField(to='auth.Group', verbose_name='Groups', blank=True)),
|
|
||||||
('page', models.ForeignKey(to='data.Page')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Invoices',
|
|
||||||
},
|
|
||||||
bases=(models.Model,),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,76 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import models, migrations
|
|
||||||
|
|
||||||
def migrate_activeitems_cells(apps, schema_editor):
|
|
||||||
InvoicesCell = apps.get_model('lingo', 'InvoicesCell')
|
|
||||||
Page = apps.get_model('data', 'Page')
|
|
||||||
ActiveItems = apps.get_model('lingo', 'ActiveItems')
|
|
||||||
for cell in ActiveItems.objects.all():
|
|
||||||
page = Page.objects.get(pk=cell.page_id)
|
|
||||||
InvoicesCell.objects.get_or_create(order=cell.order,
|
|
||||||
page=page, placeholder=cell.placeholder,
|
|
||||||
public=cell.public, regie=cell.regie,
|
|
||||||
restricted_to_unlogged=cell.restricted_to_unlogged,
|
|
||||||
slug=cell.slug, text=cell.text, title=cell.title,
|
|
||||||
categories='active'
|
|
||||||
)
|
|
||||||
cell.delete()
|
|
||||||
|
|
||||||
def migrate_itemshistory_cells(apps, schema_editor):
|
|
||||||
InvoicesCell = apps.get_model('lingo', 'InvoicesCell')
|
|
||||||
Page = apps.get_model('data', 'Page')
|
|
||||||
ItemsHistory = apps.get_model('lingo', 'ItemsHistory')
|
|
||||||
for cell in ItemsHistory.objects.all():
|
|
||||||
page = Page.objects.get(pk=cell.page_id)
|
|
||||||
InvoicesCell.objects.get_or_create(order=cell.order,
|
|
||||||
page=page, placeholder=cell.placeholder,
|
|
||||||
public=cell.public, regie=cell.regie,
|
|
||||||
restricted_to_unlogged=cell.restricted_to_unlogged,
|
|
||||||
slug=cell.slug, text=cell.text, title=cell.title,
|
|
||||||
categories='past'
|
|
||||||
)
|
|
||||||
cell.delete()
|
|
||||||
|
|
||||||
def restore_activeitems_cells(apps, schema_editor):
|
|
||||||
InvoicesCell = apps.get_model('lingo', 'InvoicesCell')
|
|
||||||
Page = apps.get_model('data', 'Page')
|
|
||||||
ActiveItems = apps.get_model('lingo', 'ActiveItems')
|
|
||||||
for cell in InvoicesCell.objects.filter(categories__contains='active'):
|
|
||||||
page = Page.objects.get(pk=cell.page_id)
|
|
||||||
ActiveItems.objects.get_or_create(order=cell.order,
|
|
||||||
page=page, placeholder=cell.placeholder,
|
|
||||||
public=cell.public, regie=cell.regie,
|
|
||||||
restricted_to_unlogged=cell.restricted_to_unlogged,
|
|
||||||
slug=cell.slug, text=cell.text, title=cell.title
|
|
||||||
)
|
|
||||||
cell.delete()
|
|
||||||
|
|
||||||
def restore_itemshistory_cells(apps, schema_editor):
|
|
||||||
InvoicesCell = apps.get_model('lingo', 'InvoicesCell')
|
|
||||||
Page = apps.get_model('data', 'Page')
|
|
||||||
ItemsHistory = apps.get_model('lingo', 'ItemsHistory')
|
|
||||||
for cell in InvoicesCell.objects.filter(categories__contains='past'):
|
|
||||||
page = Page.objects.get(pk=cell.page_id)
|
|
||||||
ItemsHistory.objects.get_or_create(order=cell.order,
|
|
||||||
page=page, placeholder=cell.placeholder,
|
|
||||||
public=cell.public, regie=cell.regie,
|
|
||||||
restricted_to_unlogged=cell.restricted_to_unlogged,
|
|
||||||
slug=cell.slug, text=cell.text, title=cell.title
|
|
||||||
)
|
|
||||||
cell.delete()
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('lingo', '0018_invoicescell'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RunPython(migrate_activeitems_cells,
|
|
||||||
restore_activeitems_cells),
|
|
||||||
migrations.RunPython(migrate_itemshistory_cells,
|
|
||||||
restore_itemshistory_cells)
|
|
||||||
]
|
|
|
@ -36,15 +36,12 @@ from django.core.exceptions import PermissionDenied
|
||||||
from django.utils.http import urlencode
|
from django.utils.http import urlencode
|
||||||
|
|
||||||
from ckeditor.fields import RichTextField
|
from ckeditor.fields import RichTextField
|
||||||
from multiselectfield import MultiSelectField
|
|
||||||
|
|
||||||
from combo.data.models import CellBase
|
from combo.data.models import CellBase
|
||||||
from combo.data.library import register_cell_class
|
from combo.data.library import register_cell_class
|
||||||
from combo.utils import NothingInCacheException, sign_url
|
from combo.utils import NothingInCacheException, sign_url
|
||||||
|
|
||||||
EXPIRED = 9999
|
EXPIRED = 9999
|
||||||
ACTIVE_ITEMS = 'active'
|
|
||||||
PAST_ITEMS = 'past'
|
|
||||||
|
|
||||||
|
|
||||||
SERVICES = [
|
SERVICES = [
|
||||||
|
@ -58,11 +55,6 @@ SERVICES = [
|
||||||
(eopayment.PAYZEN, _('PayZen')),
|
(eopayment.PAYZEN, _('PayZen')),
|
||||||
]
|
]
|
||||||
|
|
||||||
INVOICE_CATEGORIES = (
|
|
||||||
(ACTIVE_ITEMS, _('Active')),
|
|
||||||
(PAST_ITEMS, _('Past'))
|
|
||||||
)
|
|
||||||
|
|
||||||
def build_remote_item(data, regie):
|
def build_remote_item(data, regie):
|
||||||
return RemoteItem(id=data.get('id'), regie=regie,
|
return RemoteItem(id=data.get('id'), regie=regie,
|
||||||
creation_date=data['created'],
|
creation_date=data['created'],
|
||||||
|
@ -366,62 +358,6 @@ class LingoBasketLinkCell(CellBase):
|
||||||
return basket_template.render(context)
|
return basket_template.render(context)
|
||||||
|
|
||||||
|
|
||||||
@register_cell_class
|
|
||||||
class InvoicesCell(CellBase):
|
|
||||||
regie = models.CharField(_('Regie'), max_length=50, blank=True)
|
|
||||||
title = models.CharField(_('Title'), max_length=200, blank=True)
|
|
||||||
text = RichTextField(_('Text'), blank=True, null=True)
|
|
||||||
categories = MultiSelectField(_('Categories'), choices=INVOICE_CATEGORIES)
|
|
||||||
|
|
||||||
user_dependant = True
|
|
||||||
template_name = 'lingo/combo/items.html'
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name = _('Invoices')
|
|
||||||
|
|
||||||
class Media:
|
|
||||||
js = ('xstatic/jquery-ui.min.js', 'js/gadjo.js',)
|
|
||||||
css = {'all': ('xstatic/themes/smoothness/jquery-ui.min.css', )}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def is_enabled(cls):
|
|
||||||
return Regie.objects.count() > 0
|
|
||||||
|
|
||||||
def get_default_form_class(self):
|
|
||||||
fields = ['title', 'categories', 'text']
|
|
||||||
widgets = {}
|
|
||||||
if Regie.objects.count() > 1:
|
|
||||||
regies = [('', _('All'))]
|
|
||||||
regies.extend([(r.slug, r.label) for r in Regie.objects.all()])
|
|
||||||
widgets['regie'] = Select(choices=regies)
|
|
||||||
fields.insert(0, 'regie')
|
|
||||||
return model_forms.modelform_factory(self.__class__, fields=fields, widgets=widgets)
|
|
||||||
|
|
||||||
def get_regies(self):
|
|
||||||
if self.regie:
|
|
||||||
return [Regie.objects.get(slug=self.regie)]
|
|
||||||
return Regie.objects.all()
|
|
||||||
|
|
||||||
def get_cell_extra_context(self, context):
|
|
||||||
ctx = {'title': self.title, 'text': self.text}
|
|
||||||
invoices = []
|
|
||||||
for r in self.get_regies():
|
|
||||||
if ACTIVE_ITEMS in self.categories:
|
|
||||||
invoices.extend(r.get_items(self.context))
|
|
||||||
if PAST_ITEMS in self.categories:
|
|
||||||
invoices.extend(r.get_past_items(self.context))
|
|
||||||
# sort items by creation date
|
|
||||||
invoices.sort(key=lambda i: i.creation_date, reverse=True)
|
|
||||||
ctx.update({'items': invoices})
|
|
||||||
return ctx
|
|
||||||
|
|
||||||
def render(self, context):
|
|
||||||
self.context = context
|
|
||||||
if not context.get('synchronous'):
|
|
||||||
raise NothingInCacheException()
|
|
||||||
return super(InvoicesCell, self).render(context)
|
|
||||||
|
|
||||||
|
|
||||||
class Items(CellBase):
|
class Items(CellBase):
|
||||||
regie = models.CharField(_('Regie'), max_length=50, blank=True)
|
regie = models.CharField(_('Regie'), max_length=50, blank=True)
|
||||||
title = models.CharField(_('Title'), max_length=200, blank=True)
|
title = models.CharField(_('Title'), max_length=200, blank=True)
|
||||||
|
|
143
combo/fields.py
143
combo/fields.py
|
@ -1,143 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# This is a modified copy of https://github.com/goinnn/django-multiselectfield
|
|
||||||
#
|
|
||||||
# Copyright (c) 2012 by Pablo Martín <goinnn@gmail.com>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with this programe. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import django
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from django.core import validators
|
|
||||||
from django import forms
|
|
||||||
from django.utils.text import capfirst
|
|
||||||
from django.core import exceptions
|
|
||||||
|
|
||||||
if sys.version_info[0] == 2:
|
|
||||||
string_type = unicode
|
|
||||||
else:
|
|
||||||
string_type = str
|
|
||||||
|
|
||||||
# Code from six egg https://bitbucket.org/gutworth/six/src/a3641cb211cc360848f1e2dd92e9ae6cd1de55dd/six.py?at=default
|
|
||||||
|
|
||||||
def get_max_length(choices, max_length, default=200):
|
|
||||||
if max_length is None:
|
|
||||||
if choices:
|
|
||||||
return len(','.join([string_type(key) for key, label in choices]))
|
|
||||||
else:
|
|
||||||
return default
|
|
||||||
return max_length
|
|
||||||
|
|
||||||
|
|
||||||
class MaxValueMultiFieldValidator(validators.MaxLengthValidator):
|
|
||||||
clean = lambda self, x: len(','.join(x))
|
|
||||||
code = 'max_multifield_value'
|
|
||||||
|
|
||||||
|
|
||||||
class MultiSelectFormField(forms.MultipleChoiceField):
|
|
||||||
widget = forms.CheckboxSelectMultiple
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
self.max_choices = kwargs.pop('max_choices', None)
|
|
||||||
self.max_length = kwargs.pop('max_length', None)
|
|
||||||
super(MultiSelectFormField, self).__init__(*args, **kwargs)
|
|
||||||
self.max_length = get_max_length(self.choices, self.max_length)
|
|
||||||
self.validators.append(MaxValueMultiFieldValidator(self.max_length))
|
|
||||||
|
|
||||||
|
|
||||||
class MultiSelectField(models.CharField):
|
|
||||||
""" Choice values can not contain commas. """
|
|
||||||
|
|
||||||
__metaclass__ = models.SubfieldBase
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
self.max_choices = kwargs.pop('max_choices', None)
|
|
||||||
super(MultiSelectField, self).__init__(*args, **kwargs)
|
|
||||||
self.max_length = get_max_length(self.choices, self.max_length)
|
|
||||||
self.validators[0] = MaxValueMultiFieldValidator(self.max_length)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def flatchoices(self):
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_choices_default(self):
|
|
||||||
return self.get_choices(include_blank=False)
|
|
||||||
|
|
||||||
def get_choices_selected(self, arr_choices):
|
|
||||||
choices_selected = []
|
|
||||||
for choice_selected in arr_choices:
|
|
||||||
choices_selected.append(string_type(choice_selected[0]))
|
|
||||||
return choices_selected
|
|
||||||
|
|
||||||
def value_to_string(self, obj):
|
|
||||||
value = self._get_val_from_obj(obj)
|
|
||||||
return self.get_prep_value(value)
|
|
||||||
|
|
||||||
def validate(self, value, model_instance):
|
|
||||||
arr_choices = self.get_choices_selected(self.get_choices_default())
|
|
||||||
for opt_select in value:
|
|
||||||
if (opt_select not in arr_choices):
|
|
||||||
raise exceptions.ValidationError(self.error_messages['invalid_choice'] % value)
|
|
||||||
|
|
||||||
def get_default(self):
|
|
||||||
default = super(MultiSelectField, self).get_default()
|
|
||||||
if isinstance(default, int):
|
|
||||||
default = string_type(default)
|
|
||||||
return default
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {'required': not self.blank,
|
|
||||||
'label': capfirst(self.verbose_name),
|
|
||||||
'help_text': self.help_text,
|
|
||||||
'choices': self.choices,
|
|
||||||
'max_length': self.max_length,
|
|
||||||
'max_choices': self.max_choices}
|
|
||||||
if self.has_default():
|
|
||||||
defaults['initial'] = self.get_default()
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return MultiSelectFormField(**defaults)
|
|
||||||
|
|
||||||
def get_prep_value(self, value):
|
|
||||||
return '' if value is None else ",".join(value)
|
|
||||||
|
|
||||||
def to_python(self, value):
|
|
||||||
if value:
|
|
||||||
return value if isinstance(value, list) else value.split(',')
|
|
||||||
|
|
||||||
def contribute_to_class(self, cls, name):
|
|
||||||
super(MultiSelectField, self).contribute_to_class(cls, name)
|
|
||||||
if self.choices:
|
|
||||||
def get_list(obj):
|
|
||||||
fieldname = name
|
|
||||||
choicedict = dict(self.choices)
|
|
||||||
display = []
|
|
||||||
if getattr(obj, fieldname):
|
|
||||||
for value in getattr(obj, fieldname):
|
|
||||||
item_display = choicedict.get(value, None)
|
|
||||||
if item_display is None:
|
|
||||||
try:
|
|
||||||
item_display = choicedict.get(int(value), value)
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
item_display = value
|
|
||||||
display.append(string_type(item_display))
|
|
||||||
return display
|
|
||||||
|
|
||||||
def get_display(obj):
|
|
||||||
return ", ".join(get_list(obj))
|
|
||||||
|
|
||||||
setattr(cls, 'get_%s_list' % self.name, get_list)
|
|
||||||
setattr(cls, 'get_%s_display' % self.name, get_display)
|
|
|
@ -70,7 +70,6 @@ INSTALLED_APPS = (
|
||||||
'combo.apps.fargo',
|
'combo.apps.fargo',
|
||||||
'combo.apps.usersearch',
|
'combo.apps.usersearch',
|
||||||
'xstatic.pkg.chartnew_js',
|
'xstatic.pkg.chartnew_js',
|
||||||
'multiselectfield'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
INSTALLED_APPS = plugins.register_plugins_apps(INSTALLED_APPS)
|
INSTALLED_APPS = plugins.register_plugins_apps(INSTALLED_APPS)
|
||||||
|
|
|
@ -15,7 +15,6 @@ Depends: ${misc:Depends}, ${python:Depends},
|
||||||
python-feedparser,
|
python-feedparser,
|
||||||
python-django-cmsplugin-blurp,
|
python-django-cmsplugin-blurp,
|
||||||
python-xstatic-chartnew-js
|
python-xstatic-chartnew-js
|
||||||
python-django-multiselectfield
|
|
||||||
Recommends: python-django-mellon
|
Recommends: python-django-mellon
|
||||||
Conflicts: python-lingo
|
Conflicts: python-lingo
|
||||||
Description: Portal Management System (Python module)
|
Description: Portal Management System (Python module)
|
||||||
|
|
1
setup.py
1
setup.py
|
@ -113,7 +113,6 @@ setup(
|
||||||
'XStatic-ChartNew.js',
|
'XStatic-ChartNew.js',
|
||||||
'eopayment>=1.3',
|
'eopayment>=1.3',
|
||||||
'python-dateutil',
|
'python-dateutil',
|
||||||
'django-multiselectfield',
|
|
||||||
],
|
],
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
cmdclass={
|
cmdclass={
|
||||||
|
|
|
@ -6,9 +6,7 @@ from django.template import Context
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from combo.data.models import Page
|
from combo.data.models import Page
|
||||||
from combo.utils import NothingInCacheException
|
|
||||||
from combo.apps.lingo.models import Regie, BasketItem, Transaction
|
from combo.apps.lingo.models import Regie, BasketItem, Transaction
|
||||||
from combo.apps.lingo.models import ACTIVE_ITEMS, InvoicesCell
|
|
||||||
from combo.apps.lingo.models import LingoBasketCell, LingoRecentTransactionsCell
|
from combo.apps.lingo.models import LingoBasketCell, LingoRecentTransactionsCell
|
||||||
|
|
||||||
pytestmark = pytest.mark.django_db
|
pytestmark = pytest.mark.django_db
|
||||||
|
@ -70,16 +68,3 @@ def test_basket_cell(regie, user):
|
||||||
|
|
||||||
content = cell.render(context)
|
content = cell.render(context)
|
||||||
assert '12345' in content
|
assert '12345' in content
|
||||||
|
|
||||||
def test_invoices_cell(regie, user):
|
|
||||||
page = Page(title='invoices', slug='test_invoices_cell', template_name='standard')
|
|
||||||
page.save()
|
|
||||||
cell = InvoicesCell(page=page, placeholder='content', order=0,
|
|
||||||
regie=regie.slug, title='Active Invoices', categories=ACTIVE_ITEMS)
|
|
||||||
context = Context({'request': RequestFactory().get('/')})
|
|
||||||
context['request'].user = user
|
|
||||||
assert cell.is_relevant(context) is True
|
|
||||||
with pytest.raises(NothingInCacheException):
|
|
||||||
cell.render(context)
|
|
||||||
context['synchronous'] = True
|
|
||||||
assert 'Active Invoices' in cell.render(context)
|
|
||||||
|
|
Loading…
Reference in New Issue