From 9dcc51f2211385239b0272bdbf2466637c874f35 Mon Sep 17 00:00:00 2001 From: Filipp Lepalaan Date: Sun, 30 May 2021 10:34:01 +0300 Subject: Check-in fixes and improvements --- servo/forms/checkin.py | 54 ++++++++++++++++++++++------------- servo/models/customer.py | 4 +-- servo/models/device.py | 4 +-- servo/static/css/login.css | 11 +++++-- servo/static/css/servo.css | 1 + servo/templates/accounts/login.html | 2 +- servo/templates/checkin/newindex.html | 8 +++--- servo/templates/default.html | 10 ++----- servo/templates/orders/close.html | 1 + servo/templates/orders/toolbar.html | 5 +++- servo/validators.py | 5 +++- servo/views/checkin.py | 13 +++++---- 12 files changed, 72 insertions(+), 46 deletions(-) diff --git a/servo/forms/checkin.py b/servo/forms/checkin.py index 6a6cf9d..7141bc8 100644 --- a/servo/forms/checkin.py +++ b/servo/forms/checkin.py @@ -7,6 +7,7 @@ from datetime import date from django.conf import settings from django_countries import countries from django.core.validators import RegexValidator +from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from django.forms import SelectDateWidget @@ -40,15 +41,11 @@ class ConfirmationForm(forms.Form): class DeviceForm(forms.ModelForm): - """The form for editing devices in the /checkin view""" - + """ + Form for entering devices in the /checkin view + """ required_css_class = 'required' - purchase_country = forms.ChoiceField( - label=_('Country'), - choices=countries, - initial=settings.INSTALL_COUNTRY - ) accessories = forms.CharField( required=False, label=_('Accessories'), @@ -64,10 +61,10 @@ class DeviceForm(forms.ModelForm): ) condition = forms.CharField( - label=_('Condition of device'), required=False, + label=_('Condition of device'), widget=forms.Textarea(attrs={'class': 'span12', 'rows': 3}), - help_text=_("Please describe the condition of the device") + help_text=_('Please describe the condition of the device. Will be shown on the print-out.') ) queue = forms.ModelChoiceField( @@ -123,9 +120,10 @@ class DeviceForm(forms.ModelForm): class CustomerForm(forms.Form): - - from django.utils.safestring import mark_safe - + """ + Form for entering customer info in /checkin + Not using a ModelForm for a reason. + """ required_css_class = 'required' fname = forms.CharField(label=_('First name')) @@ -139,15 +137,12 @@ class CustomerForm(forms.Form): label=_('Email address'), widget=forms.TextInput(attrs={'class': 'span12'}) ) - phone = forms.CharField( - label=_('Phone number'), - validators=[phone_validator] - ) + phone = forms.CharField(label=_('Phone number')) address = forms.CharField(label=_('Address')) country = forms.ChoiceField( label=_('Country'), choices=Customer.COUNTRY_CHOICES, - initial=settings.INSTALL_COUNTRY + initial=settings.INSTALL_COUNTRY.upper() ) city = forms.CharField(label=_('City')) postal_code = forms.CharField(label=_('Postal Code')) @@ -179,6 +174,24 @@ class CustomerForm(forms.Form): label=_('Notify by Email') ) + def clean(self): + cd = super(CustomerForm, self).clean() + + phone = cd.get('phone') + country = cd.get('country') + + if len(phone) < 1: + return cd + + try: + phonenumbers.parse(phone, country) + except phonenumbers.NumberParseException as e: + print(e) + msg = _('Enter a valid phone number') + self._errors["phone"] = self.error_class([msg]) + + return cd + def clean_fname(self): v = self.cleaned_data.get('fname') return v.capitalize() @@ -242,20 +255,21 @@ class IssueForm(forms.Form): issue_description = forms.CharField( min_length=10, label=_(u'Problem description'), + help_text=_('Will appear on the print-out'), widget=forms.Textarea(attrs={'class': 'span12'}) ) attachment = forms.FileField( required=False, - label=_(u'Attachment'), + label=_('Attachment'), validators=[file_upload_validator], - help_text=_(u'Please use this to attach relevant documents') + help_text=_('Please use this to attach relevant documents') ) notes = forms.CharField( required=False, label=_(u'Notes'), widget=forms.Textarea(attrs={'class': 'span12'}), - help_text=_(u'Will not appear on the print-out') + help_text=_('Will not appear on the print-out') ) diff --git a/servo/models/customer.py b/servo/models/customer.py index 9d81371..bb34892 100644 --- a/servo/models/customer.py +++ b/servo/models/customer.py @@ -93,9 +93,9 @@ class Customer(MPTTModel): country = models.CharField( blank=True, max_length=2, + choices=COUNTRY_CHOICES, verbose_name=_('Country'), - default=defaults.country, - choices=COUNTRY_CHOICES + default=settings.INSTALL_COUNTRY.upper(), ) photo = models.ImageField( null=True, diff --git a/servo/models/device.py b/servo/models/device.py index d994d20..671dc3e 100644 --- a/servo/models/device.py +++ b/servo/models/device.py @@ -141,8 +141,8 @@ class Device(models.Model): blank=True, max_length=128, choices=countries, - default=defaults.country, - verbose_name=_("Purchase Country") + verbose_name=_("Country Of Purchase"), + default=settings.INSTALL_COUNTRY.upper(), ) sla_description = models.TextField(null=True, editable=False) diff --git a/servo/static/css/login.css b/servo/static/css/login.css index 11363b3..62cc0c7 100755 --- a/servo/static/css/login.css +++ b/servo/static/css/login.css @@ -4,6 +4,7 @@ body { background-color: #f5f5f5; } + form { margin-left: 10px; margin-top: 30px; @@ -13,8 +14,8 @@ form { margin: auto; position: absolute; top: 0; left: 0; bottom: 0; right: 0; - width: 250px; height: 250px; - padding: 70px; + width: 250px; + padding: 250px 70px; background-color: #fff; border: 1px solid #e5e5e5; -webkit-border-radius: 5px; @@ -29,3 +30,9 @@ form { width: 251px; display: block; } + +div.alert { + width: 100%; + position: fixed; + z-index: 99999; +} diff --git a/servo/static/css/servo.css b/servo/static/css/servo.css index ba1a3c8..2f19ef2 100755 --- a/servo/static/css/servo.css +++ b/servo/static/css/servo.css @@ -191,6 +191,7 @@ textarea { .typeahead { margin-top: 0; } + .alert .errorlist { margin: 5px; } diff --git a/servo/templates/accounts/login.html b/servo/templates/accounts/login.html index e77c753..80daf06 100755 --- a/servo/templates/accounts/login.html +++ b/servo/templates/accounts/login.html @@ -13,7 +13,7 @@ {{ form.password }} -
+

{% if show_checkin %} {% trans "Check-in" %} diff --git a/servo/templates/checkin/newindex.html b/servo/templates/checkin/newindex.html index f1fc035..55a52fa 100644 --- a/servo/templates/checkin/newindex.html +++ b/servo/templates/checkin/newindex.html @@ -6,7 +6,7 @@ {% block main %} {% comment %} @@ -66,15 +66,15 @@ {% include "checkin/device_form.html" %}
{% include "checkin/customer_form.html" %}
- {% if request.user.is_authenticated %} + {% if request.user.is_authenticated and tags %}
diff --git a/servo/templates/default.html b/servo/templates/default.html index 15de430..d770655 100755 --- a/servo/templates/default.html +++ b/servo/templates/default.html @@ -64,19 +64,13 @@ {% with request.user as user %} {% endwith %} diff --git a/servo/templates/orders/close.html b/servo/templates/orders/close.html index b80f862..a53db5e 100755 --- a/servo/templates/orders/close.html +++ b/servo/templates/orders/close.html @@ -12,6 +12,7 @@ {% block footer %}
{% csrf_token %} +
{% endblock footer %} diff --git a/servo/templates/orders/toolbar.html b/servo/templates/orders/toolbar.html index 286d93e..56fe851 100755 --- a/servo/templates/orders/toolbar.html +++ b/servo/templates/orders/toolbar.html @@ -26,6 +26,9 @@ {% if order.invoice_set.count %}
  • {% trans "Receipt" %}
  • {% trans "Dispatch" context "noun" %}
  • + {% else %} +
  • {% trans "Receipt" %}
  • +
  • {% trans "Dispatch" context "noun" %}
  • {% endif %}
    @@ -61,7 +64,7 @@ {% if order.can_dispatch %} {% trans "Dispatch" %} {% else %} - {% trans "Dispatch" %} + {% trans "Dispatch" %} {% endif %} {% if perms.servo.change_order and order.can_close %} {% trans "Close" %} diff --git a/servo/validators.py b/servo/validators.py index 6fc3a91..97fe974 100644 --- a/servo/validators.py +++ b/servo/validators.py @@ -11,18 +11,21 @@ from django.utils.translation import ugettext as _ def phone_validator(val): try: - phonenumbers.parse(val, settings.INSTALL_COUNTRY) + phonenumbers.parse(val.upper(), settings.INSTALL_COUNTRY) except phonenumbers.NumberParseException: raise ValidationError(_('%s is not a valid phone number') % val) + def apple_sn_validator(val): if validate(val.upper()) not in ('serialNumber', 'alternateDeviceId',): raise ValidationError(_(u'%s is not a valid serial or IMEI number') % val) + def sn_validator(val): if not re.match(r'^\w*$', val): raise ValidationError(_('Serial numbers may only contain letters and numbers')) + def file_upload_validator(val): allowed = ['.pdf', '.zip', '.doc', '.jpg', '.jpeg', '.png', '.txt', '.mov', '.m4v'] ext = os.path.splitext(val.name)[1].lower() diff --git a/servo/views/checkin.py b/servo/views/checkin.py index 513625b..fc1719a 100644 --- a/servo/views/checkin.py +++ b/servo/views/checkin.py @@ -161,9 +161,12 @@ def init_session(request): user = get_object_or_404(User, pk=user_id) request.session['checkin_locations'] = Location.get_checkin_list() - checkin_users = User.get_checkin_group() - queryset = checkin_users.filter(location=location) - request.session['checkin_users'] = User.serialize(queryset) + try: + checkin_users = User.get_checkin_group() + queryset = checkin_users.filter(location=location) + request.session['checkin_users'] = User.serialize(queryset) + except Exception as e: + messages.error(request, _("Failed to launch check-in interface. Please check your system settings.")) request.session['checkin_user'] = user.pk request.session['checkin_location'] = location.pk @@ -351,7 +354,7 @@ def index(request): order.add_device(device, user) - note = Note(created_by=user, body=idata['issue_description']) + note = Note(created_by=user, body=idata['issue_description'], type=Note.T_PROBLEM) note.is_reported = True note.order = order note.save() @@ -385,7 +388,7 @@ def index(request): # mark down internal notes (only if logged in) if len(idata.get('notes')): - note = Note(created_by=user, body=idata['notes']) + note = Note(created_by=user, body=idata['notes'], type=Note.T_NOTE) note.is_reported = False note.order = order note.save() -- cgit v1.2.3