From ad82e73c276b3c5bc894c99000dfd78b49766f00 Mon Sep 17 00:00:00 2001
From: Gabriella Azzopardi
Date: Wed, 10 Feb 2021 10:17:48 +0000
Subject: [PATCH] Revert "Automate infected breaks DIV creation in JS"
This reverts commit c8fb1b68f65e41575ba698814e6d835cc3bf389f
---
cara/apps/calculator/README.md | 26 ++-
cara/apps/calculator/model_generator.py | 162 +++++++++++------
cara/apps/calculator/static/css/report.css | 1 -
cara/apps/calculator/static/js/form.js | 112 +++++++-----
.../templates/calculator.form.html.j2 | 159 ++++++++++------
cara/apps/calculator/templates/report.html.j2 | 46 ++++-
.../apps/calculator/test_model_generator.py | 172 +++++++++++-------
7 files changed, 436 insertions(+), 242 deletions(-)
diff --git a/cara/apps/calculator/README.md b/cara/apps/calculator/README.md
index 9de5cdc4..9ae16f3e 100644
--- a/cara/apps/calculator/README.md
+++ b/cara/apps/calculator/README.md
@@ -121,7 +121,7 @@ In this case it is assumed that the infected person is the trainer, because this
You should enter the time (hours:minutes) for the start and end of the simulation period (i.e. 8:30 to 17:30 for a typical office day).
It is important to enter the correct times for the simulation, in particular when using natural ventilation.
-It is possible to specify a different time for the entry and exit of the infected person, however for most cases (where we do not know apriori which of the occupants is infected), it is recommended to set these to the same values as the activity start and end.
+It is possible to specify a different time for the entry and exit of both the exposed and infected person, however for most cases (where we do not know apriori which of the occupants is infected), it is recommended to set these to the same values as the activity start and end.
#### When is the event?
@@ -131,17 +131,17 @@ Only the month is used by the model to retrieve the average outdoor air temperat
### Breaks
-#### Lunch
+#### Lunch Break
You have the option to specify a lunch break.
This will be useful if you plan to simulate a typical full working day.
-During the lunch break it is assumed that all occupants will leave the simulated space (to go an eat lunch, somewhere else - restaurant or break room).
+During the lunch break it is assumed that all occupants will leave the simulated space (to go eat lunch somewhere else - restaurant or break room).
If you plan to eat lunch in the same area where you have been working, you should select 'No' even if a lunch break will be taken, since the risk of infection is related to the occupation of the simulated space.
+See 'Split Breaks' if the occupants do not break at the same time.
It should also be noted that the infection probabilities presented in the report does not take into account any potential exposures during the break times.
-
-### Coffee Breaks
+#### Coffee Breaks
You have the option to choose 0(No breaks), 2 or 4 coffee breaks during the simulated period.
It is assumed that all occupants vacate the space during the break period.
@@ -151,10 +151,22 @@ When enabled, the breaks are spread equally throughout the day - for example if
The exact timing of the breaks within the day is not particularly critical to an accurate simulation, so you do not need to be concerned about major differences if you take a coffee break at 10:00 instead of 11:00.
The variation of coffee breaks can be altered in 5 minute increments up to 30 minutes in length.
Note that this doesn't necessarily have to be a coffee break, it can represent any period where the simulated space is vacated.
-
+See 'Split Breaks' if the occupants do not break at the same time.
+
It should also be noted that the infection probabilities presented in the report does not take into account any potential exposures during the break times.
-#### Face Masks
+#### Split breaks
+
+You have the option to specify whether the exposed and infected person(s) break at the same time.
+If not, then you can input separate breaks. This is particularly different when specifying coffee breaks as they are spread evenly throughout the activity times specified.
+
+If we take an example where the exposed person(s) activity time is from 9:00 to 18:00 and the infected person(s) is from 10:00 to 17:00, with both having a lunch break from 13:00 to 14:00 and have 2 coffee breaks each, we can have two different results:
+
+1. Specify the default situtaion where both exposed and infected persons(s) have their breaks at the same time: in this case the coffee break times are calculated based on the activity time of the exposed - both will have their first coffee break around 11:00 and the second around 16:00.
+
+2. Specify separate breaks for the infected person(s): in this case the coffee breaks will be calculated based on the different activity times (i.e. exposed from 9:00 to 18:00 and infected from 10:00 to 17:00) - the exposed person(s) will have their first coffee break around 11:00 and the second around 16:00, whereas the infected will have their first coffee break around 11:30 and the second around 15:30.
+
+### Face Masks
The model allows for a simulation with either a continuous wearing of face masks throughout the duration of the event, or have the removed at all times - i.e. all occupants (infected and exposed alike) wear or not masks for the duration of the simulation.
Please bear in mind the user inputs shall be aligned with the current applicable public health & safety instructions.
diff --git a/cara/apps/calculator/model_generator.py b/cara/apps/calculator/model_generator.py
index 998f0a13..9a3d60f4 100644
--- a/cara/apps/calculator/model_generator.py
+++ b/cara/apps/calculator/model_generator.py
@@ -15,24 +15,30 @@ LOG = logging.getLogger(__name__)
@dataclass
class FormData:
# Number of minutes after 00:00
- activity_start: int
- activity_finish: int
- lunch_start: int
- lunch_finish: int
- infected_start: int
+ exposed_finish: int
+ exposed_lunch_finish: int
+ exposed_lunch_start: int
+ exposed_start: int
infected_finish: int
+ infected_lunch_finish: int #Used if infected_dont_have_breaks_with_exposed
+ infected_lunch_start: int #Used if infected_dont_have_breaks_with_exposed
+ infected_start: int
activity_type: str
air_changes: float
air_supply: float
ceiling_height: float
- coffee_breaks: int
- coffee_duration: int
+ exposed_coffee_breaks: int
+ exposed_coffee_duration: int
+ exposed_lunch_option: bool
floor_area: float
hepa_amount: float
hepa_option: bool
+ infected_coffee_breaks: int #Used if infected_dont_have_breaks_with_exposed
+ infected_coffee_duration: int #Used if infected_dont_have_breaks_with_exposed
+ infected_dont_have_breaks_with_exposed: bool
+ infected_lunch_option: bool #Used if infected_dont_have_breaks_with_exposed
infected_people: int
- lunch_option: bool
mask_type: str
mask_wearing: str
mechanical_ventilation_type: str
@@ -58,12 +64,12 @@ class FormData:
# Take a copy of the form data so that we can mutate it.
form_data = form_data.copy()
- valid_na_values = ['windows_open', 'window_type', 'mechanical_ventilation_type']
+ valid_na_values = ['windows_open', 'window_type', 'mechanical_ventilation_type', 'infected_dont_have_breaks_with_exposed']
for name in valid_na_values:
if not form_data.get(name, ''):
form_data[name] = 'not-applicable'
- for name in ['lunch_start', 'lunch_finish']:
+ for name in ['exposed_lunch_start', 'exposed_lunch_finish', 'infected_lunch_start', 'infected_lunch_finish']:
if not form_data.get(name, ''):
form_data[name] = '00:00'
@@ -78,34 +84,42 @@ class FormData:
form_data[key] = "0"
time_attributes = [
- 'activity_start', 'activity_finish', 'lunch_start',
- 'lunch_finish', 'infected_start', 'infected_finish',
+ 'exposed_lunch_start', 'exposed_lunch_finish', 'exposed_start', 'exposed_finish',
+ 'infected_lunch_start', 'infected_lunch_finish', 'infected_start', 'infected_finish',
]
for attr_name in time_attributes:
form_data[attr_name] = time_string_to_minutes(form_data[attr_name])
boolean_attributes = [
- 'hepa_option', 'lunch_option',
+ 'hepa_option', 'exposed_lunch_option', 'infected_lunch_option', 'infected_dont_have_breaks_with_exposed',
]
for attr_name in boolean_attributes:
form_data[attr_name] = form_data[attr_name] == '1'
instance = cls(
- activity_finish=form_data['activity_finish'],
- activity_start=form_data['activity_start'],
activity_type=form_data['activity_type'],
air_changes=float(form_data['air_changes']),
air_supply=float(form_data['air_supply']),
ceiling_height=float(form_data['ceiling_height']),
- coffee_breaks=int(form_data['coffee_breaks']),
- coffee_duration=int(form_data['coffee_duration']),
+ exposed_coffee_breaks=int(form_data['exposed_coffee_breaks']),
+ exposed_coffee_duration=int(form_data['exposed_coffee_duration']),
+ exposed_finish=form_data['exposed_finish'],
+ exposed_lunch_finish=form_data['exposed_lunch_finish'],
+ exposed_lunch_option=form_data['exposed_lunch_option'],
+ exposed_lunch_start=form_data['exposed_lunch_start'],
+ exposed_start=form_data['exposed_start'],
floor_area=float(form_data['floor_area']),
hepa_amount=float(form_data['hepa_amount']),
hepa_option=form_data['hepa_option'],
+ infected_coffee_breaks=int(form_data['infected_coffee_breaks']),
+ infected_coffee_duration=int(form_data['infected_coffee_duration']),
+ infected_dont_have_breaks_with_exposed=form_data['infected_dont_have_breaks_with_exposed'],
+ infected_finish=form_data['infected_finish'],
+ infected_lunch_finish=form_data['infected_lunch_finish'],
+ infected_lunch_option=form_data['infected_lunch_option'],
+ infected_lunch_start=form_data['infected_lunch_start'],
infected_people=int(form_data['infected_people']),
- lunch_finish=form_data['lunch_finish'],
- lunch_option=form_data['lunch_option'],
- lunch_start=form_data['lunch_start'],
+ infected_start=form_data['infected_start'],
mask_type=form_data['mask_type'],
mask_wearing=form_data['mask_wearing'],
mechanical_ventilation_type=form_data['mechanical_ventilation_type'],
@@ -125,18 +139,21 @@ class FormData:
window_width=float(form_data['window_width']),
windows_number=int(form_data['windows_number']),
windows_open=form_data['windows_open'],
- infected_start=form_data['infected_start'],
- infected_finish=form_data['infected_finish'],
)
instance.validate()
return instance
def validate(self):
+ # Validate time intervals selected by user
time_intervals = [
- ['activity_start', 'activity_finish'],
- ['lunch_start', 'lunch_finish'],
+ ['exposed_start', 'exposed_finish'],
['infected_start', 'infected_finish'],
]
+ if self.exposed_lunch_option:
+ time_intervals.append(['exposed_lunch_start', 'exposed_lunch_finish'])
+ if self.infected_dont_have_breaks_with_exposed and self.infected_lunch_option:
+ time_intervals.append(['infected_lunch_start', 'infected_lunch_finish'])
+
for start_name, end_name in time_intervals:
start = getattr(self, start_name)
end = getattr(self, end_name)
@@ -295,42 +312,67 @@ class FormData:
)
return exposed
- def _compute_breaks_in_interval(self, start, finish, n_breaks) -> models.BoundarySequence_t:
- break_delay = ((finish - start) - (n_breaks * self.coffee_duration)) // (n_breaks+1)
+ def _compute_breaks_in_interval(self, start, finish, n_breaks, duration) -> models.BoundarySequence_t:
+ break_delay = ((finish - start) - (n_breaks * duration)) // (n_breaks+1)
break_times = []
end = start
for n in range(n_breaks):
begin = end + break_delay
- end = begin + self.coffee_duration
+ end = begin + duration
break_times.append((begin, end))
return tuple(break_times)
- def lunch_break_times(self) -> models.BoundarySequence_t:
+ def exposed_lunch_break_times(self) -> models.BoundarySequence_t:
result = []
- if self.lunch_option:
- result.append((self.lunch_start, self.lunch_finish))
+ if self.exposed_lunch_option:
+ result.append((self.exposed_lunch_start, self.exposed_lunch_finish))
return tuple(result)
- def coffee_break_times(self) -> models.BoundarySequence_t:
- if not self.coffee_breaks:
- return ()
- if self.lunch_option:
- time_before_lunch = self.lunch_start - self.activity_start
- time_after_lunch = self.activity_finish - self.lunch_finish
- before_lunch_frac = time_before_lunch / (time_before_lunch + time_after_lunch)
- n_morning_breaks = round(self.coffee_breaks * before_lunch_frac)
- breaks = (
- self._compute_breaks_in_interval(
- self.activity_start, self.lunch_start, n_morning_breaks
- )
- + self._compute_breaks_in_interval(
- self.lunch_finish, self.activity_finish, self.coffee_breaks - n_morning_breaks
- )
- )
+ def infected_lunch_break_times(self) -> models.BoundarySequence_t:
+ if self.infected_dont_have_breaks_with_exposed:
+ result = []
+ if self.infected_lunch_option:
+ result.append((self.infected_lunch_start, self.infected_lunch_finish))
+ return tuple(result)
else:
- breaks = self._compute_breaks_in_interval(self.activity_start, self.activity_finish, self.coffee_breaks)
+ return self.exposed_lunch_break_times()
+
+ def _coffee_break_times(self, activity_start, activity_finish, coffee_breaks, coffee_duration, lunch_start, lunch_finish) -> models.BoundarySequence_t:
+ time_before_lunch = lunch_start - activity_start
+ time_after_lunch = activity_finish - lunch_finish
+ before_lunch_frac = time_before_lunch / (time_before_lunch + time_after_lunch)
+ n_morning_breaks = round(coffee_breaks * before_lunch_frac)
+ breaks = (
+ self._compute_breaks_in_interval(
+ activity_start, lunch_start, n_morning_breaks, coffee_duration
+ )
+ + self._compute_breaks_in_interval(
+ lunch_finish, activity_finish, coffee_breaks - n_morning_breaks, coffee_duration
+ )
+ )
return breaks
+ def exposed_coffee_break_times(self) -> models.BoundarySequence_t:
+ if not self.exposed_coffee_breaks:
+ return ()
+ if self.exposed_lunch_option:
+ breaks = self._coffee_break_times(self.exposed_start, self.exposed_finish, self.exposed_coffee_breaks, self.exposed_coffee_duration, self.exposed_lunch_start, self.exposed_lunch_finish)
+ else:
+ breaks = self._compute_breaks_in_interval(self.exposed_start, self.exposed_finish, self.exposed_coffee_breaks, self.exposed_coffee_duration)
+ return breaks
+
+ def infected_coffee_break_times(self) -> models.BoundarySequence_t:
+ if self.infected_dont_have_breaks_with_exposed:
+ if not self.infected_coffee_breaks:
+ return ()
+ if self.infected_lunch_option:
+ breaks = self._coffee_break_times(self.infected_start, self.infected_finish, self.infected_coffee_breaks, self.infected_coffee_duration, self.infected_lunch_start, self.infected_lunch_finish)
+ else:
+ breaks = self._compute_breaks_in_interval(self.infected_start, self.infected_finish, self.infected_coffee_breaks, self.infected_coffee_duration)
+ return breaks
+ else:
+ return self.exposed_coffee_break_times()
+
def present_interval(
self,
start: int,
@@ -433,13 +475,13 @@ class FormData:
def infected_present_interval(self) -> models.Interval:
return self.present_interval(
self.infected_start, self.infected_finish,
- breaks=self.lunch_break_times() + self.coffee_break_times(),
+ breaks=self.infected_lunch_break_times() + self.infected_coffee_break_times(),
)
def exposed_present_interval(self) -> models.Interval:
return self.present_interval(
- self.activity_start, self.activity_finish,
- breaks=self.lunch_break_times() + self.coffee_break_times(),
+ self.exposed_start, self.exposed_finish,
+ breaks=self.exposed_lunch_break_times() + self.exposed_coffee_break_times(),
)
@@ -497,23 +539,29 @@ def model_from_form(form: FormData) -> models.ExposureModel:
def baseline_raw_form_data():
# Note: This isn't a special "baseline". It can be updated as required.
return {
- 'activity_finish': '18:00',
- 'activity_start': '09:00',
'activity_type': 'office',
'air_changes': '',
'air_supply': '',
'ceiling_height': '',
- 'coffee_breaks': '4',
- 'coffee_duration': '10',
+ 'exposed_coffee_breaks': '4',
+ 'exposed_coffee_duration': '10',
+ 'exposed_finish': '18:00',
+ 'exposed_lunch_finish': '13:30',
+ 'exposed_lunch_option': '1',
+ 'exposed_lunch_start': '12:30',
+ 'exposed_start': '09:00',
'floor_area': '',
'hepa_amount': '250',
'hepa_option': '0',
+ 'infected_coffee_breaks': '4',
+ 'infected_coffee_duration': '10',
+ 'infected_dont_have_breaks_with_exposed': '1',
'infected_finish': '18:00',
+ 'infected_lunch_finish': '13:30',
+ 'infected_lunch_option': '1',
+ 'infected_lunch_start': '12:30',
'infected_people': '1',
'infected_start': '09:00',
- 'lunch_finish': '13:30',
- 'lunch_option': '1',
- 'lunch_start': '12:30',
'mask_type': 'Type I',
'mask_wearing': 'removed',
'mechanical_ventilation_type': '',
diff --git a/cara/apps/calculator/static/css/report.css b/cara/apps/calculator/static/css/report.css
index 694f5639..f7101ffd 100644
--- a/cara/apps/calculator/static/css/report.css
+++ b/cara/apps/calculator/static/css/report.css
@@ -26,7 +26,6 @@ p.data_title {
p.data_text {
padding-left: 30px;
- padding-left: 1em;
}
p.data_subtext {
diff --git a/cara/apps/calculator/static/js/form.js b/cara/apps/calculator/static/js/form.js
index 3f9c7557..de6814ce 100644
--- a/cara/apps/calculator/static/js/form.js
+++ b/cara/apps/calculator/static/js/form.js
@@ -67,11 +67,13 @@ function require_fields(obj) {
case "mask_off":
require_mask(false);
break;
- case "lunch_option_no":
- require_lunch(false);
+ case "exposed_lunch_option_no":
+ case "infected_lunch_option_no":
+ require_lunch($(obj).attr('id'), false);
break;
- case "lunch_option_yes":
- require_lunch(true);
+ case "exposed_lunch_option_yes":
+ case "infected_lunch_option_yes":
+ require_lunch($(obj).attr('id'), true);
break;
default:
break;
@@ -144,26 +146,28 @@ function require_venting(option) {
set_disabled_status("#windows_frequency", !option);
}
-function require_lunch(option) {
- $("#lunch_start").prop('required', option);
- $("#lunch_finish").prop('required', option);
+function require_lunch(id, option) {
+ var activity = $(document.getElementById(id)).data('lunch-select');
+ var startObj = $(".start_time[data-lunch-for='"+activity+"']")[0];
+ var startID = '#'+$(startObj).attr('id');
+ var finishObj = $(".finish_time[data-lunch-for='"+activity+"']")[0];
+ var finishID = '#'+$(finishObj).attr('id');
- var lunchStartObj = document.getElementById("lunch_start");
- var lunchFinishObj = document.getElementById("lunch_finish");
- if (option) {
- if (lunchStartObj.value === "") {
- lunchStartObj.value = "12:30";
- }
- if (lunchFinishObj.value === "") {
- lunchFinishObj.value = "13:30";
- }
+ require_input_field(startID, option);
+ require_input_field(finishID, option);
+ set_disabled_status(startID, !option);
+ set_disabled_status(finishID, !option);
+
+ if (!option) {
+ $(finishID).removeClass("red_border finish_time_error lunch_break_error");
+ removeErrorFor(finishObj);
}
else {
- lunchStartObj.value = "";
- lunchFinishObj.value = "";
- $("#lunch_finish").removeClass("red_border finish_time_error lunch_break_error");
- $("#lunch_finish").removeClass("red_border finish_time_error lunch_break_error");
- removeErrorFor(lunchFinishObj);
+ if (startObj.value === "" && finishObj.value === "") {
+ startObj.value = "12:30";
+ finishObj.value = "13:30";
+ }
+ validateLunchBreak($(startObj).data('time-group'));
}
}
@@ -253,6 +257,12 @@ $("[data-has-radio]").on('change', function(event){
$($(this).data("has-radio")).click();
});
+function toggle_split_breaks() {
+ $("#DIVinfected_breaks").toggle(this.checked);
+ $("#exposed_break_title").toggle(this.checked);
+ require_lunch("infected_lunch_option_yes", document.getElementById("infected_dont_have_breaks_with_exposed").checked);
+}
+
/* -------Form validation------- */
function validate_form(form) {
var submit = true;
@@ -276,31 +286,34 @@ function validate_form(form) {
});
}
- //Validate breaks length < activity length
- if (submit) {
- var activityBreaksObj= document.getElementById("activity_breaks");
- removeErrorFor(activityBreaksObj);
+ //Check if breaks length >= activity length
+ $("[data-lunch-for]").each(function() {
+ if (submit) {
+ var activity = $(this).data('lunch-for')
+ var activityBreaksObj= document.getElementById("activity_breaks");
+ removeErrorFor(activityBreaksObj);
- var lunch_mins = 0;
- if (document.getElementById('lunch_option_yes').checked) {
- var lunch_start = document.getElementById("lunch_start");
- var lunch_finish = document.getElementById("lunch_finish");
- lunch_mins = parseTimeToMins(lunch_finish.value) - parseTimeToMins(lunch_start.value);
- }
+ if (document.getElementById(activity+"_lunch_option_yes").checked) {
+ var lunch_mins = 0;
+ var lunch_start = document.getElementById(activity+"_lunch_start");
+ var lunch_finish = document.getElementById(activity+"_lunch_finish");
+ lunch_mins = parseTimeToMins(lunch_finish.value) - parseTimeToMins(lunch_start.value);
+ }
- var coffee_breaks = parseInt(document.querySelector('input[name="coffee_breaks"]:checked').value);
- var coffee_duration = parseInt(document.getElementById("break_duration").value);
- var coffee_mins = coffee_breaks * coffee_duration;
-
- var activity_start = document.getElementById("activity_start");
- var activity_finish = document.getElementById("activity_finish");
- var activity_mins = parseTimeToMins(activity_finish.value) - parseTimeToMins(activity_start.value);
+ var coffee_breaks = parseInt(document.querySelector('input[name="'+activity+'_coffee_breaks"]:checked').value);
+ var coffee_duration = parseInt(document.getElementById(activity+"_coffee_duration").value);
+ var coffee_mins = coffee_breaks * coffee_duration;
+
+ var activity_start = document.getElementById(activity+"_start");
+ var activity_finish = document.getElementById(activity+"_finish");
+ var activity_mins = parseTimeToMins(activity_finish.value) - parseTimeToMins(activity_start.value);
- if ((lunch_mins + coffee_mins) >= activity_mins) {
- insertErrorFor(activityBreaksObj, "Length of breaks >= Length of activity");
- submit = false;
+ if ((lunch_mins + coffee_mins) >= activity_mins) {
+ insertErrorFor(activityBreaksObj, "Length of breaks >= Length of "+activity+" presence");
+ submit = false;
+ }
}
- }
+ });
//Validate all non zero values
$("input[required].non_zero").each(function() {
@@ -369,7 +382,6 @@ function isValidDateOrEmpty(date) {
}
function validateFinishTime(obj) {
-
var groupID = $(obj).data('time-group');
var startObj = $(".start_time[data-time-group='"+groupID+"']")[0];
var finishObj = $(".finish_time[data-time-group='"+groupID+"']")[0];
@@ -392,6 +404,10 @@ function validateFinishTime(obj) {
}
function validateLunchBreak(lunchGroup) {
+ //Valid if lunch break not selected
+ if(document.getElementById(lunchGroup+"_option_no").checked)
+ return true;
+
var lunchStartObj = $(".start_time[data-time-group='"+lunchGroup+"']")[0];
var lunchFinishObj = $(".finish_time[data-time-group='"+lunchGroup+"']")[0];
@@ -402,7 +418,7 @@ function validateLunchBreak(lunchGroup) {
removeErrorFor(lunchFinishObj);
var valid = validateLunchTime(lunchStartObj) & validateLunchTime(lunchFinishObj);
if (!valid) {
- insertErrorFor(lunchFinishObj, "Lunch break must be within activity times");
+ insertErrorFor(lunchFinishObj, "Lunch break must be within presence times");
}
return valid;
@@ -410,7 +426,6 @@ function validateLunchBreak(lunchGroup) {
//Check if exposed/infected lunch time within exposed/infected presence times
function validateLunchTime(obj) {
-
var activityGroup = $(obj).data('lunch-for');
var activityStart = parseValToNumber($(".start_time[data-time-group='"+activityGroup+"']")[0].value);
var activityFinish = parseValToNumber($(".finish_time[data-time-group='"+activityGroup+"']")[0].value);
@@ -446,6 +461,13 @@ $(document).ready(function () {
// Call the function now to handle forward/back button presses in the browser.
on_ventilation_type_change();
+ // Chrome fix - on back button infected break DIV not shown
+ if (document.getElementById("infected_dont_have_breaks_with_exposed").checked) {
+ $("#DIVinfected_breaks").show();
+ $("#exposed_break_title").show();
+ require_lunch("infected_lunch_option_yes", true);
+ }
+
//Check all radio buttons previously selected
$("input[type=radio]:checked").each(function() {require_fields(this)});
diff --git a/cara/apps/calculator/templates/calculator.form.html.j2 b/cara/apps/calculator/templates/calculator.form.html.j2
index 7ea8b75c..b7e0db91 100644
--- a/cara/apps/calculator/templates/calculator.form.html.j2
+++ b/cara/apps/calculator/templates/calculator.form.html.j2
@@ -1,6 +1,6 @@
{% extends "layout.html.j2" %}
-{% set MODEL_VERSION="v1.2.1" %}
+{% set MODEL_VERSION="v1.3.0" %}
{% set DEBUG=False %}
{% set active_page="calculator/" %}
@@ -134,73 +134,122 @@
Training activities limited to 1 infected
- Activity type:
- Start:
- Finish:
+ Activity type:
+
+ Exposed person(s) presence:
+ Start:
+ Finish:
Infected person(s) presence:
- Start:
- Finish:
+ Start:
+ Finish:
-
-