Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement "station not open" #828

Draft
wants to merge 9 commits into
base: develop
Choose a base branch
from
38 changes: 38 additions & 0 deletions apollo/frontend/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,20 @@ def _get_group_coverage(query, form, group, location_type):
else:
offline_query = query.filter(false())

if group_tags:
not_opened_query = query.filter(
and_(
Submission.not_opened == True, # noqa
not_(
and_(
Submission.data.has_all(array(group_tags)),
Submission.not_opened == True
)
)
))
else:
not_opened_query = query.filter(false())

dataset = defaultdict(dict)

for loc_id, loc_name, count in _get_coverage_results(
Expand Down Expand Up @@ -178,13 +192,22 @@ def _get_group_coverage(query, form, group, location_type):
'name': loc_name
})

for loc_id, loc_name, count in _get_coverage_results(
not_opened_query, depth_info.depth):
dataset[loc_name].update({
'Closed': count,
'id': loc_id,
'name': loc_name
})

for name in sorted(dataset.keys()):
loc_data = dataset.get(name)
loc_data.setdefault('Complete', 0)
loc_data.setdefault('Conflict', 0)
loc_data.setdefault('Missing', 0)
loc_data.setdefault('Partial', 0)
loc_data.setdefault('Offline', 0)
loc_data.setdefault('Closed', 0)

coverage_list.append(loc_data)

Expand Down Expand Up @@ -257,12 +280,27 @@ def _get_global_coverage(query, form):
else:
offline_query = query.filter(false())

if group_tags:
not_opened_query = query.filter(
and_(
Submission.not_opened == True, # noqa
not_(
and_(
Submission.data.has_all(array(group_tags)),
Submission.not_opened == True
)
)
))
else:
not_opened_query = query.filter(false())

data = {
'Complete': complete_query.count(),
'Conflict': conflict_query.count(),
'Missing': missing_query.count(),
'Partial': partial_query.count(),
'Offline': offline_query.count(),
'Closed': not_opened_query.count(),
'name': group['name'],
'slug': group['slug']
}
Expand Down
18 changes: 10 additions & 8 deletions apollo/frontend/templates/frontend/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ <h5 class="text-center">{% if not location and not request.args.location %}<a cl
</div>
{%- if session['dashboard_chart_type'] == 'bar' %}
<pre style="display:none" id="csvdata">
Id,Link,Name,Complete,Offline,Partial,Missing
Id,Link,Name,Complete,Offline,Partial,Missing,Closed
{% for row in data -%}
{{ row.id }},
{%- if group %}
Expand All @@ -70,7 +70,7 @@ <h5 class="text-center">{% if not location and not request.args.location %}<a cl
{{ url_for('dashboard.response_rate', form_id=form_id, group=row.slug, locationtype=locationtype, **args) }}
{%- endif %}
{%- endif -%}
,"{{ row.name }}",{{ row.Complete }},{{ row.Offline }},{{ row.Partial }},{{ row.Missing }}
,"{{ row.name }}",{{ row.Complete }},{{ row.Offline }},{{ row.Partial }},{{ row.Missing }},{{ row.Closed }}
{% endfor -%}
</pre>
<div id="barchart"></div>
Expand Down Expand Up @@ -176,23 +176,25 @@ <h5 class="text-center">{% if not location and not request.args.location %}<a cl
.set('Missing', json.Missing + (json.Conflict || 0))
.set('Partial', json.Partial)
.set('Complete', json.Complete)
.set('No Signal', json.Offline);
var labels = ['Missing', 'Partial', 'Complete', 'No Signal'];
.set('No Signal', json.Offline)
.set('Not Opened', json.Closed);
var labels = ['Missing', 'Partial', 'Complete', 'No Signal', 'Not Opened'];
var labelsMap = new Map()
.set('Missing', "{{ _('Missing') }}")
.set('Partial', "{{ _('Partial') }}")
.set('Complete', "{{ _('Complete') }}")
.set('No Signal', "{{ _('No Signal') }}");
var colors = ["#dc3545", "#ffc107", "#007bff", "#aaaaaa"];
var label_colors = ["#ffffff", "#000000", "#ffffff", "#000000"];
.set('No Signal', "{{ _('No Signal') }}")
.set('Not Opened', "{{ _('Not Opened') }}");
var colors = ["#dc3545", "#ffc107", "#007bff", "#aaaaaa", "#374151"];
var label_colors = ["#ffffff", "#000000", "#ffffff", "#000000", "#ffffff"];
var total_label = "{{ _('Total') }}";

