Skip to content
Snippets Groups Projects
Commit 5e5afa60 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

forms and views for creatng and editing vouchers

parent df5c970d
No related branches found
No related tags found
1 merge request!113Resolve "voucher functionality"
Showing
with 432 additions and 78 deletions
from luhn_algorithm import LuhnAlgorithm
from verhoeff_alogirthm import VerhoeffAlgorithm
__all__ = [VerhoeffAlgorithm, LuhnAlgorithm]
class LuhnAlgorithm(object):
def __init__(self):
pass
@staticmethod
def luhn_checksum(card_number):
def digits_of(n):
return [int(d) for d in str(n)]
digits = digits_of(card_number)
odd_digits = digits[-1::-2]
even_digits = digits[-2::-2]
checksum = 0
checksum += sum(odd_digits)
for d in even_digits:
checksum += sum(digits_of(d * 2))
return checksum % 10
@staticmethod
def is_luhn_valid(card_number):
return LuhnAlgorithm.luhn_checksum(card_number) == 0
verhoeff_multiplication_table = (
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
(1, 2, 3, 4, 0, 6, 7, 8, 9, 5),
(2, 3, 4, 0, 1, 7, 8, 9, 5, 6),
(3, 4, 0, 1, 2, 8, 9, 5, 6, 7),
(4, 0, 1, 2, 3, 9, 5, 6, 7, 8),
(5, 9, 8, 7, 6, 0, 4, 3, 2, 1),
(6, 5, 9, 8, 7, 1, 0, 4, 3, 2),
(7, 6, 5, 9, 8, 2, 1, 0, 4, 3),
(8, 7, 6, 5, 9, 3, 2, 1, 0, 4),
(9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
verhoeff_permutation_table = (
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
(1, 5, 7, 6, 2, 8, 3, 0, 9, 4),
(5, 8, 0, 3, 7, 9, 6, 1, 4, 2),
(8, 9, 1, 6, 0, 4, 3, 5, 2, 7),
(9, 4, 5, 3, 1, 2, 6, 8, 7, 0),
(4, 2, 8, 6, 5, 7, 3, 9, 0, 1),
(2, 7, 9, 3, 8, 0, 6, 4, 1, 5),
(7, 0, 4, 6, 9, 1, 3, 2, 5, 8))
class VerhoeffAlgorithm(object):
def __init__(self):
pass
@staticmethod
def verhoeff_checksum(number):
"""Calculate the Verhoeff checksum over the provided number. The checksum
is returned as an int. Valid numbers should have a checksum of 0."""
# transform number list
number = tuple(int(n) for n in reversed(str(number)))
# calculate checksum
check = 0
for i, n in enumerate(number):
check = verhoeff_multiplication_table[check][verhoeff_permutation_table[i % 8][n]]
return check
@staticmethod
def is_valid_verhoeff(number):
return VerhoeffAlgorithm.verhoeff_checksum(number) == 0
@staticmethod
def calculate_verhoeff_check_sum(number):
return str(verhoeff_multiplication_table[VerhoeffAlgorithm.verhoeff_checksum(str(number) + '0')].index(0))
...@@ -4,11 +4,13 @@ from collections import OrderedDict ...@@ -4,11 +4,13 @@ from collections import OrderedDict
from django import forms from django import forms
from django.forms import ModelForm, Form from django.forms import ModelForm, Form
from django.utils import timezone
from django.utils.dates import MONTHS from django.utils.dates import MONTHS
from web.algorithm import VerhoeffAlgorithm
from web.models import StudySubject, Worker, Appointment, Visit, AppointmentType, ContactAttempt, AppointmentTypeLink, \ from web.models import StudySubject, Worker, Appointment, Visit, AppointmentType, ContactAttempt, AppointmentTypeLink, \
Availability, Holiday, VoucherType, VoucherTypePrice Availability, Holiday, VoucherType, VoucherTypePrice, Voucher
from web.models.constants import SUBJECT_TYPE_CHOICES from web.models.constants import SUBJECT_TYPE_CHOICES, VOUCHER_STATUS_NEW, VOUCHER_STATUS_USED
from web.views.notifications import get_filter_locations from web.views.notifications import get_filter_locations
""" """
...@@ -404,3 +406,48 @@ class VoucherTypePriceForm(ModelForm): ...@@ -404,3 +406,48 @@ class VoucherTypePriceForm(ModelForm):
class Meta: class Meta:
model = VoucherTypePrice model = VoucherTypePrice
exclude = ['voucher_type'] exclude = ['voucher_type']
class VoucherForm(ModelForm):
class Meta:
model = Voucher
fields = '__all__'
def __init__(self, *args, **kwargs):
super(VoucherForm, self).__init__(*args, **kwargs)
self.fields['number'].widget.attrs['readonly'] = True
self.fields['number'].required = False
self.fields['issue_date'].widget.attrs['readonly'] = True
self.fields['issue_date'].required = False
self.fields['expiry_date'].widget.attrs['readonly'] = True
self.fields['expiry_date'].required = False
self.fields['use_date'].widget.attrs['readonly'] = True
instance = getattr(self, 'instance', None)
if instance and instance.pk:
self.fields['voucher_type'].widget.attrs['readonly'] = True
if instance.status != VOUCHER_STATUS_NEW:
self.fields['status'].widget.attrs['readonly'] = True
self.fields['feedback'].widget.attrs['readonly'] = True
self.fields['usage_partner'].widget.attrs['readonly'] = True
def clean(self):
if self.cleaned_data["status"] == VOUCHER_STATUS_USED and not self.cleaned_data["usage_partner"]:
self.add_error('usage_partner', "Partner must be defined for used voucher")
if self.cleaned_data["status"] != VOUCHER_STATUS_USED and self.cleaned_data["usage_partner"]:
self.add_error('status', "Status must be used for voucher with defined partner")
def save(self, commit=True):
instance = super(VoucherForm, self).save(commit=False)
if not instance.id:
instance.issue_date = timezone.now()
instance.expiry_date = instance.issue_date + datetime.timedelta(days=92)
max_id = str(0).zfill(5)
if Voucher.objects.latest('id'):
max_id = str(Voucher.objects.latest('id').id).zfill(5)
instance.number = max_id + VerhoeffAlgorithm.calculate_verhoeff_check_sum(max_id)
if instance.status == VOUCHER_STATUS_USED and not instance.use_date:
instance.use_date = timezone.now()
if commit:
instance.save()
...@@ -3,6 +3,7 @@ import logging ...@@ -3,6 +3,7 @@ import logging
from django import forms from django import forms
from django.forms import ModelForm from django.forms import ModelForm
from web.algorithm import VerhoeffAlgorithm, LuhnAlgorithm
from web.forms.forms import DATEPICKER_DATE_ATTRS from web.forms.forms import DATEPICKER_DATE_ATTRS
from web.models import Subject from web.models import Subject
from web.models.constants import COUNTRY_OTHER_ID from web.models.constants import COUNTRY_OTHER_ID
...@@ -26,75 +27,14 @@ def is_valid_social_security_number(number): ...@@ -26,75 +27,14 @@ def is_valid_social_security_number(number):
return False return False
if not number.isdigit(): if not number.isdigit():
return False return False
if not is_luhn_valid(number[:12]): if not LuhnAlgorithm.is_luhn_valid(number[:12]):
return False return False
if not is_valid_verhoeff(number[:11] + number[12]): if not VerhoeffAlgorithm.is_valid_verhoeff(number[:11] + number[12]):
return False return False
return True return True
def luhn_checksum(card_number):
def digits_of(n):
return [int(d) for d in str(n)]
digits = digits_of(card_number)
odd_digits = digits[-1::-2]
even_digits = digits[-2::-2]
checksum = 0
checksum += sum(odd_digits)
for d in even_digits:
checksum += sum(digits_of(d * 2))
return checksum % 10
def is_luhn_valid(card_number):
return luhn_checksum(card_number) == 0
verhoeff_multiplication_table = (
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
(1, 2, 3, 4, 0, 6, 7, 8, 9, 5),
(2, 3, 4, 0, 1, 7, 8, 9, 5, 6),
(3, 4, 0, 1, 2, 8, 9, 5, 6, 7),
(4, 0, 1, 2, 3, 9, 5, 6, 7, 8),
(5, 9, 8, 7, 6, 0, 4, 3, 2, 1),
(6, 5, 9, 8, 7, 1, 0, 4, 3, 2),
(7, 6, 5, 9, 8, 2, 1, 0, 4, 3),
(8, 7, 6, 5, 9, 3, 2, 1, 0, 4),
(9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
verhoeff_permutation_table = (
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
(1, 5, 7, 6, 2, 8, 3, 0, 9, 4),
(5, 8, 0, 3, 7, 9, 6, 1, 4, 2),
(8, 9, 1, 6, 0, 4, 3, 5, 2, 7),
(9, 4, 5, 3, 1, 2, 6, 8, 7, 0),
(4, 2, 8, 6, 5, 7, 3, 9, 0, 1),
(2, 7, 9, 3, 8, 0, 6, 4, 1, 5),
(7, 0, 4, 6, 9, 1, 3, 2, 5, 8))
def verhoeff_checksum(number):
"""Calculate the Verhoeff checksum over the provided number. The checksum
is returned as an int. Valid numbers should have a checksum of 0."""
# transform number list
number = tuple(int(n) for n in reversed(str(number)))
# calculate checksum
check = 0
for i, n in enumerate(number):
check = verhoeff_multiplication_table[check][verhoeff_permutation_table[i % 8][n]]
return check
def is_valid_verhoeff(number):
return verhoeff_checksum(number) == 0
def calculate_verhoeff_check_sum(number):
return str(verhoeff_multiplication_table[verhoeff_checksum(str(number) + '0')].index(0))
FIELD_ORDER = ["first_name", "last_name", "sex", "date_born", "social_security_number", FIELD_ORDER = ["first_name", "last_name", "sex", "date_born", "social_security_number",
"default_written_communication_language", "languages", "phone_number", "phone_number_2", "default_written_communication_language", "languages", "phone_number", "phone_number_2",
"phone_number_3", "address", "city", "postal_code", "country"] "phone_number_3", "address", "city", "postal_code", "country"]
......
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-12-08 15:00
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('web', '0091_auto_20171208_1312'),
]
operations = [
migrations.CreateModel(
name='Voucher',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('number', models.CharField(max_length=10, unique=True, verbose_name=b'Number')),
('issue_date', models.DateField(verbose_name=b'Issue date')),
('expiry_date', models.DateField(verbose_name=b'Expiry date')),
('use_date', models.DateField(verbose_name=b'Use date')),
('status', models.CharField(choices=[(b'NEW', b'New'), (b'USED', b'Used'), (b'EXPIRED', b'Expired')], default=b'NEW', max_length=20, verbose_name=b'Status')),
('feedback', models.TextField(blank=True, max_length=2000, verbose_name=b'Feedback')),
('study_subject', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to='web.StudySubject')),
('usage_partner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.Worker')),
('voucher_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.VoucherType')),
],
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-12-08 15:08
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('web', '0092_voucher'),
]
operations = [
migrations.AlterField(
model_name='voucher',
name='usage_partner',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='web.Worker'),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-12-08 15:08
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('web', '0093_auto_20171208_1508'),
]
operations = [
migrations.AlterField(
model_name='voucher',
name='usage_partner',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='web.Worker'),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-12-08 15:09
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('web', '0094_auto_20171208_1508'),
]
operations = [
migrations.AlterField(
model_name='voucher',
name='use_date',
field=models.DateField(null=True, verbose_name=b'Use date'),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-12-08 15:09
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('web', '0095_auto_20171208_1509'),
]
operations = [
migrations.AlterField(
model_name='voucher',
name='use_date',
field=models.DateField(blank=True, null=True, verbose_name=b'Use date'),
),
]
...@@ -27,6 +27,7 @@ from item import Item ...@@ -27,6 +27,7 @@ from item import Item
from language import Language from language import Language
from subject import Subject from subject import Subject
from study_subject import StudySubject from study_subject import StudySubject
from voucher import Voucher
from study_subject_list import StudySubjectList from study_subject_list import StudySubjectList
from study_visit_list import StudyVisitList from study_visit_list import StudyVisitList
from appointment_list import AppointmentList from appointment_list import AppointmentList
...@@ -38,5 +39,5 @@ from inconsistent_subject import InconsistentSubject, InconsistentField ...@@ -38,5 +39,5 @@ from inconsistent_subject import InconsistentSubject, InconsistentField
__all__ = [Study, FlyingTeam, Appointment, AppointmentType, Availability, Holiday, Item, Language, Location, Room, __all__ = [Study, FlyingTeam, Appointment, AppointmentType, Availability, Holiday, Item, Language, Location, Room,
Subject, StudySubject, StudySubjectList, SubjectColumns, StudyNotificationParameters, Subject, StudySubject, StudySubjectList, SubjectColumns, StudyNotificationParameters,
AppointmentList, AppointmentColumns, Visit, Worker, ContactAttempt, ConfigurationItem, MailTemplate, AppointmentList, AppointmentColumns, Visit, Worker, ContactAttempt, ConfigurationItem, MailTemplate,
AppointmentTypeLink, VoucherType, VoucherTypePrice, AppointmentTypeLink, VoucherType, VoucherTypePrice, Voucher,
MissingSubject, InconsistentSubject, InconsistentField, Country, StudyColumns, VisitColumns, StudyVisitList] MissingSubject, InconsistentSubject, InconsistentField, Country, StudyColumns, VisitColumns, StudyVisitList]
# coding=utf-8 # coding=utf-8
import datetime
from time import timezone
from django.db import models from django.db import models
from models import VoucherType, StudySubject, Worker from web.models import VoucherType, StudySubject, Worker
from models.constants import VOUCHER_STATUS_CHOICES, VOUCHER_STATUS_NEW from web.models.constants import VOUCHER_STATUS_CHOICES, VOUCHER_STATUS_NEW
class Voucher(models.Model): class Voucher(models.Model):
...@@ -22,7 +20,7 @@ class Voucher(models.Model): ...@@ -22,7 +20,7 @@ class Voucher(models.Model):
issue_date = models.DateField(verbose_name='Issue date', null=False) issue_date = models.DateField(verbose_name='Issue date', null=False)
expiry_date = models.DateField(verbose_name='Expiry date', null=False) expiry_date = models.DateField(verbose_name='Expiry date', null=False)
use_date = models.DateField(verbose_name='Use date') use_date = models.DateField(verbose_name='Use date', null=True, blank=True)
voucher_type = models.ForeignKey( voucher_type = models.ForeignKey(
VoucherType, VoucherType,
on_delete=models.CASCADE, on_delete=models.CASCADE,
...@@ -36,7 +34,7 @@ class Voucher(models.Model): ...@@ -36,7 +34,7 @@ class Voucher(models.Model):
editable=False editable=False
) )
status = models.CharField(max_length=20, choices=VOUCHER_STATUS_CHOICES.items(), status = models.CharField(max_length=20, choices=VOUCHER_STATUS_CHOICES,
verbose_name='Status', verbose_name='Status',
default=VOUCHER_STATUS_NEW default=VOUCHER_STATUS_NEW
) )
...@@ -49,14 +47,10 @@ class Voucher(models.Model): ...@@ -49,14 +47,10 @@ class Voucher(models.Model):
usage_partner = models.ForeignKey( usage_partner = models.ForeignKey(
Worker, Worker,
on_delete=models.CASCADE, on_delete=models.CASCADE,
null=True,
blank=True
) )
def save(self, *args, **kwargs):
if not self.id:
self.issue_date = timezone.now()
self.expiry_date = self.issue_date + datetime.timedelta(days=92)
return super(Voucher, self).save(*args, **kwargs)
def __str__(self): def __str__(self):
return "%s - %s %s" % (self.number, self.study_subject.subject.first_name, self.study_subject.subject.last_name) return "%s - %s %s" % (self.number, self.study_subject.subject.first_name, self.study_subject.subject.last_name)
......
...@@ -57,6 +57,14 @@ ...@@ -57,6 +57,14 @@
<span>Export</span> <span>Export</span>
</a> </a>
</li> </li>
<li data-desc="vouchers">
<a href="{% url 'web.views.vouchers' %}">
<i class="fa fa-user-md"></i>
<span>Vouchers</span>
</a>
</li>
<li data-desc="configuration" class="treeview"> <li data-desc="configuration" class="treeview">
<a href="#"> <a href="#">
<i class="fa fa-wrench"></i> <span>Configuration</span> <i class="fa fa-wrench"></i> <span>Configuration</span>
......
{% extends "vouchers/add_edit.html" %}
{% block page_header %}New voucher{% endblock page_header %}
{% block title %}{{ block.super }} - Add voucher{% endblock %}
{% block form-title %}Enter voucher details{% endblock %}
{% block save-button %}Add{% endblock %}
{% extends "_base.html" %}
{% load static %}
{% load filters %}
{% block styles %}
{{ block.super }}
<link rel="stylesheet" href="{% static 'AdminLTE/plugins/awesomplete/awesomplete.css' %}"/>
{% endblock styles %}
{% block ui_active_tab %}'configuration'{% endblock ui_active_tab %}
{% block page_description %}{% endblock page_description %}
{% block breadcrumb %}
{% include "vouchers/breadcrumb.html" %}
{% endblock breadcrumb %}
{% block maincontent %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="box box-success">
<div class="box-header with-border">
<h3 class="box-title">{% block form-title %}Enter voucher details{% endblock %}</h3>
</div>
<form method="post" action="" class="form-horizontal" enctype="multipart/form-data">
{% csrf_token %}
<div class="box-body">
{% for field in form %}
<div class="form-group {% if field.errors %}has-error{% endif %}">
<label class="col-sm-4 col-lg-offset-1 col-lg-2 control-label">
{{ field.label }}
</label>
<div class="col-sm-8 col-lg-4">
{{ field|add_class:'form-control' }}
{% if field.errors %}
<span class="help-block">{{ field.errors }}</span>
{% endif %}
</div>
</div>
{% endfor %}
</div><!-- /.box-body -->
<div class="box-footer">
<div class="col-sm-6">
<button type="submit" class="btn btn-block btn-success">{% block save-button %}
Add{% endblock %}
</button>
</div>
<div class="col-sm-6">
<a href="{% url 'web.views.vouchers' %}"
class="btn btn-block btn-default">Cancel</a>
</div>
</div><!-- /.box-footer -->
</form>
</div>
</div>
</div>
{% endblock %}
{% endblock maincontent %}
{% block scripts %}
{{ block.super }}
<script src="{% static 'AdminLTE/plugins/awesomplete/awesomplete.min.js' %}"></script>
{% endblock scripts %}
\ No newline at end of file
<li><a href="{% url 'web.views.appointments' %}"><i class="fa fa-dashboard"></i> Dashboard</a></li>
<li class="active"><a href="{% url 'web.views.vouchers' %}">Vouchers</a></li>
\ No newline at end of file
{% extends "vouchers/add_edit.html" %}
{% block page_header %}Edit voucher "{{ voucher.number }}"{% endblock page_header %}
{% block title %}{{ block.super }} - Edit voucher "{{ voucher.number }}"{% endblock %}
{% block form-title %}Enter voucher details{% endblock %}
{% block save-button %}Save{% endblock %}
{% extends "_base.html" %}
{% load static %}
{% block styles %}
{{ block.super }}
<!-- DataTables -->
<link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}">
{% endblock styles %}
{% block ui_active_tab %}'configuration'{% endblock ui_active_tab %}
{% block page_header %}Vouchers{% endblock page_header %}
{% block page_description %}{% endblock page_description %}
{% block breadcrumb %}
{% include "vouchers/breadcrumb.html" %}
{% endblock breadcrumb %}
{% block maincontent %}
<div class="box-body">
<table id="table" class="table table-bordered table-striped">
<thead>
<tr>
<th>Number</th>
<th>First name</th>
<th>Last name</th>
<th>Issue date</th>
<th>Expiry date</th>
<th>Status</th>
<th>Use date</th>
<th>Partner</th>
<th>Feedback</th>
<th>Edit</th>
</tr>
</thead>
<tbody>
{% for voucher in vouchers %}
<tr>
<td>{{ voucher.number }}</td>
<td>{{ voucher.study_subject.subject.first_name }}</td>
<td>{{ voucher.study_subject.subject.last_name }}</td>
<td>{{ voucher.issue_date }}</td>
<td>{{ voucher.expiry_date }}</td>
<td>{{ voucher.status }}</td>
<td>{{ voucher.use_date }}</td>
<td>{{ voucher.usage_partner.first_name }} {{ voucher.usage_partner.last_name }}</td>
<td>{{ voucher.feedback }}</td>
<td><a href="{% url 'web.views.voucher_edit' voucher.id %}"><i class="fa fa-edit"></i></a></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock maincontent %}
{% block scripts %}
{{ block.super }}
<script src="{% static 'AdminLTE/plugins/datatables/jquery.dataTables.min.js' %}"></script>
<script src="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.min.js' %}"></script>
<script>
$(function () {
$('#table').DataTable({
"paging": true,
"lengthChange": false,
"searching": true,
"ordering": true,
"info": true,
"autoWidth": false
});
});
</script>
{% endblock scripts %}
...@@ -178,6 +178,14 @@ urlpatterns = [ ...@@ -178,6 +178,14 @@ urlpatterns = [
url(r'^voucher_types/(?P<voucher_type_id>\d+)/prices/(?P<pk>\d+)/edit$', url(r'^voucher_types/(?P<voucher_type_id>\d+)/prices/(?P<pk>\d+)/edit$',
views.voucher_type_price.VoucherTypePriceEditView.as_view(), name='web.views.voucher_type_price_edit'), views.voucher_type_price.VoucherTypePriceEditView.as_view(), name='web.views.voucher_type_price_edit'),
####################
# VOUCHERS #
####################
url(r'^vouchers$', views.voucher.VoucherListView.as_view(), name='web.views.vouchers'),
url(r'^vouchers/add$', views.voucher.VoucherCreateView.as_view(), name='web.views.voucher_add'),
url(r'^vouchers/(?P<pk>\d+)/edit$', views.voucher.VoucherEditView.as_view(), name='web.views.voucher_edit'),
#################### ####################
# STATISTICS # # STATISTICS #
#################### ####################
......
...@@ -72,6 +72,7 @@ import export ...@@ -72,6 +72,7 @@ import export
import contact_attempt import contact_attempt
import configuration_item import configuration_item
import language import language
import voucher
import voucher_type import voucher_type
import voucher_type_price import voucher_type_price
import redcap import redcap
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment