1
# -*- coding: utf-8 -*-
4
DVI - Management of Dead Bodies and Disaster Victim Identification
11
if deployment_settings.has_module(module):
15
tablename = "%s_%s" % (module, resource)
16
table = db.define_table(tablename,
17
Field("audit_read", "boolean"),
18
Field("audit_write", "boolean"),
21
# -----------------------------------------------------------------------------
24
dvi_task_status_opts = {
29
5:T("Not Applicable"),
33
opt_dvi_task_status = db.Table(None, "opt_dvi_task_status",
34
Field("opt_dvi_task_status","integer",
35
requires = IS_IN_SET(dvi_task_status_opts, zero=None),
37
label = T("Task Status"),
38
represent = lambda opt: \
39
dvi_task_status_opts.get(opt, UNKNOWN_OPT)))
41
# -----------------------------------------------------------------------------
45
tablename = "%s_%s" % (module, resource)
46
table = db.define_table(tablename, timestamp, uuidstamp, deletion_status,
47
Field("date", "datetime"),
48
Field("site_id", length=64),
50
Field("location_details"),
53
Field("bodies_est", "integer"), # Number of bodies found
55
Field("bodies_rec", "integer"), # Number of bodies recovered
58
# Settings and Restrictions
59
table.uuid.requires = IS_NOT_IN_DB(db, "%s.uuid" % table)
61
table.date.label = T("Date/Time of Find")
62
table.date.comment = SPAN("*", _class="req")
63
table.date.requires = IS_UTC_DATETIME(utc_offset=shn_user_utc_offset(),
65
table.date.represent = lambda value: shn_as_local_time(value)
67
table.site_id.label = T("Site ID")
68
#table.site_id.requires = IS_EMPTY_OR(IS_NOT_IN_DB(db, table.site_id))
70
table.location_id.label = T("Location")
71
table.person_id.label = T("Finder")
73
table.bodies_est.label = T("Bodies found")
74
table.bodies_est.comment = SPAN("*", _class="req")
75
table.bodies_est.requires = IS_INT_IN_RANGE(1, 99999)
76
table.bodies_est.default = 0
78
table.bodies_rec.label = T("Bodies recovered")
79
table.bodies_rec.requires = IS_NULL_OR(IS_INT_IN_RANGE(0, 99999))
80
table.bodies_rec.default = 0
82
table.opt_dvi_task_status.label = T("Task status")
85
s3.crud_strings[tablename] = Storage(
86
title_create = T("Body Recovery Request"),
87
title_display = T("Request Details"),
88
title_list = T("List of Requests"),
89
title_update = T("Update Request"),
90
title_search = T("Search Request"),
91
subtitle_create = T("Add New Request"),
92
subtitle_list = T("Body Recovery Requests"),
93
label_list_button = T("List of Requests"),
94
label_create_button = T("Add Request"),
95
label_delete_button = T("Delete Request"),
96
msg_record_created = T("Recovery Request added"),
97
msg_record_modified = T("Recovery Request updated"),
98
msg_record_deleted = T("Recovery Request deleted"),
99
msg_list_empty = T("No requests currently registered"))
101
dvi_recreq_id = db.Table(None, "dvi_recreq_id",
102
Field("dvi_recreq_id", table,
103
requires = IS_NULL_OR(IS_ONE_OF(db,
105
"[%(site_id)s] %(date)s: %(bodies_est)s bodies")),
106
represent = lambda id: id,
107
ondelete = "RESTRICT"))
109
s3xrc.model.configure(table,
118
"opt_dvi_task_status"])
121
# Body ------------------------------------------------------------------------
124
tablename = "%s_%s" % (module, resource)
125
table = db.define_table(tablename, timestamp, deletion_status, uuidstamp,
128
Field("date_of_recovery", "datetime"),
130
Field("recovery_details","text"),
131
Field("has_major_outward_damage","boolean"),
132
Field("is_burned_or_charred","boolean"),
133
Field("is_decayed","boolean"),
134
Field("is_incomplete","boolean"),
139
# Settings and Restrictions
140
#table.pr_pe_parent.readable = True # not visible in body registration form
141
#table.pr_pe_parent.writable = True # not visible in body registration form
142
#table.pr_pe_parent.requires = IS_NULL_OR(IS_ONE_OF(db,"pr_pentity.id",shn_pentity_represent,filterby="opt_pr_entity_type",filter_opts=(3,)))
144
table.pr_pe_label.comment = SPAN("*", _class="req")
145
table.pr_pe_label.requires = [IS_NOT_EMPTY(),IS_NOT_IN_DB(db, "dvi_body.pr_pe_label")]
146
table.date_of_recovery.comment = SPAN("*", _class="req")
147
table.date_of_recovery.requires = IS_DATETIME()
150
table.dvi_recreq_id.label = T("Recovery Request")
151
table.opt_pr_gender.label=T("Apparent Gender")
152
table.opt_pr_age_group.label=T("Apparent Age")
153
table.location_id.label=T("Place of Recovery")
156
table.has_major_outward_damage.represent = lambda opt: (opt and ["yes"] or [""])[0]
157
table.is_burned_or_charred.represent = lambda opt: (opt and ["yes"] or [""])[0]
158
table.is_decayed.represent = lambda opt: (opt and ["yes"] or [""])[0]
159
table.is_incomplete.represent = lambda opt: (opt and ["yes"] or [""])[0]
162
s3.crud_strings[tablename] = Storage(
163
title_create = T("Add Recovery Report"),
164
title_display = T("Dead Body Details"),
165
title_list = T("Body Recovery Reports"),
166
title_update = T("Edit Recovery Details"),
167
title_search = T("Find Recovery Report"),
168
subtitle_create = T("Add New Report"),
169
subtitle_list = T("List of Reports"),
170
label_list_button = T("List Reports"),
171
label_create_button = T("Add Recovery Report"),
172
label_delete_button = T("Delete Recovery Report"),
173
msg_record_created = T("Recovery report added"),
174
msg_record_modified = T("Recovery report updated"),
175
msg_record_deleted = T("Recovery report deleted"),
176
msg_list_empty = T("No recovery reports available"))
178
s3xrc.model.configure(table,
179
onaccept=lambda form: \
180
shn_pentity_onaccept(form, table=db.dvi_body, entity_type=3),
181
delete_onaccept=lambda form: \
182
shn_pentity_ondelete(form),
191
# Checklist of operations -----------------------------------------------------
193
resource = "checklist"
194
tablename = "%s_%s" % (module, resource)
195
table = db.define_table(tablename, timestamp, uuidstamp, deletion_status,
197
Field("personal_effects","integer",
198
requires = IS_IN_SET(dvi_task_status_opts, zero=None),
200
label = T("Inventory of Effects"),
201
represent = lambda opt: dvi_task_status_opts.get(opt, T("not specified"))),
202
Field("body_radiology","integer",
203
requires = IS_IN_SET(dvi_task_status_opts, zero=None),
205
label = T("Radiology"),
206
represent = lambda opt: dvi_task_status_opts.get(opt, T("not specified"))),
207
Field("fingerprints","integer",
208
requires = IS_IN_SET(dvi_task_status_opts, zero=None),
210
label = T("Fingerprinting"),
211
represent = lambda opt: dvi_task_status_opts.get(opt, T("not specified"))),
212
Field("anthropology","integer",
213
requires = IS_IN_SET(dvi_task_status_opts, zero=None),
215
label = T("Anthropolgy"),
216
represent = lambda opt: dvi_task_status_opts.get(opt, T("not specified"))),
217
Field("pathology","integer",
218
requires = IS_IN_SET(dvi_task_status_opts, zero=None),
220
label = T("Pathology"),
221
represent = lambda opt: dvi_task_status_opts.get(opt, T("not specified"))),
222
Field("embalming","integer",
223
requires = IS_IN_SET(dvi_task_status_opts, zero=None),
225
label = T("Embalming"),
226
represent = lambda opt: dvi_task_status_opts.get(opt, T("not specified"))),
227
Field("dna","integer",
228
requires = IS_IN_SET(dvi_task_status_opts, zero=None),
230
label = T("DNA Profiling"),
231
represent = lambda opt: dvi_task_status_opts.get(opt, T("not specified"))),
232
Field("dental","integer",
233
requires = IS_IN_SET(dvi_task_status_opts, zero=None),
235
label = T("Dental Examination"),
236
represent = lambda opt: dvi_task_status_opts.get(opt, T("not specified"))),
239
# Setting and restrictions
242
CREATE_CHECKLIST = T("Create Checklist")
243
s3.crud_strings[tablename] = Storage(
244
title_create = CREATE_CHECKLIST,
245
title_display = T("Checklist of Operations"),
246
title_list = T("List Checklists"),
247
title_update = T("Update Task Status"),
248
title_search = T("Search Checklists"),
249
subtitle_create = T("New Checklist"),
250
subtitle_list = T("Checklist of Operations"),
251
label_list_button = T("Show Checklist"),
252
label_create_button = CREATE_CHECKLIST,
253
msg_record_created = T("Checklist created"),
254
msg_record_modified = T("Checklist updated"),
255
msg_record_deleted = T("Checklist deleted"),
256
msg_list_empty = T("No Checklist available"))
259
s3xrc.model.add_component(module, resource,
265
s3xrc.model.configure(table, list_fields = ["id"])
268
# Personal Effects ------------------------------------------------------------------------
271
tablename = "%s_%s" % (module, resource)
272
table = db.define_table(tablename, timestamp, uuidstamp, deletion_status,
275
Field("clothing", "text"), #TODO: elaborate
276
Field("jewellery", "text"), #TODO: elaborate
277
Field("footwear", "text"), #TODO: elaborate
278
Field("watch", "text"), #TODO: elaborate
279
Field("other", "text"),
282
# Settings and Restrictions
285
#table.person_id.label = T("Reporter")
288
ADD_PERSONAL_EFFECTS = T("Add Personal Effects")
289
s3.crud_strings[tablename] = Storage(
290
title_create = ADD_PERSONAL_EFFECTS,
291
title_display = T("Personal Effects Details"),
292
title_list = T("List Personal Effects"),
293
title_update = T("Edit Personal Effects Details"),
294
title_search = T("Search Personal Effects"),
295
subtitle_create = T("Add New Entry"),
296
subtitle_list = T("Personal Effects"),
297
label_list_button = T("List Records"),
298
label_create_button = ADD_PERSONAL_EFFECTS,
299
msg_record_created = T("Record added"),
300
msg_record_modified = T("Record updated"),
301
msg_record_deleted = T("Record deleted"),
302
msg_list_empty = T("No Details currently registered"))
305
s3xrc.model.add_component(module, resource,
311
s3xrc.model.configure(table, list_fields = ["id"])
314
# Identification --------------------------------------------------------------
316
dvi_id_status_opts = {
322
opt_dvi_id_status = db.Table(None, "opt_dvi_id_status",
323
Field("opt_dvi_id_status","integer",
324
requires = IS_IN_SET(dvi_id_status_opts, zero=None),
326
label = T("Identification Status"),
327
represent = lambda opt: dvi_id_status_opts.get(opt, UNKNOWN_OPT)))
329
dvi_id_method_opts = {
330
1:T("Visual Recognition"),
331
2:T("Physical Description"),
333
4:T("Dental Profile"),
335
6:T("Combined Method"),
336
99:T("Other Evidence")
339
opt_dvi_id_method = db.Table(None, "opt_dvi_id_method",
340
Field("opt_dvi_id_method","integer",
341
requires = IS_IN_SET(dvi_id_method_opts, zero=None),
343
label = T("Method used"),
344
represent = lambda opt: dvi_id_method_opts.get(opt, UNKNOWN_OPT)))
346
resource = "identification"
347
tablename = "%s_%s" % (module, resource)
348
table = db.define_table(tablename, timestamp, uuidstamp, deletion_status,
350
Field("identified_by", db.pr_person), # Person identifying the body
351
Field("reported_by", db.pr_person), # Person reporting
352
opt_dvi_id_status, # Identity status
353
opt_dvi_id_method, # Method used
354
Field("identity", db.pr_person), # Identity of the body
355
Field("comment", "text"), # Comment (optional)
358
# Settings and Restrictions
359
table.identified_by.requires = IS_NULL_OR(IS_ONE_OF(db, "pr_person.id", shn_pr_person_represent))
360
table.identified_by.represent = lambda id: (id and [shn_pr_person_represent(id)] or ["None"])[0]
361
table.identified_by.comment = shn_person_comment
362
table.identified_by.ondelete = "RESTRICT"
364
table.reported_by.requires = IS_NULL_OR(IS_ONE_OF(db, "pr_person.id", shn_pr_person_represent))
365
table.reported_by.represent = lambda id: (id and [shn_pr_person_represent(id)] or ["None"])[0]
366
table.reported_by.comment = shn_person_comment
367
table.reported_by.ondelete = "RESTRICT"
369
table.identity.requires = IS_NULL_OR(IS_ONE_OF(db, "pr_person.id", shn_pr_person_represent))
370
table.identity.represent = lambda id: (id and [shn_pr_person_represent(id)] or ["None"])[0]
371
table.identity.comment = shn_person_comment
372
table.identity.ondelete = "RESTRICT"
377
s3.crud_strings[tablename] = Storage(
378
title_create = T("Add Identification Report"),
379
title_display = T("Identification Report"),
380
title_list = T("List Reports"),
381
title_update = T("Edit Identification Report"),
382
title_search = T("Search Report"),
383
subtitle_create = T("Add New Report"),
384
subtitle_list = T("Identification Reports"),
385
label_list_button = T("List Reports"),
386
label_create_button = T("Add Identification Report"),
387
msg_record_created = T("Report added"),
388
msg_record_modified = T("Report updated"),
389
msg_record_deleted = T("Report deleted"),
390
msg_list_empty = T("No Identification Report Available"))
393
s3xrc.model.add_component(module, resource,
399
s3xrc.model.configure(table, list_fields = ["id"])
401
# -----------------------------------------------------------------------------
403
def shn_dvi_rheader(jr, tabs=[]):
405
""" Page header for component pages """
407
if jr.name == "body":
408
if jr.representation == "html":
412
rheader_tabs = shn_rheader_tabs(jr, tabs)
418
TR(TH(T("ID Label: ")),
419
"%(pr_pe_label)s" % body,
423
TR(TH(T("Gender: ")),
424
"%s" % pr_person_gender_opts[body.opt_pr_gender],
428
TR(TH(T("Age Group: ")),
429
"%s" % pr_person_age_group_opts[body.opt_pr_age_group],
439
# -----------------------------------------------------------------------------
441
def shn_dvi_get_body_id(label, fields=None, filterby=None):
443
"""" find IDs for all body records matching a label """
445
if fields and isinstance(fields, (list,tuple)):
448
if db.dvi_body.has_key(f): # TODO: check for field type?
449
search_fields.append(f)
450
if not len(search_fields):
451
# Error: none of the specified search fields exists
454
# No search fields specified at all => fallback
455
search_fields = ["pr_pe_label"]
457
if label and isinstance(label,str):
458
labels = label.split()
461
# TODO: make a more sophisticated search function (levenshtein?)
466
_l = "%s%s%s" % (wc, l, wc)
469
for f in search_fields:
471
query = (db.dvi_body[f].like(_l)) | query
473
query = (db.dvi_body[f].like(_l))
475
# undeleted records only
476
query = (db.dvi_body.deleted==False) & (query)
477
# restrict to prior results (AND)
479
query = (db.dvi_body.id.belongs(results)) & query
481
query = (filterby) & (query)
482
records = db(query).select(db.dvi_body.id)
483
# rebuild result list
484
results = [r.id for r in records]
490
# no label given or wrong parameter type
493
# -----------------------------------------------------------------------------
495
def shn_dvi_body_search_simple(xrequest, **attr):
497
""" Simple Search form for body recovery reports """
502
if not shn_has_permission("read", db.dvi_body):
503
session.error = UNAUTHORISED
504
redirect(URL(r=request, c="default", f="user", args="login", vars={"_next":URL(r=request, args="search_simple", vars=request.vars)}))
506
if xrequest.representation=="html":
507
# Check for redirection
508
if request.vars._next:
509
next = str.lower(request.vars._next)
511
next = str.lower(URL(r=request, f="body", args="[id]"))
514
response.view = "%s/body_search.html" % xrequest.prefix
517
title = T("Find Recovery Report")
518
subtitle = T("Matching Records")
523
INPUT(_type="text", _name="label", _size="40"),
524
DIV( _class="tooltip", _title=Tstr("ID Label") + "|" + Tstr("To search for a body, enter the ID label of the body. You may use % as wildcard. Press 'Search' without input to list all bodies."))),
525
TR("", INPUT(_type="submit", _value="Search"))
528
output = dict(title=title, subtitle=subtitle, form=form, vars=form.vars)
532
if form.accepts(request.vars, session):
534
if form.vars.label == "":
535
form.vars.label = "%"
537
results = shn_dvi_get_body_id(form.vars.label)
539
if results and len(results):
540
rows = db(db.dvi_body.id.belongs(results)).select()
544
# Build table rows from matching records
548
href = next.replace("%5bid%5d", "%s" % row.id)
550
A(row.pr_pe_label or "[no label]", _href=href),
551
row.opt_pr_gender and pr_person_gender_opts[row.opt_pr_gender] or "unknown",
552
row.opt_pr_age_group and pr_person_age_group_opts[row.opt_pr_age_group] or "unknown",
553
row.date_of_recovery,
554
(row.location_id and [db.gis_location[row.location_id].name] or [""])[0],
555
# location_id.location_id.represent(row.location_id)
557
items=DIV(TABLE(THEAD(TR(
562
TH("Recovery Site"))),
563
TBODY(records), _id="list", _class="display"))
568
label_create_button = s3.crud_strings["dvi_body"].label_create_button
570
label_create_button = s3.crud_strings.label_create_button
572
add_btn = A(label_create_button, _href=URL(r=request, f="body", args="create"), _class="action-btn")
574
output.update(dict(items=items, add_btn=add_btn))
578
session.error = BADFORMAT
579
redirect(URL(r=request))
581
# Plug into REST controller
582
s3xrc.model.set_method(module, "body", method="search_simple", action=shn_dvi_body_search_simple )
584
# -----------------------------------------------------------------------------