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

Merge branch '187-voucher-types' into 'master'

Resolve "voucher types"

Closes #187

See merge request NCER-PD/scheduling-system!112
parents 373bc97a 531324ce
No related branches found
No related tags found
1 merge request!112Resolve "voucher types"
Pipeline #
Showing
with 520 additions and 11 deletions
......@@ -7,7 +7,7 @@ from django.forms import ModelForm, Form
from django.utils.dates import MONTHS
from web.models import StudySubject, Worker, Appointment, Visit, AppointmentType, ContactAttempt, AppointmentTypeLink, \
Availability, Holiday
Availability, Holiday, VoucherType, VoucherTypePrice
from web.models.constants import SUBJECT_TYPE_CHOICES
from web.views.notifications import get_filter_locations
......@@ -385,3 +385,22 @@ class HolidayAddForm(ModelForm):
availabilities = worker.availability_set.all()
for availability in availabilities:
validate_availability_conflict(self, self.cleaned_data, availability)
class VoucherTypeForm(ModelForm):
class Meta:
model = VoucherType
exclude = ['study']
class VoucherTypePriceForm(ModelForm):
start_date = forms.DateField(label="Start date",
widget=forms.DateInput(DATEPICKER_DATE_ATTRS, "%Y-%m-%d")
)
end_date = forms.DateField(label="End date",
widget=forms.DateInput(DATEPICKER_DATE_ATTRS, "%Y-%m-%d")
)
class Meta:
model = VoucherTypePrice
exclude = ['voucher_type']
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-12-08 09:00
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('web', '0089_unfinshed_appointment_list'),
]
operations = [
migrations.CreateModel(
name='VoucherType',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('code', models.CharField(max_length=20, verbose_name=b'Code')),
('description', models.CharField(blank=True, max_length=1024, verbose_name=b'Description')),
('study', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.Study')),
],
),
migrations.CreateModel(
name='VoucherTypePrice',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('price', models.DecimalField(decimal_places=2, max_digits=6, verbose_name=b'Price')),
('start_date', models.DateField(verbose_name=b'Start date')),
('end_date', models.DateField(verbose_name=b'End date')),
('voucher_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.VoucherType')),
],
),
]
......@@ -14,6 +14,8 @@ from study_columns import StudyColumns
from visit_columns import VisitColumns
from notification_columns import StudyNotificationParameters
from study import Study
from voucher_type import VoucherType
from voucher_type_price import VoucherTypePrice
from room import Room
from visit import Visit
from worker import Worker
......@@ -36,5 +38,5 @@ from inconsistent_subject import InconsistentSubject, InconsistentField
__all__ = [Study, FlyingTeam, Appointment, AppointmentType, Availability, Holiday, Item, Language, Location, Room,
Subject, StudySubject, StudySubjectList, SubjectColumns, StudyNotificationParameters,
AppointmentList, AppointmentColumns, Visit, Worker, ContactAttempt, ConfigurationItem, MailTemplate,
AppointmentTypeLink,
AppointmentTypeLink, VoucherType, VoucherTypePrice,
MissingSubject, InconsistentSubject, InconsistentField, Country, StudyColumns, VisitColumns, StudyVisitList]
# coding=utf-8
from django.db import models
from web.models import Study
class VoucherType(models.Model):
class Meta:
app_label = 'web'
code = models.CharField(max_length=20, verbose_name='Code', blank=False, null=False)
description = models.CharField(max_length=1024, verbose_name='Description', blank=True, null=False)
study = models.ForeignKey(
Study,
on_delete=models.CASCADE,
null=False,
)
def __str__(self):
return "%s" % self.code
def __unicode__(self):
return "%s" % self.code
# coding=utf-8
from django.db import models
from web.models import VoucherType
class VoucherTypePrice(models.Model):
class Meta:
app_label = 'web'
price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name='Price', null=False, blank=False)
start_date = models.DateField(verbose_name='Start date', null=False, blank=False)
end_date = models.DateField(verbose_name='End date', null=False, blank=False)
voucher_type = models.ForeignKey(
VoucherType,
on_delete=models.CASCADE,
null=False,
related_name="prices"
)
......@@ -80,9 +80,7 @@ desired effect
<!-- Menu toggle button -->
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-envelope-o"></i>
<span class="label label-success">
0
</span>
<span class="label label-success">0</span>
</a>
<ul class="dropdown-menu">
<li class="header">
......
{% extends "mail_templates/add_edit.html" %}
{% extends "languages/add_edit.html" %}
{% block page_header %}Edit language "{{ language.name }}"{% endblock page_header %}
......
......@@ -66,9 +66,8 @@
</a>
<ul class="treeview-menu">
<li><a href="{% url 'web.views.configuration' %}">General</a></li>
<li>
<a href="{% url 'web.views.languages' %}">Languages</a>
</li>
<li><a href="{% url 'web.views.languages' %}">Languages</a></li>
<li><a href="{% url 'web.views.voucher_types' %}">Voucher types</a></li>
</ul>
</li>
......
{% extends "voucher_type_prices/add_edit.html" %}
{% block page_header %}New voucher type price{% endblock page_header %}
{% block title %}{{ block.super }} - Add new voucher type price{% endblock %}
{% block form-title %}Enter voucher type price 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' %}"/>
{% include "includes/datepicker.css.html" %}
{% include "includes/datetimepicker.css.html" %}
{% endblock styles %}
{% block ui_active_tab %}'configuration'{% endblock ui_active_tab %}
{% block page_description %}{% endblock page_description %}
{% block breadcrumb %}
{% include "voucher_type_prices/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 type price 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.voucher_types' %}"
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>
{% include "includes/datepicker.js.html" %}
{% include "includes/datetimepicker.js.html" %}
{% 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.voucher_types' %}">Voucher types</a></li>
\ No newline at end of file
{% extends "voucher_type_prices/add_edit.html" %}
{% block page_header %}Edit voucher type price {% endblock page_header %}
{% block title %}{{ block.super }} - Edit voucher type price "{{ voucher_type.code }}"{% endblock %}
{% block form-title %}Enter voucher type price details{% endblock %}
{% block save-button %}Save{% endblock %}
{% extends "voucher_types/add_edit.html" %}
{% block page_header %}New voucher type{% endblock page_header %}
{% block title %}{{ block.super }} - Add new voucher type{% endblock %}
{% block form-title %}Enter voucher type 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 "voucher_types/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 type 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.voucher_types' %}"
class="btn btn-block btn-default">Cancel</a>
</div>
</div><!-- /.box-footer -->
</form>
{% if voucher_type.study %}
<div class="box-header with-border">
<h3>Prices <a title="add a new contact attempt"
id="add-contact-attempt"
href="{% url 'web.views.voucher_type_price_add' voucher_type.id %}"
class="text-primary"
><i class="fa fa-plus-circle text-success"></i></a></h3>
</div>
<div class="box-body">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th class="text-center">From</th>
<th class="text-center">To</th>
<th class="text-center">Price</th>
<th class="text-center">Edit</th>
</tr>
</thead>
<tbody>
{% for voucher_type_price in voucher_type.prices.all %}
<tr>
<td>{{ voucher_type_price.start_date }}</td>
<td>{{ voucher_type_price.end_date }}</td>
<td>{{ voucher_type_price.price }}</td>
<td><a title="edit price"
href="{% url 'web.views.voucher_type_price_edit' voucher_type.id voucher_type_price.id %}"
type="button"
class="btn btn-block btn-default"
>EDIT</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
</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.voucher_types' %}">Voucher types</a></li>
\ No newline at end of file
{% extends "voucher_types/add_edit.html" %}
{% block page_header %}Edit voucher type "{{ voucher_type.code }}"{% endblock page_header %}
{% block title %}{{ block.super }} - Edit voucher type "{{ voucher_type.code }}"{% endblock %}
{% block form-title %}Enter voucher type 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 %}Voucher types{% endblock page_header %}
{% block page_description %}{% endblock page_description %}
{% block breadcrumb %}
{% include "voucher_types/breadcrumb.html" %}
{% endblock breadcrumb %}
{% block maincontent %}
<div>
<a class="btn btn-app" href="{% url 'web.views.voucher_type_add' %}">
<i class="fa fa-plus"></i> Add new voucher type
</a>
</div>
<div class="box-body">
<table id="table" class="table table-bordered table-striped">
<thead>
<tr>
<th>Id</th>
<th>Code</th>
<th>Description</th>
<th>Edit</th>
</tr>
</thead>
<tbody>
{% for voucher_type in voucher_types %}
<tr>
<td>{{ voucher_type.id }}</td>
<td>{{ voucher_type.code }}</td>
<td>{{ voucher_type.description }}</td>
<td><a href="{% url 'web.views.voucher_type_edit' voucher_type.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 %}
......@@ -5,7 +5,8 @@ import os
from django.contrib.auth.models import User
from web.models import Location, AppointmentType, StudySubject, Worker, Visit, Appointment, ConfigurationItem, \
Language, ContactAttempt, FlyingTeam, Availability, Subject, Study, StudyColumns, StudyNotificationParameters
Language, ContactAttempt, FlyingTeam, Availability, Subject, Study, StudyColumns, StudyNotificationParameters, \
VoucherType, VoucherTypePrice
from web.models.constants import REDCAP_TOKEN_CONFIGURATION_TYPE, REDCAP_BASE_URL_CONFIGURATION_TYPE, \
SEX_CHOICES_MALE, SUBJECT_TYPE_CHOICES_CONTROL, CONTACT_TYPES_PHONE, \
MONDAY_AS_DAY_OF_WEEK, COUNTRY_AFGHANISTAN_ID
......@@ -26,6 +27,17 @@ def create_location(name="test"):
return Location.objects.create(name=name)
def create_voucher_type():
return VoucherType.objects.create(code="X", study=get_test_study())
def create_voucher_type_price():
return VoucherTypePrice.objects.create(voucher_type=create_voucher_type(),
price=12.34,
start_date=get_today_midnight_date(),
end_date=get_today_midnight_date())
def create_empty_study_columns():
study_columns = StudyColumns.objects.create(
postponed=False,
......@@ -233,7 +245,9 @@ def get_resource_path(filename):
def format_form_field(value):
if isinstance(value, datetime.datetime):
if isinstance(value, datetime.date):
return value.strftime('%Y-%m-%d')
elif isinstance(value, datetime.datetime):
return value.strftime('%Y-%m-%d %H:%M')
else:
return value
......
import logging
from django.urls import reverse
from web.models import VoucherType
from web.models.constants import GLOBAL_STUDY_ID
from web.tests.functions import create_voucher_type
from .. import LoggedInTestCase
logger = logging.getLogger(__name__)
class VoucherTypeViewTests(LoggedInTestCase):
def test_render_add_voucher_type_request(self):
response = self.client.get(reverse('web.views.voucher_type_add'))
self.assertEqual(response.status_code, 200)
def test_render_edit_voucher_type_request(self):
voucher_type = create_voucher_type()
response = self.client.get(reverse('web.views.voucher_type_edit', kwargs={'pk': voucher_type.id}))
self.assertEqual(response.status_code, 200)
def test_add_voucher_type(self):
form_data = {
'code': "X",
'description': "y",
'study': str(GLOBAL_STUDY_ID),
}
response = self.client.post(reverse('web.views.voucher_type_add'), data=form_data)
self.assertEqual(response.status_code, 302)
self.assertEqual(1, VoucherType.objects.all().count())
import logging
from django.urls import reverse
from web.forms.forms import VoucherTypePriceForm
from web.models import VoucherType, VoucherTypePrice
from web.tests.functions import create_voucher_type, create_voucher_type_price, format_form_field
from .. import LoggedInTestCase
logger = logging.getLogger(__name__)
class VoucherTypePriceViewTests(LoggedInTestCase):
def setUp(self):
super(VoucherTypePriceViewTests, self).setUp()
self.voucher_type = create_voucher_type()
def test_render_add_voucher_type_price_request(self):
url = reverse('web.views.voucher_type_price_add', kwargs={'voucher_type_id': self.voucher_type.id})
response = self.client.get(url
)
self.assertEqual(response.status_code, 200)
def test_render_edit_voucher_type_price_request(self):
voucher_type_price = create_voucher_type_price()
url = reverse('web.views.voucher_type_price_edit',
kwargs={'pk': voucher_type_price.id, 'voucher_type_id': self.voucher_type.id})
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_add_voucher_type_price(self):
form_data = {
'price': "11.0",
'start_date': "2017-01-01",
'end_date': "2018-01-01"
}
url = reverse('web.views.voucher_type_price_add', kwargs={'voucher_type_id': self.voucher_type.id})
response = self.client.post(url, data=form_data)
self.assertEqual(response.status_code, 302)
self.assertEqual(1, VoucherType.objects.all().count())
def test_edit_voucher_type_price(self):
voucher_type_price = create_voucher_type_price()
form = VoucherTypePriceForm(instance=voucher_type_price)
form_data = {}
for key, value in form.initial.items():
if value is not None:
form_data['{}'.format(key)] = format_form_field(value)
form_data['price'] = 90.50
url = reverse('web.views.voucher_type_price_edit',
kwargs={'pk': voucher_type_price.id, 'voucher_type_id': voucher_type_price.voucher_type.id})
response = self.client.post(url, data=form_data)
self.assertEqual(90.50, VoucherTypePrice.objects.get(id=voucher_type_price.id).price)
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