Merge pull request #78 from danieldupriest/implement-rules
Implement rules for GET report
This commit is contained in:
commit
a4bf17ee71
5 changed files with 78 additions and 16 deletions
38
back/backend/migrations/0008_auto_20190214_1421.py
Normal file
38
back/backend/migrations/0008_auto_20190214_1421.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# Generated by Django 2.1.5 on 2019-02-14 22:21
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('backend', '0007_merge_20190213_2318'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='field',
|
||||||
|
name='data_decimal',
|
||||||
|
field=models.DecimalField(decimal_places=2, default=0, max_digits=9),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='field',
|
||||||
|
name='number',
|
||||||
|
field=models.IntegerField(default=0),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='section',
|
||||||
|
name='auto_submit',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='section',
|
||||||
|
name='completed',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='section',
|
||||||
|
name='required',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
|
@ -15,9 +15,9 @@ class Report(models.Model):
|
||||||
|
|
||||||
class Section(models.Model):
|
class Section(models.Model):
|
||||||
report_id = models.ForeignKey(Report, on_delete=models.CASCADE)
|
report_id = models.ForeignKey(Report, on_delete=models.CASCADE)
|
||||||
auto_submit = models.BooleanField()
|
auto_submit = models.BooleanField(default=False)
|
||||||
required = models.BooleanField()
|
required = models.BooleanField(default=False)
|
||||||
completed = models.BooleanField()
|
completed = models.BooleanField(default=False)
|
||||||
title = models.CharField(max_length=256)
|
title = models.CharField(max_length=256)
|
||||||
html_description = models.TextField()
|
html_description = models.TextField()
|
||||||
number = models.IntegerField()
|
number = models.IntegerField()
|
||||||
|
@ -29,11 +29,11 @@ class Field(models.Model):
|
||||||
section_id = models.ForeignKey(Section, on_delete=models.CASCADE)
|
section_id = models.ForeignKey(Section, on_delete=models.CASCADE)
|
||||||
field_name = models.CharField(max_length=512, default="field")
|
field_name = models.CharField(max_length=512, default="field")
|
||||||
label = models.CharField(max_length=512)
|
label = models.CharField(max_length=512)
|
||||||
number = models.IntegerField()
|
number = models.IntegerField(default=0)
|
||||||
field_type = models.CharField(max_length=128)
|
field_type = models.CharField(max_length=128)
|
||||||
completed = models.BooleanField(default=False)
|
completed = models.BooleanField(default=False)
|
||||||
data_bool = models.BooleanField(default=False)
|
data_bool = models.BooleanField(default=False)
|
||||||
data_decimal = models.DecimalField(max_digits=9, decimal_places=2, null=True, blank=True)
|
data_decimal = models.DecimalField(max_digits=9, decimal_places=2, default=0)
|
||||||
data_date = models.DateField(null=True, blank=True)
|
data_date = models.DateField(null=True, blank=True)
|
||||||
data_file = models.FileField(upload_to='uploads/%Y/%m/%d/', max_length=512, null=True, blank=True)
|
data_file = models.FileField(upload_to='uploads/%Y/%m/%d/', max_length=512, null=True, blank=True)
|
||||||
data_string = models.TextField(default='', blank=True)
|
data_string = models.TextField(default='', blank=True)
|
||||||
|
|
|
@ -45,7 +45,7 @@ general_section = Section(
|
||||||
|
|
||||||
general_section.add_rule(
|
general_section.add_rule(
|
||||||
title="Destination city check",
|
title="Destination city check",
|
||||||
rule=lambda report, section: section.field.destination == "Timbuktu",
|
rule=lambda report, fields: fields['destination'] == "Timbuktu",
|
||||||
rule_break_text="What did the cowboy say about Tim, his wild horse?"
|
rule_break_text="What did the cowboy say about Tim, his wild horse?"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ flight_section = Section(
|
||||||
|
|
||||||
flight_section.add_rule(
|
flight_section.add_rule(
|
||||||
title="Airline fare pre-approval check",
|
title="Airline fare pre-approval check",
|
||||||
rule=lambda report, section: section.fields.fare < 500,
|
rule=lambda report, fields: fields['fare'] < 500,
|
||||||
rule_break_text="Fares cannot be more than $500"
|
rule_break_text="Fares cannot be more than $500"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -88,14 +88,14 @@ lodging_section = Section(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def nightly_rate_check(report, section):
|
def nightly_rate_check(report, fields):
|
||||||
checkin_date = date(section.fields.checkin_date)
|
checkin_date = date(fields['checkin_date'])
|
||||||
checkout_date = date(section.fields.checkout_date)
|
checkout_date = date(fields['checkout_date'])
|
||||||
duration = checkout_date - checkin_date
|
duration = checkout_date - checkin_date
|
||||||
return section.fields.cost <= duration * section.fields.rate
|
return fields['cost'] <= duration * fields['rate']
|
||||||
|
|
||||||
lodging_section.add_rule(
|
lodging_section.add_rule(
|
||||||
title="",
|
title="Average nightly rate",
|
||||||
rule=nightly_rate_check,
|
rule=nightly_rate_check,
|
||||||
rule_break_text="The average nightly rate cannot be more than the USGSA rate."
|
rule_break_text="The average nightly rate cannot be more than the USGSA rate."
|
||||||
)
|
)
|
||||||
|
@ -108,14 +108,14 @@ transport_section = Section(
|
||||||
title="Local Transportation",
|
title="Local Transportation",
|
||||||
html_description="<p>How much did you spend on local transportation, in total?</p>",
|
html_description="<p>How much did you spend on local transportation, in total?</p>",
|
||||||
fields={
|
fields={
|
||||||
"duration": {"label": "How many days was your trip?", "field_type": "decimal"},
|
"duration": {"label": "How many days was your trip?", "field_type": "integer"},
|
||||||
"cost": {"label": "Total cost", "field_type": "decimal"}
|
"cost": {"label": "Total cost", "field_type": "decimal"}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
transport_section.add_rule(
|
transport_section.add_rule(
|
||||||
title="Total cost check",
|
title="Total cost check",
|
||||||
rule=lambda report, section: section.fields.cost <= section.fields.duration * 10,
|
rule=lambda report, fields: fields['cost'] <= fields['duration'] * 10,
|
||||||
rule_break_text="Local transportation costs must be less than $10 per day, on average."
|
rule_break_text="Local transportation costs must be less than $10 per day, on average."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ per_diem_section = Section(
|
||||||
|
|
||||||
per_diem_section.add_rule(
|
per_diem_section.add_rule(
|
||||||
title="Per Diem Cost Check",
|
title="Per Diem Cost Check",
|
||||||
rule=lambda report, section: section.fields.cost <= section.fields.duration * section.fields.rate,
|
rule=lambda report, fields: fields['cost'] <= fields['duration'] * fields['rate'],
|
||||||
rule_break_text="The average cost per day for per diem expenses cannot be more than the rate specified by the USGSA."
|
rule_break_text="The average cost per day for per diem expenses cannot be more than the rate specified by the USGSA."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -28,15 +28,31 @@ def get_sections(r_id):
|
||||||
# create a dict of arrays for section
|
# create a dict of arrays for section
|
||||||
section_set = {"sections": []}
|
section_set = {"sections": []}
|
||||||
queryset = Section.objects.filter(report_id=r_id)
|
queryset = Section.objects.filter(report_id=r_id)
|
||||||
for i in queryset:
|
for index in range(len(queryset)):
|
||||||
|
i = queryset[index]
|
||||||
data = {
|
data = {
|
||||||
"id": i.id,
|
"id": i.id,
|
||||||
"completed": i.completed,
|
"completed": i.completed,
|
||||||
"title": i.title,
|
"title": i.title,
|
||||||
"html_description": i.html_description,
|
"html_description": i.html_description,
|
||||||
|
"rule_violations": [],
|
||||||
}
|
}
|
||||||
# append the fields for corresponding section
|
# append the fields for corresponding section
|
||||||
data.update(get_fields(i.id))
|
data.update(get_fields(i.id))
|
||||||
|
# process rules from the policy file if the section is completed
|
||||||
|
if i.completed:
|
||||||
|
rules = pol.sections[index].rules
|
||||||
|
for rule in rules:
|
||||||
|
try:
|
||||||
|
named_fields = generate_named_fields_for_section(data['fields'])
|
||||||
|
if not rule['rule'](data, named_fields):
|
||||||
|
info = {
|
||||||
|
"label": rule['title'],
|
||||||
|
"rule_break_text": rule['rule_break_text'],
|
||||||
|
}
|
||||||
|
data['rule_violations'].append(info)
|
||||||
|
except Exception as e:
|
||||||
|
print('Rule "{}" encountered an error. {}'.format(rule['title'], e))
|
||||||
# append section to the array
|
# append section to the array
|
||||||
section_set["sections"].append(data.copy())
|
section_set["sections"].append(data.copy())
|
||||||
|
|
||||||
|
@ -67,6 +83,14 @@ def get_fields(s_id):
|
||||||
return field_set
|
return field_set
|
||||||
|
|
||||||
|
|
||||||
|
def generate_named_fields_for_section(fields):
|
||||||
|
result = {}
|
||||||
|
for field in fields:
|
||||||
|
key = field['field_name']
|
||||||
|
value = field['value']
|
||||||
|
result[key] = value
|
||||||
|
return result
|
||||||
|
|
||||||
# API Endpoints
|
# API Endpoints
|
||||||
@api_view(['POST'])
|
@api_view(['POST'])
|
||||||
def report(request):
|
def report(request):
|
||||||
|
|
BIN
back/db.sqlite3
BIN
back/db.sqlite3
Binary file not shown.
Loading…
Reference in a new issue