Merge pull request #59: Implemented policy parsing
Implemented policy parsing!
This commit is contained in:
		
						commit
						21440bf3dc
					
				
					 6 changed files with 87 additions and 98 deletions
				
			
		
							
								
								
									
										18
									
								
								back/backend/migrations/0005_field_field_name.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								back/backend/migrations/0005_field_field_name.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | ||||||
|  | # Generated by Django 2.1.5 on 2019-02-07 22:02 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations, models | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('backend', '0004_auto_20190131_1645'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AddField( | ||||||
|  |             model_name='field', | ||||||
|  |             name='field_name', | ||||||
|  |             field=models.CharField(default='field', max_length=512), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
|  | @ -26,12 +26,13 @@ class Section(models.Model): | ||||||
| 
 | 
 | ||||||
| class Field(models.Model): | 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") | ||||||
|     label = models.CharField(max_length=512) |     label = models.CharField(max_length=512) | ||||||
|     number = models.IntegerField() |     number = models.IntegerField() | ||||||
|     type = models.CharField(max_length=128) |     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, null=True, blank=True) | ||||||
|     data_date = models.DateField(default=datetime.date.today) |     data_date = models.DateField(default=datetime.date.today) | ||||||
|     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) | ||||||
|  |  | ||||||
|  | @ -1,10 +1,36 @@ | ||||||
| # simple_policy.py |  | ||||||
| from datetime import date | from datetime import date | ||||||
| from policy import Policy, Section |  | ||||||
| 
 | 
 | ||||||
| # - For the rules, should one refer to fields by 'section.fields.x' | #### Classes for policy, sections. | ||||||
| # or by the section name eg. 'general_section.fields.x'? |  | ||||||
| 
 | 
 | ||||||
|  | class Policy(): | ||||||
|  | 
 | ||||||
|  |     def __init__(self): | ||||||
|  |         self.sections = [] | ||||||
|  | 
 | ||||||
|  |     def add_section(self, section): | ||||||
|  |         self.sections.append(section) | ||||||
|  | 
 | ||||||
|  | class Section(): | ||||||
|  |      | ||||||
|  |     def __init__(self, title="Section", html_description="", required=False, auto_submit=False, fields={}): | ||||||
|  |         self.title = title | ||||||
|  |         self.html_description = html_description | ||||||
|  |         self.required = required | ||||||
|  |         self.auto_submit = auto_submit | ||||||
|  |         self.fields = fields | ||||||
|  |         self.rules = [] | ||||||
|  | 
 | ||||||
|  |     def add_rule(self, title="Rule", rule=None, rule_break_text=""): | ||||||
|  |         rule = { | ||||||
|  |             "title": title, | ||||||
|  |             "rule": rule, | ||||||
|  |             "rule_break_text": rule_break_text, | ||||||
|  |         } | ||||||
|  |         self.rules.append(rule) | ||||||
|  | 
 | ||||||
|  | #### Policy configuration begin here | ||||||
|  | 
 | ||||||
|  | pol = Policy() | ||||||
| 
 | 
 | ||||||