drawPieChart(el, dataMap, labels, labelsMap, colors, label_colors, total_label);
});
{%- else %}
let rawData = d3.select('#csvdata').text();
let csvData = d3.csvParse(rawData);
let colors = ["#007bff", "#aaaaaa", "#ffc107", "#dc3545"];
let colors = ["#007bff", "#aaaaaa", "#ffc107", "#dc3545", "#374151"];

drawNormalizedBarchart('#barchart', csvData, colors);
{%- endif %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
<div class="col-md-6 col-lg-2 mb-2">
<label for="{{ filter_form.participant_role.id }}" class="sr-only">{{ filter_form.participant_role.label.text }}</label>
{{ filter_form.participant_role(class_='form-control custom-select') }}
<div class="col-md-2 mb-2">
<label for="{{ filter_form.station_status.id }}" class="sr-only">{{ filter_form.station_status.label.text }}</label>
{{ filter_form.station_status(class_='form-control custom-select') }}
</div>
{%- if form.show_moment %}
<div class="col-md-6 col-lg-2 mb-2">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
<label for="{{ filter_form.participant_role.id }}" class="sr-only">{{ filter_form.participant_role.label.text }}</label>
{{ filter_form.participant_role(class_='form-control custom-select') }}
</div>
<div class="col-md-2 mb-2">
<label for="{{ filter_form.station_status.id }}" class="sr-only">{{ filter_form.station_status.label.text }}</label>
{{ filter_form.station_status(class_='form-control custom-select') }}
</div>
{%- if form.show_moment %}
<div class="col-6 col-lg-2 mb-2">
<div class="input-group date" id="datepicker" data-target-input="nearest">
Expand Down
19 changes: 19 additions & 0 deletions apollo/frontend/templates/frontend/submission_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,25 @@ <h5 class="alert-heading">{{ _('Data Validation Errors') }}</h5>
<td class="col-2 align-middle">&nbsp;</td>
{%- endif %}
</tr>
<tr>
<td class="align-middle"><strong>{{ _('Was station opened?') }}</strong></td>
<td class="col-2 align-middle obs-on text-center">
<label for="{{ submission_form.not_opened.id }}" class="sr-only">{{ submission_form.not_opened.label.text }}</label>
{%- if readonly %}
{{ submission_form.not_opened(**{'class_': 'tracked', 'data-toggle': 'switchbutton', 'data-width': '80', 'data-onlabel': _('Not Opened'), 'data-onstyle': 'danger', 'data-offlabel': _('Opened'), 'data-offstyle': 'primary', 'data-size': 'sm', 'disabled': 'disabled'}) }}
{%- else %}
{{ submission_form.not_opened(**{'class_': 'tracked', 'data-toggle': 'switchbutton', 'data-width': '80', 'data-onlabel': _('Not Opened'), 'data-onstyle': 'danger', 'data-offlabel': _('Opened'), 'data-offstyle': 'primary', 'data-size': 'sm'}) }}
{%- endif %}
</td>
{%- if form.form_type == 'CHECKLIST' and not form.untrack_data_conflicts -%}
{%- for sibling_form in sibling_forms %}
<td class="col-2 align-middle">
&nbsp;
</td>
{% endfor %}
<td class="col-2 align-middle">&nbsp;</td>
{%- endif %}
</tr>
{% if perms.edit_submission_quarantine_status.can() %}
<tr>
<td class="align-middle"><strong>{{ _('Quarantine Status') }}</strong></td>
Expand Down
1 change: 1 addition & 0 deletions apollo/submissions/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ def submission():
submission.update_related(data)
if submission.master is not None:
submission.update_master_offline_status()
submission.update_master_opened_status()
update_submission_version(submission)

message_text = make_message_text(form, participant, data)
Expand Down
31 changes: 31 additions & 0 deletions apollo/submissions/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,22 @@ def filter(self, query, value, **kwargs):
return (None, None)


class StationStatusFilter(ChoiceFilter):
def filter(self, query, value, **kwargs):
if value and value == '1':
return (
models.Submission.not_opened == True, # noqa
None
)
elif value:
return (
models.Submission.not_opened == False, # noqa
None
)

return (None, None)


class DateFilter(CharFilter):
def filter(self, query, value, **kwargs):
if value:
Expand Down Expand Up @@ -744,6 +760,13 @@ def make_submission_list_filter(event, form, filter_on_locations=False):
('1', _('No Signal'))
)
)
attributes['station_status'] = StationStatusFilter(
choices=(
('', _('Station Status')),
('0', _('Opened')),
('1', _('Not opened'))
)
)
attributes['date'] = DateFilter()
attributes['fsn'] = FormSerialNumberFilter()
attributes['participant_role'] = make_participant_role_filter(
Expand Down Expand Up @@ -799,6 +822,14 @@ class QualityAssuranceConditionsForm(Form):
)
)

