# This file is part of Shuup.
#
# Copyright (c) 2012-2021, Shuup Commerce Inc. All rights reserved.
#
# This source code is licensed under the OSL-3.0 license found in the
# LICENSE file in the root directory of this source tree.
from decimal import Decimal
from django.forms import DecimalField, Field, MultipleChoiceField, Select, SelectMultiple
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from numbers import Number
[docs]class PercentageField(DecimalField):
MULTIPLIER = Decimal(100)
[docs] def prepare_value(self, value):
# Percentage values are 0..1 in database, so multiply by 100
if value is not None and isinstance(value, Number):
value *= self.MULTIPLIER
return super(PercentageField, self).prepare_value(value)
[docs] def to_python(self, value):
value = super(PercentageField, self).to_python(value)
if value is not None:
# We got a value, so divide it by 100 to get the 0..1 range value
value /= self.MULTIPLIER
return value
[docs]class Select2ModelField(Field):
widget = Select
def __init__(self, model, *args, **kwargs):
self.model = model
super(Select2ModelField, self).__init__(*args, **kwargs)
[docs] def prepare_value(self, value):
return getattr(value, "pk", value)
[docs] def to_python(self, value):
if value:
return self.model.objects.filter(pk=value).first()
[docs]class Select2MultipleField(Field):
widget = SelectMultiple
def __init__(self, model, search_mode=None, *args, **kwargs):
self.model = model
if search_mode:
self.search_mode = search_mode
super(Select2MultipleField, self).__init__(*args, **kwargs)
[docs] def prepare_value(self, value):
values = [getattr(v, "pk", v) for v in value or []]
# make sure to add the initial values as choices to the field
if values and not self.widget.choices:
from django.utils.encoding import force_text
self.widget.choices = [
(instance.pk, force_text(instance)) for instance in self.model.objects.filter(pk__in=values)
]
return values
[docs] def to_python(self, value):
value = super(Select2MultipleField, self).to_python(value)
# Here we have sometimes None which will cause errors when
# saving related fields so let's fallback to empty list
return value or []
[docs]class Select2ModelMultipleField(Select2MultipleField):
"""
Just like Select2MultipleField, but return instances instead of ids.
"""
[docs] def prepare_value(self, value):
return [getattr(v, "pk", v) for v in value or []]
[docs] def to_python(self, value):
if value and isinstance(value, (list, tuple)):
value = [v for v in value if v]
if value:
return self.model.objects.filter(pk__in=value)
return []
[docs]class Select2MultipleMainProductField(Select2MultipleField):
"""Search only from parent and normal products."""
[docs] def widget_attrs(self, widget):
attrs = super(Select2MultipleMainProductField, self).widget_attrs(widget)
attrs.update({"data-search-mode": "main"})
return attrs
[docs]class WeekdaysSelectMultiple(SelectMultiple):
[docs]class WeekdayField(MultipleChoiceField):
widget = WeekdaysSelectMultiple
DAYS_OF_THE_WEEK = [
(0, _("Monday")),
(1, _("Tuesday")),
(2, _("Wednesday")),
(3, _("Thursday")),
(4, _("Friday")),
(5, _("Saturday")),
(6, _("Sunday")),
]
def __init__(self, choices=(), required=True, widget=None, label=None, initial=None, help_text="", *args, **kwargs):
if not choices:
choices = self.DAYS_OF_THE_WEEK
super().__init__(
choices=choices,
required=required,
widget=widget,
label=label,
initial=initial,
help_text=help_text,
**kwargs
)
[docs] def clean(self, value):
return ",".join(super(WeekdayField, self).clean(value))