| #### General | #### General | ||||||
| #### Section 0 | #### Section 0 | ||||||
|  | @ -12,7 +38,7 @@ general_section = Section( | ||||||
|     title="General Info", |     title="General Info", | ||||||
|     html_description="", |     html_description="", | ||||||
|     fields={ |     fields={ | ||||||
|         "destination": {"label": "Destination City", "type": "string"} |         "destination": {"label": "Destination City", "type": "string"}, | ||||||
|     } |     } | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -22,7 +48,7 @@ general_section.add_rule( | ||||||
|     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?" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| Policy.add_section(general_section) | pol.add_section(general_section) | ||||||
| 
 | 
 | ||||||
| #### Flight | #### Flight | ||||||
| #### Section 1 | #### Section 1 | ||||||
|  | @ -43,7 +69,7 @@ flight_section.add_rule( | ||||||
|     rule_break_text="Fares cannot be more than $500" |     rule_break_text="Fares cannot be more than $500" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| Policy.add_section(flight_section) | pol.add_section(flight_section) | ||||||
| 
 | 
 | ||||||
| #### Lodging | #### Lodging | ||||||
| #### Section 2 | #### Section 2 | ||||||
|  | @ -64,13 +90,13 @@ def nightly_rate_check(report, section): | ||||||
|     duration = checkout_date - checkin_date |     duration = checkout_date - checkin_date | ||||||
|     return section.fields.cost <= duration * section.fields.rate |     return section.fields.cost <= duration * section.fields.rate | ||||||
| 
 | 
 | ||||||
| section.add_rule( | lodging_section.add_rule( | ||||||
|     title="", |     title="", | ||||||
|     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." | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| Policy.add_section(lodging_section) | pol.add_section(lodging_section) | ||||||
| 
 | 
 | ||||||
| #### Local Transportation | #### Local Transportation | ||||||
| #### Section 3 | #### Section 3 | ||||||
|  | @ -89,7 +115,7 @@ transport_section.add_rule( | ||||||
|     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." | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| Policy.add_section(transport_section) | pol.add_section(transport_section) | ||||||
| 
 | 
 | ||||||
| #### Per Diem | #### Per Diem | ||||||
| #### Section 4 | #### Section 4 | ||||||
|  | @ -109,24 +135,4 @@ per_diem_section.add_rule( | ||||||
|     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." | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| Policy.add_section(per_diem_section) | pol.add_section(per_diem_section) | ||||||
| 
 |  | ||||||
| ''' |  | ||||||
| Section( |  | ||||||
|     title="", |  | ||||||
|     html_description="<p></p>", |  | ||||||
|     fields={ |  | ||||||
|         "": {"label": "", "type": ""} |  | ||||||
|     } |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| section.add_rule( |  | ||||||
|     title="", |  | ||||||
|     rule=lambda report, section: boolean_statement, |  | ||||||
|     rule_break_text="" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| #// or, for a rule which doesn’t apply to a specific section... |  | ||||||
| #// |  | ||||||
| #// add_general_rule(...) |  | ||||||
| ''' |  | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								back/backend/test.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								back/backend/test.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | ||||||
|  | from policy import pol | ||||||
|  | 
 | ||||||
|  | print(pol) | ||||||
|  | @ -1,7 +1,8 @@ | ||||||
| from rest_framework.decorators import api_view | from rest_framework.decorators import api_view | ||||||
| from django.http import JsonResponse | from django.http import JsonResponse | ||||||
| from .models import * | from .models import * | ||||||
| 
 | from .policy import pol | ||||||
|  | import json | ||||||
| 
 | 
 | ||||||
| # function that prints all the reports | # function that prints all the reports | ||||||
| def get_reports(report_pk): | def get_reports(report_pk): | ||||||
|  | @ -47,15 +48,14 @@ def get_sections(r_id): | ||||||
| def get_fields(s_id): | def get_fields(s_id): | ||||||
|     # create dict of arrays for fields |     # create dict of arrays for fields | ||||||
|     field_set = {"fields": []} |     field_set = {"fields": []} | ||||||
|     queryset = Field.objects.filter(section_id=s_id) |     queryset = Field.objects.filter(section_id=s_id).order_by('number') | ||||||
|     # queryset = Field.objects.all() |  | ||||||
|     for i in queryset: |     for i in queryset: | ||||||
|         data = { |         data = { | ||||||
|             "field_name": "TODO", |             "field_name": i.field_name, | ||||||
|             "label": i.label, |             "label": i.label, | ||||||
|             "type": i.type, |             "type": i.type, | ||||||
|             "number": i.number, |             "number": i.number, | ||||||
|             "value": "get_value", |             "value": "i.to_json()", | ||||||
|         } |         } | ||||||
|         # append the fields to array |         # append the fields to array | ||||||
|         # use copy() to avoid overwriting |         # use copy() to avoid overwriting | ||||||
|  | @ -70,73 +70,34 @@ def report(request): | ||||||
|     ''' |     ''' | ||||||
|     Generate a new empty report and return it |     Generate a new empty report and return it | ||||||
|     ''' |     ''' | ||||||
|     data = { |      | ||||||
|         "title": "2018 Portland trip", |     # Create the report | ||||||
|         "date_created": "2018-05-22T14:56:28.000Z", |     report = Report.objects.create(user_id=request.user, title=request.data['title'], date_created=datetime.date.today()) | ||||||
|         "submitted": False, |     report.save() | ||||||
|         "date_submitted": "0000-00-00T00:00:00.000Z", | 
 | ||||||
|         "sections": [ |     # Create the sections | ||||||
|             { |     for i in range(len(pol.sections)): | ||||||
|                 "id": 1, |         section = pol.sections[i] | ||||||
|                 "completed": True, |         s = Section.objects.create(report_id=report, auto_submit=section.auto_submit, required=section.required, completed=False, title=section.title, html_description=section.html_description, number=i) | ||||||
|                 "title": "Flight Info", |         s.save() | ||||||
|                 "html_description": "<p>Enter flight details here.</p>", | 
 | ||||||
|                 "fields": { |         # Create the fields | ||||||
|                     "international": { |         j = 0 | ||||||
|                         "label": "International flight", |         for key in section.fields: | ||||||
|                         "type": "boolean", |             field = section.fields[key] | ||||||
|                         "value": True |             f = Field.objects.create(section_id=s, field_name=key, label=field['label'], number=j, type=field['type'], completed=False) | ||||||
|                     }, |             f.save() | ||||||
|                     "travel_date": { |             j = j+1 | ||||||
|                         "label": "Travel start date", |      | ||||||
|                         "type": "date", |     # Return the newly created report | ||||||
|                         "value": "2016-05-22T14:56:28.000Z" |     data = get_reports(report.id) | ||||||
|                     }, |  | ||||||
|                     "fare": { |  | ||||||
|                         "label": "Fare", |  | ||||||
|                         "type": "decimal", |  | ||||||
|                         "value": "1024.99" |  | ||||||
|                     }, |  | ||||||
|                     "lowest_fare_screenshot": { |  | ||||||
|                         "label": "Lowest fare screenshot", |  | ||||||
|                         "type": "file", |  | ||||||
|                         "value": "e92h842jiu49f8..." |  | ||||||
|                     }, |  | ||||||
|                     "plane_ticket_invoice": { |  | ||||||
|                         "label": "Plane ticket invoice PDF", |  | ||||||
|                         "type": "file", |  | ||||||
|                         "value": "" |  | ||||||
|                     } |  | ||||||
|                 }, |  | ||||||
|                 "rule_violations": [ |  | ||||||
|                     { |  | ||||||
|                         "error_text": "Plane ticket invoice must be submitted." |  | ||||||
|                     } |  | ||||||
|                 ] |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 "id": 2, |  | ||||||
|                 "completed": False, |  | ||||||
|                 "title": "Hotel info", |  | ||||||
|                 "html_description": "<p>If you used a hotel, please enter the details.</p>", |  | ||||||
|                 "fields": { |  | ||||||
|                     "total": { |  | ||||||
|                         "label": "Total cost", |  | ||||||
|                         "type": "decimal" |  | ||||||
|                     } |  | ||||||
|                 }, |  | ||||||
|                 "rule_violations": [ |  | ||||||
|                 ] |  | ||||||
|             } |  | ||||||
|         ] |  | ||||||
|     } |  | ||||||
|     return JsonResponse(data) |     return JsonResponse(data) | ||||||
| 
 | 
 | ||||||
| # List of reports | # List of reports | ||||||
| @api_view(['GET']) | @api_view(['GET']) | ||||||
| def reports(request): | def reports(request): | ||||||
|     report_set = {"reports": []} |     report_set = {"reports": []} | ||||||
|     queryset = Report.objects.all() |     queryset = Report.objects.all().order_by('date_created') | ||||||
|     for i in queryset: |     for i in queryset: | ||||||
|         data = { |         data = { | ||||||
|             "report_pk": i.id, |             "report_pk": i.id, | ||||||
|  |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								back/db.sqlite3
									
										
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								back/db.sqlite3
									
										
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Daniel Dupriest
						Daniel Dupriest