attributes['station_status'] = StationStatusFilter(
choices=(
('', _('Station Status')),
('0', _('Open')),
('1', _('Not opened'))
)
)

# participant id and location
attributes['participant_id'] = ParticipantIDFilter()
attributes['location'] = AJAXLocationFilter()
Expand Down
1 change: 1 addition & 0 deletions apollo/submissions/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ def make_submission_edit_form_class(event, form):
form_fields['validate'] = validate_location

form_fields['unreachable'] = fields.BooleanField()
form_fields['not_opened'] = fields.BooleanField()

return type(
'SubmissionEditForm',
Expand Down
23 changes: 23 additions & 0 deletions apollo/submissions/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ class Submission(BaseModel):
passive_deletes=True))
conflicts = db.Column(JSONB)
unreachable = db.Column(db.Boolean, default=False, nullable=False)
not_opened = db.Column(db.Boolean, default=False, nullable=False)
geom = db.Column(Geometry('POINT', srid=4326))
verified_fields = db.Column(JSONB, default=[])

Expand Down Expand Up @@ -335,6 +336,28 @@ def update_master_offline_status(self):
if master_offline_status != self.master.unreachable:
db.session.add(self.master)

def update_master_opened_status(self):
if self.master is None:
return

siblings = self.siblings
master_opened_status = self.master.not_opened

if siblings:
if (
all([s.not_opened for s in self.siblings]) and
self.not_opened
):
self.master.not_opened = True
else:
self.master.not_opened = False
else:
self.master.not_opened = self.not_opened

# if the offline status changed in any way
if master_opened_status != self.master.not_opened:
db.session.add(self.master)

def compute_conflict_tags(self, tags=None):
# don't compute if the 'track conflicts' flag is not set
# on the form
Expand Down
2 changes: 1 addition & 1 deletion apollo/submissions/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def make_submission_dataframe(query, form, selected_tags=None,
# the 'updated' field is required for results analysis
columns = [
Submission.data[tag].label(tag) for tag in fields] + [
Submission.updated
Submission.not_opened, Submission.updated
]

# alias just in case the query is already joined to the tables below
Expand Down
7 changes: 7 additions & 0 deletions apollo/submissions/views_submissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,7 @@ def submission_edit(submission_id):
initial_data.update(location=submission.location_id)
initial_data.update(participant=submission.participant_id)
initial_data.update(unreachable=submission.unreachable)
initial_data.update(not_opened=submission.not_opened)
if submission.quarantine_status:
initial_data.update(
quarantine_status=submission.quarantine_status.code)
Expand Down Expand Up @@ -706,6 +707,7 @@ def submission_edit(submission_id):
for sibling in sibling_submissions:
initial_data = sibling.data
initial_data.update(unreachable=sibling.unreachable)
initial_data.update(not_opened=sibling.not_opened)
if sibling.quarantine_status:
initial_data.update(
quarantine_status=sibling.quarantine_status.code)
Expand Down Expand Up @@ -1015,6 +1017,7 @@ def submission_edit(submission_id):
new_quarantine_status = submission_form.data.get(
'quarantine_status')
new_offline_status = submission_form.unreachable.data
new_station_status = submission_form.not_opened.data

if permissions.edit_submission_verification_status.can():
new_verified_fields = \
Expand Down Expand Up @@ -1050,6 +1053,9 @@ def submission_edit(submission_id):
if new_offline_status != submission.unreachable:
changed = True
update_params['unreachable'] = new_offline_status
if new_station_status != submission.not_opened:
changed = True
update_params['not_opened'] = new_station_status

changed_fields = []

Expand Down Expand Up @@ -1117,6 +1123,7 @@ def submission_edit(submission_id):
submission.update_related(data)

submission.update_master_offline_status()
submission.update_master_opened_status()

db.session.add_all(attachments)
for attachment in deleted_attachments:
Expand Down
31 changes: 31 additions & 0 deletions migrations/versions/b3ccd538959e_add_not_opened_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""add not_opened field

Revision ID: b3ccd538959e
Revises: c4166678fb79
Create Date: 2021-08-03 09:41:18.244493

"""
import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = 'b3ccd538959e'
down_revision = 'c4166678fb79'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column(
'submission',
sa.Column('not_opened', sa.Boolean(), nullable=False,
server_default='False'))
op.alter_column('submission', 'not_opened', server_default=None)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('submission', 'not_opened')
# ### end Alembic commands ###