2020-04-14 14:17:21 +02:00
# -*- coding: utf-8 -*-
from collections import OrderedDict
from gluon import current , URL
from gluon . storage import Storage
from s3 import S3ReportRepresent
def config ( settings ) :
"""
Settings for the SHARE Template
Migration Issues :
req_need . name is now length = 64
( SHARE can use req_need . description instead if the notnull = True removed )
"""
T = current . T
settings . base . system_name = T ( " Humanitarian Country Team (HCT) Relief and Rehabilitation System " )
settings . base . system_name_short = T ( " SHARE " )
# UI Settings
settings . ui . menu_logo = URL ( c = " static " ,
f = " themes " ,
args = [ " SHARE " , " img " , " sharemenulogo.png " ] ,
)
# PrePopulate data
settings . base . prepopulate . append ( " SHARE " )
settings . base . prepopulate_demo . append ( " SHARE/Demo " )
# Theme (folder to use for views/layout.html)
settings . base . theme = " SHARE "
# Authentication settings
# Should users be allowed to register themselves?
#settings.security.self_registration = False
# Do new users need to verify their email address?
#settings.auth.registration_requires_verification = True
# Do new users need to be approved by an administrator prior to being able to login?
#settings.auth.registration_requires_approval = True
settings . auth . registration_requests_organisation = True
#settings.auth.registration_organisation_required = True
#settings.auth.registration_requests_site = True
settings . auth . registration_link_user_to = { " staff " : T ( " Staff " ) ,
" volunteer " : T ( " Volunteer " ) ,
#"member": T("Member")
}
def registration_organisation_default ( default ) :
auth = current . auth
has_role = auth . s3_has_role
if has_role ( " ORG_ADMIN " ) and not has_role ( " ADMIN " ) :
return auth . user . organisation_id
else :
return default
settings . auth . registration_organisation_default = registration_organisation_default
# Approval emails get sent to all admins
settings . mail . approver = " ADMIN "
# Restrict the Location Selector to just certain countries
# NB This can also be over-ridden for specific contexts later
# e.g. Activities filtered to those of parent Project
#settings.gis.countries = ("US",)
# Uncomment to display the Map Legend as a floating DIV
settings . gis . legend = " float "
# Uncomment to Disable the Postcode selector in the LocationSelector
#settings.gis.postcode_selector = False # @ToDo: Vary by country (include in the gis_config!)
# Uncomment to show the Print control:
# http://eden.sahanafoundation.org/wiki/UserGuidelines/Admin/MapPrinting
#settings.gis.print_button = True
# GeoNames username
settings . gis . geonames_username = " trendspotter "
settings . gis . simplify_tolerance = 0
# L10n settings
# Number formats (defaults to ISO 31-0)
# Decimal separator for numbers (defaults to ,)
settings . L10n . decimal_separator = " . "
# Thousands separator for numbers (defaults to space)
settings . L10n . thousands_separator = " , "
# Security Policy
# http://eden.sahanafoundation.org/wiki/S3AAA#System-widePolicy
# 1: Simple (default): Global as Reader, Authenticated as Editor
# 2: Editor role required for Update/Delete, unless record owned by session
# 3: Apply Controller ACLs
# 4: Apply both Controller & Function ACLs
# 5: Apply Controller, Function & Table ACLs
# 6: Apply Controller, Function, Table ACLs and Entity Realm
# 7: Apply Controller, Function, Table ACLs and Entity Realm + Hierarchy
# 8: Apply Controller, Function, Table ACLs, Entity Realm + Hierarchy and Delegations
settings . security . policy = 6 # Controller, Function, Table ACLs and Entity Realm
# Don't show version info on About page
settings . security . version_info = False
# UI Settings
settings . ui . datatables_responsive = False
settings . ui . datatables_double_scroll = True
# Disable permalink
settings . ui . label_permalink = None
# Default summary pages:
settings . ui . summary = ( { " common " : True ,
" name " : " add " ,
" widgets " : [ { " method " : " create " } ] ,
} ,
{ " name " : " table " ,
" label " : " Table " ,
" widgets " : [ { " method " : " datatable " } ] ,
} ,
)
# -------------------------------------------------------------------------
# CMS Content Management
#
settings . cms . bookmarks = True
settings . cms . richtext = True
settings . cms . show_tags = True
# -------------------------------------------------------------------------
# Events
settings . event . label = " Disaster "
# Uncomment to not use Incidents under Events
settings . event . incident = False
# -------------------------------------------------------------------------
# Messaging
settings . msg . parser = " SAMBRO " # for parse_tweet
# -------------------------------------------------------------------------
# Organisations
settings . org . sector = True
# Show Organisation Types in the rheader
settings . org . organisation_type_rheader = True
# -------------------------------------------------------------------------
# Projects
# Don't use Beneficiaries
settings . project . activity_beneficiaries = False
# Don't use Item Catalog for Distributions
settings . project . activity_items = False
settings . project . activity_sectors = True
# Links to Filtered Components for Donors & Partners
settings . project . organisation_roles = {
1 : T ( " Organization " ) ,
2 : T ( " Implementing Partner " ) ,
3 : T ( " Donor " ) ,
}
# -------------------------------------------------------------------------
# Supply
# Disable the use of Multiple Item Catalogs
settings . supply . catalog_multi = False
# -------------------------------------------------------------------------
# Comment/uncomment modules here to disable/enable them
# Modules menu is defined in modules/eden/menu.py
settings . modules = OrderedDict ( [
# Core modules which shouldn't be disabled
( " default " , Storage (
name_nice = " Home " ,
restricted = False , # Use ACLs to control access to this module
access = None , # All Users (inc Anonymous) can see this module in the default menu & access the controller
module_type = None # This item is not shown in the menu
) ) ,
( " admin " , Storage (
name_nice = " Administration " ,
#description = "Site Administration",
restricted = True ,
access = " |1| " , # Only Administrators can see this module in the default menu & access the controller
module_type = None # This item is handled separately for the menu
) ) ,
( " appadmin " , Storage (
name_nice = " Administration " ,
#description = "Site Administration",
restricted = True ,
module_type = None # No Menu
) ) ,
( " errors " , Storage (
name_nice = " Ticket Viewer " ,
#description = "Needed for Breadcrumbs",
restricted = False ,
module_type = None # No Menu
) ) ,
( " setup " , Storage (
name_nice = T ( " Setup " ) ,
#description = "WebSetup",
restricted = True ,
access = " |1| " , # Only Administrators can see this module in the default menu & access the controller
module_type = None # No Menu
) ) ,
( " sync " , Storage (
name_nice = " Synchronization " ,
#description = "Synchronization",
restricted = True ,
access = " |1| " , # Only Administrators can see this module in the default menu & access the controller
module_type = None # This item is handled separately for the menu
) ) ,
#("tour", Storage(
# name_nice = T("Guided Tour Functionality"),
# module_type = None,
#)),
( " translate " , Storage (
name_nice = T ( " Translation Functionality " ) ,
#description = "Selective translation of strings based on module.",
module_type = None ,
) ) ,
( " gis " , Storage (
name_nice = " Map " ,
#description = "Situation Awareness & Geospatial Analysis",
restricted = True ,
module_type = 6 , # 6th item in the menu
) ) ,
( " pr " , Storage (
name_nice = " Person Registry " ,
#description = "Central point to record details on People",
restricted = True ,
access = " |1| " , # Only Administrators can see this module in the default menu (access to controller is possible to all still)
module_type = 10
) ) ,
( " org " , Storage (
name_nice = " Organizations " ,
#description = 'Lists "who is doing what & where". Allows relief agencies to coordinate their activities',
restricted = True ,
module_type = 1
) ) ,
( " hrm " , Storage (
name_nice = " Staff " ,
#description = "Human Resources Management",
restricted = True ,
module_type = 2 ,
) ) ,
( " vol " , Storage (
name_nice = T ( " Volunteers " ) ,
#description = "Human Resources Management",
restricted = True ,
module_type = 2 ,
) ) ,
( " cms " , Storage (
name_nice = " Content Management " ,
#description = "Content Management System",
restricted = True ,
module_type = 10 ,
) ) ,
( " doc " , Storage (
name_nice = " Documents " ,
#description = "A library of digital resources, such as photos, documents and reports",
restricted = True ,
module_type = 10 ,
) ) ,
( " msg " , Storage (
name_nice = " Messaging " ,
#description = "Sends & Receives Alerts via Email & SMS",
restricted = True ,
# The user-visible functionality of this module isn't normally required. Rather it's main purpose is to be accessed from other modules.
module_type = None ,
) ) ,
( " supply " , Storage (
name_nice = " Supply Chain Management " ,
#description = "Used within Inventory Management, Request Management and Asset Management",
restricted = True ,
module_type = None , # Not displayed
) ) ,
( " inv " , Storage (
name_nice = T ( " Warehouses " ) ,
#description = "Receiving and Sending Items",
restricted = True ,
module_type = 4
) ) ,
( " asset " , Storage (
name_nice = " Assets " ,
#description = "Recording and Assigning Assets",
restricted = True ,
module_type = 5 ,
) ) ,
# Vehicle depends on Assets
#("vehicle", Storage(
# name_nice = "Vehicles",
# #description = "Manage Vehicles",
# restricted = True,
# module_type = 10,
#)),
( " req " , Storage (
name_nice = " Requests " ,
#description = "Manage requests for supplies, assets, staff or other resources. Matches against Inventories where supplies are requested.",
restricted = True ,
module_type = 10 ,
) ) ,
# Used just for Statuses
( " project " , Storage (
name_nice = " Tasks " ,
#description = "Tracking of Projects, Activities and Tasks",
restricted = True ,
module_type = 2
) ) ,
#("cr", Storage(
# name_nice = T("Shelters"),
# #description = "Tracks the location, capacity and breakdown of victims in Shelters",
# restricted = True,
# module_type = 10
#)),
#("hms", Storage(
# name_nice = T("Hospitals"),
# #description = "Helps to monitor status of hospitals",
# restricted = True,
# module_type = 10
#)),
#("dvr", Storage(
# name_nice = T("Disaster Victim Registry"),
# #description = "Allow affected individuals & households to register to receive compensation and distributions",
# restricted = True,
# module_type = 10,
#)),
( " event " , Storage (
name_nice = " Events " ,
#description = "Activate Events (e.g. from Scenario templates) for allocation of appropriate Resources (Human, Assets & Facilities).",
restricted = True ,
module_type = 10 ,
) ) ,
#("transport", Storage(
# name_nice = T("Transport"),
# restricted = True,
# module_type = 10,
#)),
( " stats " , Storage (
name_nice = T ( " Statistics " ) ,
#description = "Manages statistics",
restricted = True ,
module_type = None ,
) ) ,
] )
# -------------------------------------------------------------------------
def customise_cms_post_resource ( r , tablename ) :
import json
from s3 import S3SQLCustomForm , S3SQLInlineComponent , \
S3DateFilter , S3OptionsFilter , S3TextFilter , \
s3_fieldmethod
s3db = current . s3db
# Virtual Field for Comments
# - otherwise need to do per-record DB calls inside cms_post_list_layout
# as direct list_fields come in unsorted, so can't match up to records
ctable = s3db . cms_comment
def comment_as_json ( row ) :
body = row [ " cms_comment.body " ]
if not body :
return None
return json . dumps ( { " body " : body ,
" created_by " : row [ " cms_comment.created_by " ] ,
" created_on " : row [ " cms_comment.created_on " ] . isoformat ( ) ,
} )
ctable . json_dump = s3_fieldmethod ( " json_dump " ,
comment_as_json ,
# over-ride the default represent of s3_unicode to prevent HTML being rendered too early
#represent = lambda v: v,
)
s3db . configure ( " cms_comment " ,
extra_fields = [ " body " ,
" created_by " ,
" created_on " ,
] ,
# Doesn't seem to have any impact
#orderby = "cms_comment.created_on asc",
)
table = s3db . cms_post
table . priority . readable = table . priority . writable = True
#table.series_id.readable = table.series_id.writable = True
#table.status_id.readable = table.status_id.writable = True
crud_form = S3SQLCustomForm ( #(T("Type"), "series_id"),
( T ( " Priority " ) , " priority " ) ,
#(T("Status"), "status_id"),
( T ( " Title " ) , " title " ) ,
( T ( " Text " ) , " body " ) ,
#(T("Location"), "location_id"),
# Tags are added client-side
S3SQLInlineComponent ( " document " ,
name = " file " ,
label = T ( " Files " ) ,
fields = [ ( " " , " file " ) ,
#"comments",
] ,
) ,
)
date_filter = S3DateFilter ( " date " ,
# If we introduce an end_date on Posts:
#["date", "end_date"],
label = " " ,
#hide_time = True,
#slider = True,
clear_text = " X " ,
)
date_filter . input_labels = { " ge " : " Start Time/Date " , " le " : " End Time/Date " }
filter_widgets = [ S3TextFilter ( [ " body " ,
] ,
#formstyle = text_filter_formstyle,
label = T ( " Search " ) ,
_placeholder = T ( " Enter search term… " ) ,
) ,
#S3OptionsFilter("series_id",
# label = "",
# noneSelectedText = "Type", # T() added in widget
# no_opts = "",
# ),
S3OptionsFilter ( " priority " ,
label = " " ,
noneSelectedText = " Priority " , # T() added in widget
no_opts = " " ,
) ,
#S3OptionsFilter("status_id",
# label = "",
# noneSelectedText = "Status", # T() added in widget
# no_opts = "",
# ),
S3OptionsFilter ( " created_by$organisation_id " ,
label = " " ,
noneSelectedText = " Source " , # T() added in widget
no_opts = " " ,
) ,
S3OptionsFilter ( " tag_post.tag_id " ,
label = " " ,
noneSelectedText = " Tag " , # T() added in widget
no_opts = " " ,
) ,
date_filter ,
]
from templates . SHARE . controllers import cms_post_list_layout
s3db . configure ( " cms_post " ,
create_next = URL ( args = [ 1 , " post " , " datalist " ] ) ,
crud_form = crud_form ,
filter_widgets = filter_widgets ,
list_fields = [ #"series_id",
" priority " ,
#"status_id",
" date " ,
" title " ,
" body " ,
" created_by " ,
" tag.name " ,
" document.file " ,
" comment.json_dump " ,
] ,
list_layout = cms_post_list_layout ,
)
settings . customise_cms_post_resource = customise_cms_post_resource
# -------------------------------------------------------------------------
def customise_event_sitrep_resource ( r , tablename ) :
from s3 import s3_comments_widget
table = current . s3db . event_sitrep
table . name . widget = lambda f , v : \
s3_comments_widget ( f , v , _placeholder = " Please provide a brief summary of the Situational Update you are submitting. " )
table . comments . comment = None
table . comments . widget = lambda f , v : \
s3_comments_widget ( f , v , _placeholder = " e.g. Any additional relevant information. " )
current . response . s3 . crud_strings [ tablename ] = Storage (
label_create = T ( " Add Situational Update " ) ,
title_display = T ( " HCT Activity and Response Report " ) ,
title_list = T ( " Situational Updates " ) ,
title_update = T ( " Edit Situational Update " ) ,
title_upload = T ( " Import Situational Updates " ) ,
label_list_button = T ( " List Situational Updates " ) ,
label_delete_button = T ( " Delete Situational Update " ) ,
msg_record_created = T ( " Situational Update added " ) ,
msg_record_modified = T ( " Situational Update updated " ) ,
msg_record_deleted = T ( " Situational Update deleted " ) ,
msg_list_empty = T ( " No Situational Updates currently registered " ) )
settings . customise_event_sitrep_resource = customise_event_sitrep_resource
# -----------------------------------------------------------------------------
def customise_event_sitrep_controller ( * * attr ) :
s3 = current . response . s3
# Custom postp
standard_postp = s3 . postp
def postp ( r , output ) :
# Call standard postp
if callable ( standard_postp ) :
output = standard_postp ( r , output )
if r . interactive :
# Mark this page to have differential CSS
s3 . jquery_ready . append ( ''' $( ' main ' ).attr( ' id ' , ' sitrep ' ) ''' )
return output
s3 . postp = postp
# Extend the width of the Summary column
dt_col_widths = { 0 : 110 ,
1 : 95 ,
2 : 100 ,
3 : 100 ,
4 : 100 ,
5 : 100 ,
6 : 110 ,
7 : 80 ,
8 : 90 ,
9 : 300 ,
10 : 110 ,
}
if " dtargs " in attr :
attr [ " dtargs " ] [ " dt_col_widths " ] = dt_col_widths
else :
attr [ " dtargs " ] = { " dt_col_widths " : dt_col_widths ,
}
return attr
settings . customise_event_sitrep_controller = customise_event_sitrep_controller
# -----------------------------------------------------------------------------
def customise_gis_location_controller ( * * attr ) :
s3 = current . response . s3
# Custom prep
standard_prep = s3 . prep
def custom_prep ( r ) :
# Call standard prep
if callable ( standard_prep ) :
result = standard_prep ( r )
else :
result = True
if r . representation == " json " :
# Special filter vars to find child locations while
# including the parent location in the JSON result:
# adm => the parent location ID
# l => the target Lx level for child locations
get_vars = r . get_vars
adm = get_vars . get ( " adm " )
if adm :
from s3 import FS
resource = r . resource
# Filter for children of adm
query = FS ( " parent " ) == adm
# Restrict children to a certain Lx level
level = get_vars . get ( " l " )
if level :
q = FS ( " level " ) == level
query = ( query & q ) if query else q
# Always include adm
query = ( FS ( " id " ) == adm ) | query
resource . add_filter ( query )
# Push the parent to top of the list + alpha-sort
table = resource . table
resource . configure ( orderby = ( table . level , table . name ) )
return result
s3 . prep = custom_prep
return attr
settings . customise_gis_location_controller = customise_gis_location_controller
# -------------------------------------------------------------------------
def customise_msg_twitter_channel_resource ( r , tablename ) :
s3db = current . s3db
def onaccept ( form ) :
# Normal onaccept
s3db . msg_channel_onaccept ( form )
_id = form . vars . id
db = current . db
table = db . msg_twitter_channel
channel_id = db ( table . id == _id ) . select ( table . channel_id ,
limitby = ( 0 , 1 ) ) . first ( ) . channel_id
# Link to Parser
table = s3db . msg_parser
_id = table . insert ( channel_id = channel_id , function_name = " parse_tweet " , enabled = True )
s3db . msg_parser_enable ( _id )
run_async = current . s3task . run_async
# Poll
run_async ( " msg_poll " , args = [ " msg_twitter_channel " , channel_id ] )
# Parse
run_async ( " msg_parse " , args = [ channel_id , " parse_tweet " ] )
s3db . configure ( tablename ,
create_onaccept = onaccept ,
)
settings . customise_msg_twitter_channel_resource = customise_msg_twitter_channel_resource
# -------------------------------------------------------------------------
def customise_org_organisation_resource ( r , tablename ) :
s3db = current . s3db
# Custom Components
s3db . add_components ( tablename ,
org_organisation_tag = ( # Request Number
{ " name " : " req_number " ,
" joinby " : " organisation_id " ,
" filterby " : { " tag " : " req_number " ,
} ,
" multiple " : False ,
} ,
# Vision
{ " name " : " vision " ,
" joinby " : " organisation_id " ,
" filterby " : { " tag " : " vision " ,
} ,
" multiple " : False ,
} ,
) ,
)
from s3 import S3SQLCustomForm , S3SQLInlineComponent , S3SQLInlineLink , s3_comments_widget
# Individual settings for specific tag components
components_get = s3db . resource ( tablename ) . components . get
vision = components_get ( " vision " )
vision . table . value . widget = s3_comments_widget
crud_form = S3SQLCustomForm ( " name " ,
" acronym " ,
S3SQLInlineLink ( " organisation_type " ,
field = " organisation_type_id " ,
# Default 10 options just triggers which adds unnecessary complexity to a commonly-used form & commonly an early one (create Org when registering)
search = False ,
label = T ( " Type " ) ,
multiple = False ,
widget = " multiselect " ,
) ,
S3SQLInlineLink ( " sector " ,
columns = 4 ,
field = " sector_id " ,
label = T ( " Sectors " ) ,
) ,
#S3SQLInlineLink("service",
# columns = 4,
# field = "service_id",
# label = T("Services"),
# ),
" country " ,
" phone " ,
" website " ,
" logo " ,
( T ( " About " ) , " comments " ) ,
S3SQLInlineComponent ( " vision " ,
label = T ( " Vision " ) ,
fields = [ ( " " , " value " ) ] ,
multiple = False ,
) ,
S3SQLInlineComponent ( " req_number " ,
label = T ( " Request Number " ) ,
fields = [ ( " " , " value " ) ] ,
multiple = False ,
) ,
)
s3db . configure ( tablename ,
crud_form = crud_form ,
)
settings . customise_org_organisation_resource = customise_org_organisation_resource
# -------------------------------------------------------------------------
def customise_org_sector_controller ( * * attr ) :
s3db = current . s3db
tablename = " org_sector "
# Just 1 set of sectors / sector leads nationally
# @ToDo: Deployment Setting
#f = s3db.org_sector.location_id
#f.readable = f.writable = False
# Custom Component for Sector Leads
s3db . add_components ( tablename ,
org_sector_organisation = { " name " : " sector_lead " ,
" joinby " : " sector_id " ,
" filterby " : { " lead " : True ,
} ,
} ,
)
from s3 import S3SQLCustomForm , S3SQLInlineComponent
crud_form = S3SQLCustomForm ( " name " ,
" abrv " ,
" comments " ,
S3SQLInlineComponent ( " sector_lead " ,
label = T ( " Lead Organization(s) " ) ,
fields = [ ( " " , " organisation_id " ) , ] ,
) ,
)
s3db . configure ( tablename ,
crud_form = crud_form ,
list_fields = [ " name " ,
" abrv " ,
( T ( " Lead Organization(s) " ) , " sector_lead.organisation_id " ) ,
] ,
)
return attr
settings . customise_org_sector_controller = customise_org_sector_controller
# -------------------------------------------------------------------------
def customise_pr_forum_controller ( * * attr ) :
s3db = current . s3db
s3 = current . response . s3
s3db . pr_forum
s3 . crud_strings [ " pr_forum " ] . title_display = T ( " HCT Coordination Folders " )
s3 . dl_no_header = True
# Comments
appname = current . request . application
s3 . scripts . append ( " / %s /static/themes/WACOP/js/update_comments.js " % appname )
script = ''' S3.wacop_comments()
S3 . redraw_fns . push ( ' wacop_comments ' ) '''
s3 . jquery_ready . append ( script )
# Tags for Updates
if s3 . debug :
s3 . scripts . append ( " / %s /static/scripts/tag-it.js " % appname )
else :
s3 . scripts . append ( " / %s /static/scripts/tag-it.min.js " % appname )
if current . auth . s3_has_permission ( " update " , s3db . cms_tag_post ) :
# @ToDo: Move the ajaxUpdateOptions into callback of getS3?
readonly = ''' afterTagAdded:function(event,ui) {
if ( ui . duringInitialization ) { return }
var post_id = $ ( this ) . attr ( ' data-post_id ' )
var url = S3 . Ap . concat ( ' /cms/post/ ' , post_id , ' /add_tag/ ' , ui . tagLabel )
$ . getS3 ( url )
S3 . search . ajaxUpdateOptions ( ' #datalist-filter-form ' )
} , afterTagRemoved : function ( event , ui ) {
var post_id = $ ( this ) . attr ( ' data-post_id ' )
var url = S3 . Ap . concat ( ' /cms/post/ ' , post_id , ' /remove_tag/ ' , ui . tagLabel )
$ . getS3 ( url )
S3 . search . ajaxUpdateOptions ( ' #datalist-filter-form ' )
} , '''
else :
readonly = ''' readOnly:true '''
script = \
''' S3.tagit=function() { $( ' .s3-tags ' ).tagit( { placeholderText: ' %s ' ,autocomplete: { source: ' %s ' }, %s })}
S3 . tagit ( )
S3 . redraw_fns . push ( ' tagit ' ) ''' % (T( " Add tags here… " ),
URL ( c = " cms " , f = " tag " ,
args = " tag_list.json " ) ,
readonly )
s3 . jquery_ready . append ( script )
attr [ " rheader " ] = None
attr [ " hide_filter " ] = False
return attr
settings . customise_pr_forum_controller = customise_pr_forum_controller
# -------------------------------------------------------------------------
def req_need_commit ( r , * * attr ) :
"""
Custom method to Commit to a Need by creating an Activity Group
"""
# Create Activity Group (Response) with values from Need
need_id = r . id
db = current . db
s3db = current . s3db
ntable = s3db . req_need
ntable_id = ntable . id
netable = s3db . event_event_need
left = [ netable . on ( netable . need_id == ntable_id ) ,
]
need = db ( ntable_id == need_id ) . select ( ntable . name ,
ntable . location_id ,
netable . event_id ,
left = left ,
limitby = ( 0 , 1 )
) . first ( )
nttable = s3db . req_need_tag
query = ( nttable . need_id == need_id ) & \
( nttable . tag . belongs ( ( " address " , " contact " ) ) ) & \
( nttable . deleted == False )
tags = db ( query ) . select ( nttable . tag ,
nttable . value ,
)
contact = address = None
for tag in tags :
if tag . tag == " address " :
address = tag . value
elif tag . tag == " contact " :
contact = tag . value
nrtable = s3db . req_need_response
need_response_id = nrtable . insert ( need_id = need_id ,
name = need [ " req_need.name " ] ,
location_id = need [ " req_need.location_id " ] ,
contact = contact ,
address = address ,
)
organisation_id = current . auth . user . organisation_id
if organisation_id :
s3db . req_need_response_organisation . insert ( need_response_id = need_response_id ,
organisation_id = organisation_id ,
role = 1 ,
)
event_id = need [ " event_event_need.event_id " ]
if event_id :
aetable = s3db . event_event_need_response
aetable . insert ( need_response_id = need_response_id ,
event_id = event_id ,
)
nltable = s3db . req_need_line
query = ( nltable . need_id == need_id ) & \
( nltable . deleted == False )
lines = db ( query ) . select ( nltable . id ,
nltable . coarse_location_id ,
nltable . location_id ,
nltable . sector_id ,
nltable . parameter_id ,
nltable . value ,
nltable . value_uncommitted ,
nltable . item_category_id ,
nltable . item_id ,
nltable . item_pack_id ,
nltable . quantity ,
nltable . quantity_uncommitted ,
nltable . status ,
)
if lines :
linsert = s3db . req_need_response_line . insert
for line in lines :
value_uncommitted = line . value_uncommitted
if value_uncommitted is None :
# No commitments yet so commit to all
value = line . value
else :
# Only commit to the remainder
value = value_uncommitted
quantity_uncommitted = line . quantity_uncommitted
if quantity_uncommitted is None :
# No commitments yet so commit to all
quantity = line . quantity
else :
# Only commit to the remainder
quantity = quantity_uncommitted
need_line_id = line . id
linsert ( need_response_id = need_response_id ,
need_line_id = need_line_id ,
coarse_location_id = line . coarse_location_id ,
location_id = line . location_id ,
sector_id = line . sector_id ,
parameter_id = line . parameter_id ,
value = value ,
item_category_id = line . item_category_id ,
item_id = line . item_id ,
item_pack_id = line . item_pack_id ,
quantity = quantity ,
)
# Update Need Line status
req_need_line_status_update ( need_line_id )
# Redirect to Update
from gluon import redirect
redirect ( URL ( c = " req " , f = " need_response " ,
args = [ need_response_id , " update " ] ,
) )
# -------------------------------------------------------------------------
def req_need_line_commit ( r , * * attr ) :
"""
Custom method to Commit to a Need Line by creating an Activity
"""
# Create Activity with values from Need Line
need_line_id = r . id
db = current . db
s3db = current . s3db
nltable = s3db . req_need_line
query = ( nltable . id == need_line_id )
line = db ( query ) . select ( nltable . id ,
nltable . need_id ,
nltable . coarse_location_id ,
nltable . location_id ,
nltable . sector_id ,
nltable . parameter_id ,
nltable . value ,
nltable . value_uncommitted ,
nltable . item_category_id ,
nltable . item_id ,
nltable . item_pack_id ,
nltable . quantity ,
nltable . quantity_uncommitted ,
nltable . status ,
limitby = ( 0 , 1 )
) . first ( )
need_id = line . need_id
ntable = s3db . req_need
ntable_id = ntable . id
netable = s3db . event_event_need
left = [ netable . on ( netable . need_id == ntable_id ) ,
]
need = db ( ntable_id == need_id ) . select ( ntable . name ,
ntable . location_id ,
netable . event_id ,
left = left ,
limitby = ( 0 , 1 )
) . first ( )
nttable = s3db . req_need_tag
query = ( nttable . need_id == need_id ) & \
( nttable . tag . belongs ( ( " address " , " contact " ) ) ) & \
( nttable . deleted == False )
tags = db ( query ) . select ( nttable . tag ,
nttable . value ,
)
contact = address = None
for tag in tags :
if tag . tag == " address " :
address = tag . value
elif tag . tag == " contact " :
contact = tag . value
nrtable = s3db . req_need_response
need_response_id = nrtable . insert ( need_id = need_id ,
name = need [ " req_need.name " ] ,
location_id = need [ " req_need.location_id " ] ,
contact = contact ,
address = address ,
)
organisation_id = current . auth . user . organisation_id
if organisation_id :
s3db . req_need_response_organisation . insert ( need_response_id = need_response_id ,
organisation_id = organisation_id ,
role = 1 ,
)
event_id = need [ " event_event_need.event_id " ]
if event_id :
aetable = s3db . event_event_need_response
aetable . insert ( need_response_id = need_response_id ,
event_id = event_id ,
)
value_uncommitted = line . value_uncommitted
if value_uncommitted is None :
# No commitments yet so commit to all
value = line . value
else :
# Only commit to the remainder
value = value_uncommitted
quantity_uncommitted = line . quantity_uncommitted
if quantity_uncommitted is None :
# No commitments yet so commit to all
quantity = line . quantity
else :
# Only commit to the remainder
quantity = quantity_uncommitted
s3db . req_need_response_line . insert ( need_response_id = need_response_id ,
need_line_id = need_line_id ,
coarse_location_id = line . coarse_location_id ,
location_id = line . location_id ,
sector_id = line . sector_id ,
parameter_id = line . parameter_id ,
value = value ,
item_category_id = line . item_category_id ,
item_id = line . item_id ,
item_pack_id = line . item_pack_id ,
quantity = quantity ,
)
# Update Need Line status
req_need_line_status_update ( need_line_id )
# Redirect to Update
from gluon import redirect
redirect ( URL ( c = " req " , f = " need_response " ,
args = [ need_response_id , " update " ] ,
) )
# -------------------------------------------------------------------------
def req_need_line_status_update ( need_line_id ) :
"""
Update the Need Line ' s fulfilment Status
"""
db = current . db
s3db = current . s3db
# Read the Line details
nltable = s3db . req_need_line
iptable = s3db . supply_item_pack
query = ( nltable . id == need_line_id )
left = iptable . on ( nltable . item_pack_id == iptable . id )
need_line = db ( query ) . select ( nltable . parameter_id ,
nltable . value ,
nltable . item_id ,
nltable . quantity ,
iptable . quantity ,
left = left ,
limitby = ( 0 , 1 )
) . first ( )
need_pack_qty = need_line [ " supply_item_pack.quantity " ]
need_line = need_line [ " req_need_line " ]
need_parameter_id = need_line . parameter_id
need_value = need_line . value or 0
need_value_committed = 0
need_value_reached = 0
need_quantity = need_line . quantity
if need_quantity :
need_quantity = need_quantity * need_pack_qty
else :
need_quantity = 0
need_item_id = need_line . item_id
need_quantity_committed = 0
need_quantity_delivered = 0
# Lookup which Status means 'Cancelled'
stable = s3db . project_status
status = db ( stable . name == " Cancelled " ) . select ( stable . id ,
limitby = ( 0 , 1 )
) . first ( )
try :
CANCELLED = status . id
except AttributeError :
# Prepop not done? Name changed?
current . log . debug ( " ' Cancelled ' Status not found " )
CANCELLED = 999999
# Read the details of all Response Lines linked to this Need Line
rltable = s3db . req_need_response_line
iptable = s3db . supply_item_pack
query = ( rltable . need_line_id == need_line_id ) & \
( rltable . deleted == False )
left = iptable . on ( rltable . item_pack_id == iptable . id )
response_lines = db ( query ) . select ( rltable . id ,
rltable . parameter_id ,
rltable . value ,
rltable . value_reached ,
rltable . item_id ,
iptable . quantity ,
rltable . quantity ,
rltable . quantity_delivered ,
rltable . status_id ,
left = left ,
)
for line in response_lines :
pack_qty = line [ " supply_item_pack.quantity " ]
line = line [ " req_need_response_line " ]
if line . status_id == CANCELLED :
continue
if line . parameter_id == need_parameter_id :
value = line . value
if value :
need_value_committed + = value
value_reached = line . value_reached
if value_reached :
need_value_reached + = value_reached
if line . item_id == need_item_id :
quantity = line . quantity
if quantity :
need_quantity_committed + = quantity * pack_qty
quantity_delivered = line . quantity_delivered
if quantity_delivered :
need_quantity_delivered + = quantity_delivered * pack_qty
# Calculate Need values & Update
value_uncommitted = max ( need_value - need_value_committed , 0 )
quantity_uncommitted = max ( need_quantity - need_quantity_committed , 0 )
if ( need_quantity_delivered > = need_quantity ) and ( need_value_reached > = need_value ) :
status = 3
elif ( quantity_uncommitted < = 0 ) and ( value_uncommitted < = 0 ) :
status = 2
elif ( need_quantity_committed > 0 ) or ( need_value_committed > 0 ) :
status = 1
else :
status = 0
db ( nltable . id == need_line_id ) . update ( value_committed = need_value_committed ,
value_uncommitted = value_uncommitted ,
value_reached = need_value_reached ,
quantity_committed = need_quantity_committed ,
quantity_uncommitted = quantity_uncommitted ,
quantity_delivered = need_quantity_delivered ,
status = status ,
)
# -------------------------------------------------------------------------
def req_need_postprocess ( form ) :
"""
Set the Realm
Set the Request Number
"""
need_id = form . vars . id
db = current . db
s3db = current . s3db
# Lookup Organisation
notable = s3db . req_need_organisation
org_link = db ( notable . need_id == need_id ) . select ( notable . organisation_id ,
limitby = ( 0 , 1 ) ,
) . first ( )
if org_link :
organisation_id = org_link . organisation_id
else :
# Create the link (form isn't doing so when readonly!)
user = current . auth . user
if user and user . organisation_id :
organisation_id = user . organisation_id
if organisation_id :
notable . insert ( need_id = need_id ,
organisation_id = organisation_id )
else :
# Nothing we can do!
return
else :
# Nothing we can do!
return
# Lookup Realm
otable = s3db . org_organisation
org = db ( otable . id == organisation_id ) . select ( otable . pe_id ,
limitby = ( 0 , 1 ) ,
) . first ( )
realm_entity = org . pe_id
# Set Realm
ntable = s3db . req_need
db ( ntable . id == need_id ) . update ( realm_entity = realm_entity )
nltable = s3db . req_need_line
db ( nltable . need_id == need_id ) . update ( realm_entity = realm_entity )
if form . record :
# Update form
return
# Lookup Request Number format
ottable = s3db . org_organisation_tag
query = ( ottable . organisation_id == organisation_id ) & \
( ottable . tag == " req_number " )
tag = db ( query ) . select ( ottable . value ,
limitby = ( 0 , 1 ) ,
) . first ( )
if not tag :
return
# Lookup most recently-used value
nttable = s3db . req_need_tag
query = ( nttable . tag == " req_number " ) & \
( nttable . need_id != need_id ) & \
( nttable . need_id == notable . need_id ) & \
( notable . organisation_id == organisation_id )
need = db ( query ) . select ( nttable . value ,
limitby = ( 0 , 1 ) ,
orderby = ~ nttable . created_on ,
) . first ( )
# Set Request Number
if need :
new_number = int ( need . value . split ( " - " , 1 ) [ 1 ] ) + 1
req_number = " %s - %s " % ( tag . value , str ( new_number ) . zfill ( 6 ) )
else :
req_number = " %s -000001 " % tag . value
nttable . insert ( need_id = need_id ,
tag = " req_number " ,
value = req_number ,
)
# -------------------------------------------------------------------------
def customise_req_need_resource ( r , tablename ) :
from gluon import IS_EMPTY_OR , IS_IN_SET
from s3 import s3_comments_widget , \
S3LocationSelector , S3LocationDropdownWidget , \
S3Represent , \
S3SQLCustomForm , S3SQLInlineComponent , S3SQLInlineLink
db = current . db
s3db = current . s3db
table = s3db . req_need
table . name . widget = lambda f , v : \
s3_comments_widget ( f , v , _placeholder = " e.g. 400 families require drinking water in Kegalle DS Division in 1-2 days. " )
table . comments . comment = None
table . comments . widget = lambda f , v : \
s3_comments_widget ( f , v , _placeholder = " e.g. Accessibility issues, additional contacts on the ground (if any), any other relevant information. " )
# These levels/labels are for SHARE/LK
table . location_id . widget = S3LocationSelector ( hide_lx = False ,
levels = ( " L1 " , " L2 " ) ,
required_levels = ( " L1 " , " L2 " ) ,
show_map = False )
ltable = s3db . req_need_line
f = ltable . coarse_location_id
f . label = T ( " Division " )
# @ToDo: Option for gis_LocationRepresent which doesn't show level/parent, but supports translation
# NB cannot have the JS in link to avoid being blocked by Chrome XSS_AUDITOR
location_represent = S3Represent ( lookup = " gis_location " )
f . represent = location_represent
f . widget = S3LocationDropdownWidget ( level = " L3 " , blank = True )
f = ltable . location_id
f . label = T ( " GN " )
f . represent = location_represent
f . widget = S3LocationDropdownWidget ( level = " L4 " , blank = True )
# Custom Filtered Components
s3db . add_components ( tablename ,
req_need_tag = ( # Address
{ " name " : " address " ,
" joinby " : " need_id " ,
" filterby " : { " tag " : " address " ,
} ,
" multiple " : False ,
} ,
# Contact
{ " name " : " contact " ,
" joinby " : " need_id " ,
" filterby " : { " tag " : " contact " ,
} ,
" multiple " : False ,
} ,
# Issue
{ " name " : " issue " ,
" joinby " : " need_id " ,
" filterby " : { " tag " : " issue " ,
} ,
" multiple " : False ,
} ,
# Req Number
{ " name " : " req_number " ,
" joinby " : " need_id " ,
" filterby " : { " tag " : " req_number " ,
} ,
" multiple " : False ,
} ,
# Original Request From
{ " name " : " request_from " ,
" joinby " : " need_id " ,
" filterby " : { " tag " : " request_from " ,
} ,
" multiple " : False ,
} ,
# Verified
{ " name " : " verified " ,
" joinby " : " need_id " ,
" filterby " : { " tag " : " verified " ,
} ,
" multiple " : False ,
} ,
)
)
# Individual settings for specific tag components
components_get = s3db . resource ( tablename ) . components . get
address = components_get ( " address " )
f = address . table . value
f . widget = s3_comments_widget
contact = components_get ( " contact " )
f = contact . table . value
f . widget = lambda f , v : \
s3_comments_widget ( f , v , _placeholder = " of person on the ground e.g. GA, DS " )
issue = components_get ( " issue " )
f = issue . table . value
f . widget = lambda f , v : \
s3_comments_widget ( f , v , _placeholder = " e.g. Lack of accessibility and contaminated wells due to heavy rainfall. " )
request_from = components_get ( " request_from " )
f = request_from . table . value
f . widget = lambda f , v : \
s3_comments_widget ( f , v , _placeholder = " Please indicate the requesting organisation/ministry. " )
verified = components_get ( " verified " )
f = verified . table . value
f . requires = IS_EMPTY_OR ( IS_IN_SET ( ( " Y " , " N " ) ) )
f . represent = lambda v : T ( " yes " ) if v == " Y " else T ( " no " )
from s3 import S3TagCheckboxWidget
f . widget = S3TagCheckboxWidget ( on = " Y " , off = " N " )
f . default = " N "
auth = current . auth
user = auth . user
if user and user . organisation_id :
organisation_id = user . organisation_id
else :
organisation_id = None
if auth . s3_has_role ( " ADMIN " ) or organisation_id :
f . default = " Y "
else :
f . writable = False
if r . id and r . resource . tablename == tablename :
# Read or Update
create = False
else :
# Create
create = True
if not create :
# Read or Update
if organisation_id :
org_readonly = True
else :
rotable = s3db . req_need_organisation
org_link = db ( rotable . need_id == r . id ) . select ( rotable . organisation_id ,
limitby = ( 0 , 1 )
) . first ( )
if org_link :
org_readonly = True
else :
org_readonly = False
#table = s3db.req_need_item
#table.quantity.label = T("Quantity Requested")
#table.quantity_committed.readable = True
#table.quantity_uncommitted.readable = True
#table.quantity_delivered.readable = True
#need_item = S3SQLInlineComponent("need_item",
# label = T("Items Needed"),
# fields = ["item_category_id",
# "item_id",
# (T("Unit"), "item_pack_id"),
# (T("Needed within Timeframe"), "timeframe"),
# "quantity",
# "quantity_committed",
# "quantity_uncommitted",
# "quantity_delivered",
# #(T("Urgency"), "priority"),
# "comments",
# ],
# )
#table = s3db.req_need_demographic
#table.value.label = T("Number in Need")
#table.value_committed.readable = True
#table.value_uncommitted.readable = True
#table.value_reached.readable = True
#demographic = S3SQLInlineComponent("need_demographic",
# label = T("People Affected"),
# fields = [(T("Type"), "parameter_id"),
# #(T("Needed within Timeframe"), "timeframe"),
# "value",
# "value_committed",
# "value_uncommitted",
# "value_reached",
# "comments",
# ],
# )
#ltable.value.label = T("Number in Need")
ltable . value_committed . readable = True
ltable . value_uncommitted . readable = True
ltable . value_reached . readable = True
#ltable.quantity.label = T("Quantity Requested")
ltable . quantity_committed . readable = True
ltable . quantity_uncommitted . readable = True
ltable . quantity_delivered . readable = True
line = S3SQLInlineComponent ( " need_line " ,
label = " " ,
fields = [ " coarse_location_id " ,
" location_id " ,
" sector_id " ,
( T ( " People affected " ) , " parameter_id " ) ,
" value " ,
" value_committed " ,
( T ( " Number Outstanding " ) , " value_uncommitted " ) ,
" value_reached " ,
( T ( " Item Category " ) , " item_category_id " ) ,
" item_id " ,
( T ( " Unit " ) , " item_pack_id " ) ,
( T ( " Item Quantity " ) , " quantity " ) ,
( T ( " Needed within Timeframe " ) , " timeframe " ) ,
" quantity_committed " ,
( T ( " Quantity Outstanding " ) , " quantity_uncommitted " ) ,
" quantity_delivered " ,
#"comments",
] ,
)
else :
# Create
org_readonly = organisation_id is not None
#need_item = S3SQLInlineComponent("need_item",
# label = T("Items Needed"),
# fields = ["item_category_id",
# "item_id",
# (T("Unit"), "item_pack_id"),
# (T("Needed within Timeframe"), "timeframe"),
# "quantity",
# #(T("Urgency"), "priority"),
# "comments",
# ],
# )
#demographic = S3SQLInlineComponent("need_demographic",
# label = T("People Affected"),
# fields = [(T("Type"), "parameter_id"),
# #(T("Needed within Timeframe"), "timeframe"),
# "value",
# "comments",
# ],
# )
line = S3SQLInlineComponent ( " need_line " ,
label = " " ,
fields = [ " coarse_location_id " ,
" location_id " ,
" sector_id " ,
( T ( " People affected " ) , " parameter_id " ) ,
" value " ,
( T ( " Item Category " ) , " item_category_id " ) ,
" item_id " ,
( T ( " Unit " ) , " item_pack_id " ) ,
" quantity " ,
( T ( " Needed within Timeframe " ) , " timeframe " ) ,
#"comments",
] ,
)
crud_fields = [ S3SQLInlineLink ( " event " ,
field = " event_id " ,
label = T ( " Disaster " ) ,
multiple = False ,
required = True ,
) ,
S3SQLInlineLink ( " organisation " ,
field = " organisation_id " ,
search = False ,
label = T ( " Organization " ) ,
multiple = False ,
readonly = org_readonly ,
required = not org_readonly ,
) ,
" location_id " ,
( T ( " Date entered " ) , " date " ) ,
#(T("Urgency"), "priority"),
# Moved into Lines
#S3SQLInlineLink("sector",
# field = "sector_id",
# search = False,
# label = T("Sector"),
# multiple = False,
# ),
" name " ,
( T ( " Original Request From " ) , " request_from.value " ) ,
( T ( " Issue/cause " ) , " issue.value " ) ,
#demographic,
#need_item,
line ,
S3SQLInlineComponent ( " document " ,
label = T ( " Attachment " ) ,
fields = [ ( " " , " file " ) ] ,
# multiple = True has reliability issues in at least Chrome
multiple = False ,
) ,
( T ( " Verified by government official " ) , " verified.value " ) ,
( T ( " Contact details " ) , " contact.value " ) ,
( T ( " Address for delivery/affected people " ) , " address.value " ) ,
" comments " ,
]
from . controllers import project_ActivityRepresent
natable = s3db . req_need_activity
#f = natable.activity_id
#f.represent = project_ActivityRepresent()
natable . activity_id . represent = project_ActivityRepresent ( )
if not create :
# Read or Update
req_number = components_get ( " req_number " )
req_number . table . value . writable = False
crud_fields . insert ( 2 , ( T ( " Request Number " ) , " req_number.value " ) )
crud_fields . insert ( - 2 , " status " )
need_links = db ( natable . need_id == r . id ) . select ( natable . activity_id )
if need_links :
# This hides the widget from Update forms instead of just rendering read-only!
#f.writable = False
crud_fields . append ( S3SQLInlineLink ( " activity " ,
field = " activity_id " ,
label = T ( " Commits " ) ,
readonly = True ,
) )
crud_form = S3SQLCustomForm ( * crud_fields ,
postprocess = req_need_postprocess )
need_line_summary = URL ( c = " req " , f = " need_line " , args = " summary " )
s3db . configure ( tablename ,
create_next = need_line_summary ,
delete_next = need_line_summary ,
update_next = need_line_summary ,
crud_form = crud_form ,
)
settings . customise_req_need_resource = customise_req_need_resource
# -------------------------------------------------------------------------
def req_need_rheader ( r ) :
"""
Resource Header for Needs
"""
if r . representation != " html " :
# RHeaders only used in interactive views
return None
record = r . record
if not record :
# RHeaders only used in single-record views
return None
if r . name == " need " :
# No Tabs (all done Inline)
tabs = [ ( T ( " Basic Details " ) , None ) ,
#(T("Demographics"), "demographic"),
#(T("Items"), "need_item"),
#(T("Skills"), "need_skill"),
#(T("Tags"), "tag"),
]
from s3 import s3_rheader_tabs
rheader_tabs = s3_rheader_tabs ( r , tabs )
location_id = r . table . location_id
from gluon import DIV , TABLE , TR , TH
rheader = DIV ( TABLE ( TR ( TH ( " %s : " % location_id . label ) ,
location_id . represent ( record . location_id ) ,
) ) ,
rheader_tabs )
else :
# Not defined, probably using wrong rheader
rheader = None
return rheader
# -------------------------------------------------------------------------
def customise_req_need_controller ( * * attr ) :
line_id = current . request . get_vars . get ( " line " )
if line_id :
from gluon import redirect
nltable = current . s3db . req_need_line
line = current . db ( nltable . id == line_id ) . select ( nltable . need_id ,
limitby = ( 0 , 1 )
) . first ( )
if line :
redirect ( URL ( args = [ line . need_id ] ,
vars = { } ) )
# Custom commit method to create an Activity Group from a Need
current . s3db . set_method ( " req " , " need " ,
method = " commit " ,
action = req_need_commit )
s3 = current . response . s3
# Custom postp
standard_postp = s3 . postp
def postp ( r , output ) :
# Call standard postp
if callable ( standard_postp ) :
output = standard_postp ( r , output )
if r . interactive :
# Inject the javascript to handle dropdown filtering
# - normally injected through AddResourceLink, but this isn't there in Inline widget
# - we also need to turn the trigger & target into dicts
s3 . scripts . append ( " / %s /static/themes/SHARE/js/need.js " % r . application )
if r . id and isinstance ( output , dict ) and \
current . auth . s3_has_permission ( " create " , " project_activity " ) :
# Custom Button
from gluon import A
output [ " commit " ] = A ( T ( " Commit " ) ,
_href = URL ( args = [ r . id , " commit " ] ) ,
_class = " action-btn " ,
#_id = "commit-btn",
)
#s3.jquery_ready.append(
#'''S3.confirmClick('#commit-btn','%s')''' % T("Do you want to commit to this need?"))
return output
s3 . postp = postp
attr [ " rheader " ] = req_need_rheader
return attr
settings . customise_req_need_controller = customise_req_need_controller
# -------------------------------------------------------------------------
def homepage_stats_update ( ) :
"""
Scheduler task to update the data files for the charts
on the homepage
"""
from . controllers import HomepageStatistics
HomepageStatistics . update_data ( )
settings . tasks . homepage_stats_update = homepage_stats_update
2020-10-23 19:47:36 +02:00
# -------------------------------------------------------------------------
2020-04-14 14:17:21 +02:00
def req_need_line_update_stats ( r , * * attr ) :
"""
Method to manually update the data files for the charts
on the homepage ; can be run by POSTing an empty request
to req / need_line / update_stats , e . g . via :
< form action = ' {{ =URL(c= " req " , f= " need_line " , args=[ " update_stats " ])}} ' method = ' post ' >
< button type = ' submit ' > { { = T ( " Update Stats " ) } } < / button >
< / form >
( this could e . g . be added to the page footer for ADMINs )
"""
if r . http == " POST " :
if not current . auth . s3_has_role ( " ADMIN " ) :
# No, this is not open for everybody
2020-10-23 19:47:36 +02:00
r . unauthorised ( )
2020-04-14 14:17:21 +02:00
else :
current . s3task . run_async ( " settings_task " ,
args = [ " homepage_stats_update " ] )
current . session . confirmation = T ( " Statistics data update started " )
from gluon import redirect
redirect ( URL ( c = " default " , f = " index " ) )
else :
r . error ( " 405 " , current . ERROR . BAD_METHOD )
# -------------------------------------------------------------------------
def customise_req_need_line_resource ( r , tablename ) :
from gluon import IS_EMPTY_OR , IS_IN_SET , SPAN
from s3 import S3Represent
s3db = current . s3db
current . response . s3 . crud_strings [ " req_need_line " ] [ " title_map " ] = T ( " Map of Needs " )
req_status_opts = { 0 : SPAN ( T ( " Uncommitted " ) ,
_class = " req_status_none " ,
) ,
1 : SPAN ( T ( " Partially Committed " ) ,
_class = " req_status_partial " ,
) ,
2 : SPAN ( T ( " Fully Committed " ) ,
_class = " req_status_committed " ,
) ,
3 : SPAN ( T ( " Complete " ) ,
_class = " req_status_complete " ,
) ,
}
table = s3db . req_need_line
f = table . status
f . requires = IS_EMPTY_OR ( IS_IN_SET ( req_status_opts , zero = None ) )
f . represent = S3Represent ( options = req_status_opts )
f = table . coarse_location_id
f . label = T ( " Division " )
# @ToDo: Option for gis_LocationRepresent which doesn't show level/parent, but supports translation
# NB cannot have the JS in link to avoid being blocked by Chrome XSS_AUDITOR
location_represent = S3Represent ( lookup = " gis_location " )
f . represent = location_represent
f = table . location_id
# @ToDo: Option for gis_LocationRepresent which doesn't show level/parent, but supports translation
f . represent = location_represent
if r . representation == " plain " :
# Settings for Map Popups
f . label = T ( " GN " )
# Custom method to (manually) update homepage statistics
s3db . set_method ( " req " , " need_line " ,
method = " update_stats " ,
action = req_need_line_update_stats ,
)
settings . customise_req_need_line_resource = customise_req_need_line_resource
# -------------------------------------------------------------------------
def customise_req_need_line_controller ( * * attr ) :
from s3 import S3OptionsFilter , S3TextFilter #, S3DateFilter, S3LocationFilter
s3db = current . s3db
settings . base . pdf_orientation = " Landscape "
settings . ui . summary = ( # Gets replaced in postp
# @ToDo: better performance by not including here & placing directly into the view instead
{ " common " : True ,
" name " : " add " ,
" widgets " : [ { " method " : " create " } ] ,
} ,
#{"common": True,
# "name": "cms",
# "widgets": [{"method": "cms"}],
# },
{ " name " : " table " ,
" label " : " Table " ,
" widgets " : [ { " method " : " datatable " } ] ,
} ,
{ " name " : " charts " ,
" label " : " Report " ,
" widgets " : [ { " method " : " report " ,
" ajax_init " : True } ] ,
} ,
#{"name": "map",
# "label": "Map",
# "widgets": [{"method": "map",
# "ajax_init": True}],
# },
)
# Custom Filtered Components
s3db . add_components ( " req_need " ,
req_need_tag = ( # Req Number
{ " name " : " req_number " ,
" joinby " : " need_id " ,
" filterby " : { " tag " : " req_number " ,
} ,
" multiple " : False ,
} ,
# Original Request From
{ " name " : " request_from " ,
" joinby " : " need_id " ,
" filterby " : { " tag " : " request_from " ,
} ,
" multiple " : False ,
} ,
# Verified
{ " name " : " verified " ,
" joinby " : " need_id " ,
" filterby " : { " tag " : " verified " ,
} ,
" multiple " : False ,
} ,
) ,
)
s3db . add_components ( " req_need_response " ,
req_need_response_organisation = ( # Agency
{ " name " : " agency " ,
" joinby " : " need_response_id " ,
" filterby " : { " role " : 1 ,
} ,
#"multiple": False,
} ,
) ,
)
filter_widgets = [ S3TextFilter ( [ " need_id$req_number.value " ,
" item_id$name " ,
# These levels are for SHARE/LK
#"location_id$L1",
" location_id$L2 " ,
#"location_id$L3",
#"location_id$L4",
" need_id$name " ,
" need_id$comments " ,
] ,
label = T ( " Search " ) ,
comment = T ( " Search for a Need by Request Number, Item, Location, Summary or Comments " ) ,
) ,
#S3OptionsFilter("need_id$event.event_type_id",
# #hidden = True,
# ),
# @ToDo: Filter this list dynamically based on Event Type (if-used):
S3OptionsFilter ( " need_id$event__link.event_id " ) ,
#S3LocationFilter("location_id",
# # These levels are for SHARE/LK
# levels = ("L2", "L3", "L4"),
# ),
S3OptionsFilter ( " need_id$location_id " ,
label = T ( " District " ) ,
) ,
S3OptionsFilter ( " need_id$organisation__link.organisation_id " ,
#hidden = True,
) ,
S3OptionsFilter ( " sector_id " ,
#hidden = True,
) ,
S3OptionsFilter ( " parameter_id " ) ,
S3OptionsFilter ( " timeframe " ) ,
S3OptionsFilter ( " item_id " ) ,
S3OptionsFilter ( " status " ,
cols = 3 ,
table = False ,
label = T ( " Status " ) ,
) ,
#S3DateFilter("date",
# ),
#S3OptionsFilter("need_id$verified.value",
# cols = 2,
# label = T("Verified"),
# #hidden = True,
# ),
]
s3db . configure ( " req_need_line " ,
filter_widgets = filter_widgets ,
# We create a custom Create Button to create a Need not a Need Line
listadd = False ,
list_fields = [ ( T ( " Status " ) , " status " ) ,
( T ( " Orgs responding " ) , " need_response_line.need_response_id$agency.organisation_id " ) ,
" need_id$date " ,
( T ( " Need entered by " ) , " need_id$organisation__link.organisation_id " ) ,
( T ( " Original Request From " ) , " need_id$request_from.value " ) ,
# These levels/Labels are for SHARE/LK
#(T("Province"), "need_id$location_id$L1"),
( T ( " District " ) , " need_id$location_id$L2 " ) ,
#(T("DS"), "location_id$L3"),
#(T("GN"), "location_id$L4"),
" sector_id " ,
" parameter_id " ,
" item_id " ,
" quantity " ,
( T ( " Quantity Outstanding " ) , " quantity_uncommitted " ) ,
" timeframe " ,
( T ( " Request Number " ) , " need_id$req_number.value " ) ,
] ,
popup_url = URL ( c = " req " , f = " need " ,
vars = { " line " : " [id] " }
) ,
)
# Custom commit method to create an Activity from a Need Line
s3db . set_method ( " req " , " need_line " ,
method = " commit " ,
action = req_need_line_commit )
s3 = current . response . s3
s3 . crud_strings [ " req_need_line " ] = Storage (
#label_create = T("Add Needs"),
title_list = T ( " Needs " ) ,
#title_display=T("Needs"),
#title_update=T("Edit Needs"),
#title_upload = T("Import Needs"),
#label_list_button = T("List Needs"),
#label_delete_button=T("Delete Needs"),
msg_record_created = T ( " Needs added " ) ,
msg_record_modified = T ( " Needs updated " ) ,
msg_record_deleted = T ( " Needs deleted " ) ,
msg_list_empty = T ( " No Needs currently registered " ) ,
)
# Custom postp
standard_postp = s3 . postp
def postp ( r , output ) :
# Call standard postp
if callable ( standard_postp ) :
output = standard_postp ( r , output )
if r . interactive and r . method == " summary " :
from gluon import A , DIV
from s3 import s3_str #, S3CRUD
auth = current . auth
# Normal Action Buttons
#S3CRUD.action_buttons(r)
# Custom Action Buttons
deletable = current . db ( auth . s3_accessible_query ( " delete " , " req_need_line " ) ) . select ( s3db . req_need_line . id )
restrict_d = [ str ( row . id ) for row in deletable ]
s3 . actions = [ { " label " : s3_str ( T ( " Open " ) ) ,
" _class " : " action-btn " ,
" url " : URL ( f = " need " , vars = { " line " : " [id] " } ) ,
} ,
{ " label " : s3_str ( T ( " Delete " ) ) ,
" _class " : " delete-btn " ,
" url " : URL ( args = [ " [id] " , " delete " ] ) ,
" restrict " : restrict_d ,
} ,
]
if auth . s3_has_permission ( " create " , " req_need_response " ) :
s3 . actions . append ( { " label " : s3_str ( T ( " Commit " ) ) ,
" _class " : " action-btn " ,
" url " : URL ( args = [ " [id] " , " commit " ] ) ,
} )
# Custom Create Button
add_btn = DIV ( DIV ( DIV ( A ( T ( " Add Needs " ) ,
_class = " action-btn " ,
_href = URL ( f = " need " , args = " create " ) ,
) ,
_id = " list-btn-add " ,
) ,
_class = " widget-container with-tabs " ,
) ,
_class = " section-container " ,
)
output [ " common " ] [ 0 ] = add_btn
return output
s3 . postp = postp
return attr
settings . customise_req_need_line_controller = customise_req_need_line_controller
# -------------------------------------------------------------------------
def req_need_response_postprocess ( form ) :
"""
Set the Realm
Ensure that the Need Lines ( if - any ) have the correct Status
"""
db = current . db
s3db = current . s3db
need_response_id = form . vars . id
# Lookup Organisation
nrotable = s3db . req_need_response_organisation
query = ( nrotable . need_response_id == need_response_id ) & \
( nrotable . role == 1 )
org_link = db ( query ) . select ( nrotable . organisation_id ,
limitby = ( 0 , 1 ) ,
) . first ( )
if not org_link :
return
organisation_id = org_link . organisation_id
# Lookup Realm
otable = s3db . org_organisation
org = db ( otable . id == organisation_id ) . select ( otable . pe_id ,
limitby = ( 0 , 1 ) ,
) . first ( )
realm_entity = org . pe_id
# Set Realm
nrtable = s3db . req_need_response
db ( nrtable . id == need_response_id ) . update ( realm_entity = realm_entity )
rltable = s3db . req_need_response_line
db ( rltable . need_response_id == need_response_id ) . update ( realm_entity = realm_entity )
# Lookup the Need Lines
query = ( rltable . need_response_id == need_response_id ) & \
( rltable . deleted == False )
response_lines = db ( query ) . select ( rltable . need_line_id )
for line in response_lines :
need_line_id = line . need_line_id
if need_line_id :
req_need_line_status_update ( need_line_id )
# -------------------------------------------------------------------------
def customise_req_need_response_resource ( r , tablename ) :
from s3 import s3_comments_widget , \
S3LocationDropdownWidget , S3LocationSelector , \
S3Represent , \
S3SQLCustomForm , S3SQLInlineComponent , S3SQLInlineLink
#db = current.db
s3db = current . s3db
table = s3db . req_need_response
current . response . s3 . crud_strings [ tablename ] = Storage (
label_create = T ( " Add Activities " ) ,
title_list = T ( " Activities " ) ,
title_display = T ( " Activities " ) ,
title_update = T ( " Edit Activities " ) ,
title_upload = T ( " Import Activities " ) ,
label_list_button = T ( " List Activities " ) ,
label_delete_button = T ( " Delete Activities " ) ,
msg_record_created = T ( " Activities added " ) ,
msg_record_modified = T ( " Activities updated " ) ,
msg_record_deleted = T ( " Activities deleted " ) ,
msg_list_empty = T ( " No Activities currently registered " ) ,
)
# These levels/labels are for SHARE/LK
table . location_id . widget = S3LocationSelector ( hide_lx = False ,
levels = ( " L1 " , " L2 " ) ,
required_levels = ( " L1 " , " L2 " ) ,
show_map = False )
ltable = s3db . req_need_response_line
f = ltable . coarse_location_id
f . label = T ( " Division " )
# @ToDo: Option for gis_LocationRepresent which doesn't show level/parent, but supports translation
f . represent = S3Represent ( lookup = " gis_location " )
f . widget = S3LocationDropdownWidget ( level = " L3 " , blank = True )
f = ltable . location_id
f . label = T ( " GN " )
# @ToDo: Option for gis_LocationRepresent which doesn't show level/parent, but supports translation
f . represent = S3Represent ( lookup = " gis_location " )
f . widget = S3LocationDropdownWidget ( level = " L4 " , blank = True )
table . comments . comment = None
table . comments . widget = lambda f , v : \
s3_comments_widget ( f , v , _placeholder = " e.g. Items changed/replaced within kits, details on partial committments to a need, any other relevant information. " )
# Custom Filtered Components
s3db . add_components ( tablename ,
req_need_response_organisation = ( # Agency
{ " name " : " agency " ,
" joinby " : " need_response_id " ,
" filterby " : { " role " : 1 ,
} ,
" multiple " : False ,
} ,
# Partners
{ " name " : " partner " ,
" joinby " : " need_response_id " ,
" filterby " : { " role " : 2 ,
} ,
#"multiple": False,
} ,
# Donors
{ " name " : " donor " ,
" joinby " : " need_response_id " ,
" filterby " : { " role " : 3 ,
} ,
#"multiple": False,
} ,
) ,
)
# Individual settings for specific tag components
components_get = s3db . resource ( tablename ) . components . get
donor = components_get ( " donor " )
donor . table . organisation_id . default = None
partner = components_get ( " partner " )
partner . table . organisation_id . default = None
crud_fields = [ S3SQLInlineLink ( " event " ,
field = " event_id " ,
label = T ( " Disaster " ) ,
multiple = False ,
#required = True,
) ,
S3SQLInlineComponent ( " agency " ,
name = " agency " ,
label = T ( " Organization " ) ,
fields = [ ( " " , " organisation_id " ) , ] ,
multiple = False ,
required = True ,
) ,
# @ToDo: MultiSelectWidget is nicer UI but S3SQLInlineLink
# requires the link*ed* table as component (not the
# link table as applied here) and linked components
# cannot currently be filtered by link table fields
# (=> should solve the latter rather than the former)
# @ToDo: Fix Create Popups
S3SQLInlineComponent ( " partner " ,
name = " partner " ,
label = T ( " Implementing Partner " ) ,
fields = [ ( " " , " organisation_id " ) , ] ,
) ,
S3SQLInlineComponent ( " donor " ,
name = " donor " ,
label = T ( " Donor " ) ,
fields = [ ( " " , " organisation_id " ) , ] ,
) ,
" location_id " ,
( T ( " Date entered " ) , " date " ) ,
( T ( " Summary of Needs/Activities " ) , " name " ) ,
S3SQLInlineComponent ( " need_response_line " ,
label = " " ,
fields = [ " coarse_location_id " ,
" location_id " ,
" sector_id " ,
" modality " ,
( T ( " Activity Date Planned " ) , " date " ) ,
( T ( " Activity Date Completed " ) , " end_date " ) ,
( T ( " Beneficiaries (Type) " ) , " parameter_id " ) ,
( T ( " Beneficiaries Planned " ) , " value " ) ,
( T ( " Beneficiaries Reached " ) , " value_reached " ) ,
( T ( " Item Category " ) , " item_category_id " ) ,
" item_id " ,
( T ( " Unit " ) , " item_pack_id " ) ,
( T ( " Quantity Planned " ) , " quantity " ) ,
( T ( " Quantity Delivered " ) , " quantity_delivered " ) ,
( T ( " Activity Status " ) , " status_id " ) ,
#"comments",
] ,
#multiple = False,
) ,
S3SQLInlineComponent ( " document " ,
label = T ( " Attachment " ) ,
fields = [ ( " " , " file " ) ] ,
# multiple = True has reliability issues in at least Chrome
multiple = False ,
) ,
" contact " ,
" address " ,
" comments " ,
]
if r . id and r . resource . tablename == tablename and r . record . need_id :
from . controllers import req_NeedRepresent
f = table . need_id
f . represent = req_NeedRepresent ( )
f . writable = False
crud_fields . insert ( 7 , " need_id " )
# Post-process to update need status for response line changes
crud_form = S3SQLCustomForm ( * crud_fields ,
postprocess = req_need_response_postprocess )
# Make sure need status gets also updated when response lines are deleted
s3db . configure ( " req_need_response_line " ,
ondelete = req_need_response_line_ondelete ,
)
need_response_line_summary = URL ( c = " req " , f = " need_response_line " , args = " summary " )
s3db . configure ( tablename ,
crud_form = crud_form ,
create_next = need_response_line_summary ,
delete_next = need_response_line_summary ,
update_next = need_response_line_summary ,
)
settings . customise_req_need_response_resource = customise_req_need_response_resource
# -------------------------------------------------------------------------
def customise_req_need_response_controller ( * * attr ) :
line_id = current . request . get_vars . get ( " line " )
if line_id :
from gluon import redirect
nltable = current . s3db . req_need_response_line
line = current . db ( nltable . id == line_id ) . select ( nltable . need_response_id ,
limitby = ( 0 , 1 )
) . first ( )
if line :
redirect ( URL ( args = [ line . need_response_id ] ,
vars = { } ) )
s3 = current . response . s3
# Custom postp
standard_postp = s3 . postp
def postp ( r , output ) :
# Call standard postp
if callable ( standard_postp ) :
output = standard_postp ( r , output )
if r . interactive :
# Inject the javascript to handle dropdown filtering
# - normally injected through AddResourceLink, but this isn't there in Inline widget
# - we also need to turn the trigger & target into dicts
s3 . scripts . append ( " / %s /static/themes/SHARE/js/need_response.js " % r . application )
return output
s3 . postp = postp
return attr
settings . customise_req_need_response_controller = customise_req_need_response_controller
# -------------------------------------------------------------------------
def req_need_response_line_ondelete ( row ) :
"""
Ensure that the Need Line ( if - any ) has the correct Status
"""
import json
db = current . db
s3db = current . s3db
response_line_id = row . get ( " id " )
# Lookup the Need Line
rltable = s3db . req_need_response_line
record = db ( rltable . id == response_line_id ) . select ( rltable . deleted_fk ,
limitby = ( 0 , 1 )
) . first ( )
if not record :
return
deleted_fk = json . loads ( record . deleted_fk )
need_line_id = deleted_fk . get ( " need_line_id " )
if not need_line_id :
return
# Check that the Need Line hasn't been deleted
nltable = s3db . req_need_line
need_line = db ( nltable . id == need_line_id ) . select ( nltable . deleted ,
limitby = ( 0 , 1 )
) . first ( )
if need_line and not need_line . deleted :
req_need_line_status_update ( need_line_id )
# -------------------------------------------------------------------------
def customise_req_need_response_line_resource ( r , tablename ) :
from s3 import S3Represent
s3db = current . s3db
table = s3db . req_need_response_line
#current.response.s3.crud_strings["req_need_response_line"] = Storage(title_map = T("Map of Activities"),)
# Settings for Map Popups
f = table . coarse_location_id
f . label = T ( " Division " )
# @ToDo: Option for gis_LocationRepresent which doesn't show level/parent, but supports translation
f . represent = S3Represent ( lookup = " gis_location " )
f = table . location_id
f . label = T ( " GN " )
# @ToDo: Option for gis_LocationRepresent which doesn't show level/parent, but supports translation
f . represent = S3Represent ( lookup = " gis_location " )
s3db . configure ( tablename ,
ondelete = req_need_response_line_ondelete ,
popup_url = URL ( c = " req " , f = " need_response " ,
vars = { " line " : " [id] " }
) ,
report_represent = NeedResponseLineReportRepresent ,
)
settings . customise_req_need_response_line_resource = customise_req_need_response_line_resource
# -------------------------------------------------------------------------
def customise_req_need_response_line_controller ( * * attr ) :
from s3 import S3OptionsFilter #, S3DateFilter, S3LocationFilter, S3TextFilter
s3db = current . s3db
table = s3db . req_need_response_line
settings . base . pdf_orientation = " Landscape "
settings . ui . summary = ( # Gets replaced in postp
# @ToDo: better performance by not including here & placing directly into the view instead
{ " common " : True ,
" name " : " add " ,
" widgets " : [ { " method " : " create " } ] ,
} ,
#{"common": True,
# "name": "cms",
# "widgets": [{"method": "cms"}],
# },
{ " name " : " table " ,
" label " : " Table " ,
" widgets " : [ { " method " : " datatable " } ] ,
} ,
{ " name " : " charts " ,
" label " : " Report " ,
" widgets " : [ { " method " : " report " ,
" ajax_init " : True } ] ,
} ,
#{"name": "map",
# "label": "Map",
# "widgets": [{"method": "map",
# "ajax_init": True}],
# },
)
# Custom Filtered Components
s3db . add_components ( " req_need_response " ,
req_need_response_organisation = ( # Agency
{ " name " : " agency " ,
" joinby " : " need_response_id " ,
" filterby " : { " role " : 1 ,
} ,
#"multiple": False,
} ,
# Partners
{ " name " : " partner " ,
" joinby " : " need_response_id " ,
" filterby " : { " role " : 2 ,
} ,
#"multiple": False,
} ,
# Donors
{ " name " : " donor " ,
" joinby " : " need_response_id " ,
" filterby " : { " role " : 3 ,
} ,
#"multiple": False,
} ,
) ,
)
s3 = current . response . s3
# Custom prep
standard_prep = s3 . prep
def prep ( r ) :
# Call standard prep
if callable ( standard_prep ) :
result = standard_postp ( r )
else :
result = True
filter_widgets = [ S3OptionsFilter ( " need_response_id$agency.organisation_id " ,
label = T ( " Organization " ) ,
) ,
#S3OptionsFilter("need_response_id$event.event_type_id",
# #hidden = True,
# ),
# @ToDo: Filter this list dynamically based on Event Type (if-used):
S3OptionsFilter ( " need_response_id$event__link.event_id " ,
#hidden = True,
) ,
S3OptionsFilter ( " sector_id " ) ,
#S3LocationFilter("location_id",
# label = T("Location"),
# # These levels are for SHARE/LK
# levels = ("L2", "L3", "L4"),
# ),
S3OptionsFilter ( " need_response_id$location_id " ,
label = T ( " District " ) ,
) ,
S3OptionsFilter ( " need_response_id$donor.organisation_id " ,
label = T ( " Donor " ) ,
) ,
S3OptionsFilter ( " need_response_id$partner.organisation_id " ,
label = T ( " Partner " ) ,
) ,
S3OptionsFilter ( " parameter_id " ) ,
S3OptionsFilter ( " item_id " ) ,
#S3OptionsFilter("modality"),
#S3DateFilter("date"),
S3OptionsFilter ( " status_id " ,
cols = 4 ,
label = T ( " Status " ) ,
#hidden = True,
) ,
]
list_fields = [ ( T ( " Organization " ) , " need_response_id$agency.organisation_id " ) ,
( T ( " Implementing Partner " ) , " need_response_id$partner.organisation_id " ) ,
( T ( " Donor " ) , " need_response_id$donor.organisation_id " ) ,
# These levels/labels are for SHARE/LK
#(T("Province"), "need_response_id$location_id$L1"),
( T ( " District " ) , " need_response_id$location_id$L2 " ) ,
" coarse_location_id " ,
" location_id " ,
( T ( " Sector " ) , " sector_id " ) ,
( T ( " Item " ) , " item_id " ) ,
( T ( " Items Planned " ) , " quantity " ) ,
#(T("Items Delivered"), "quantity_delivered"),
( T ( " Modality " ) , " modality " ) ,
( T ( " Beneficiaries Planned " ) , " value " ) ,
( T ( " Beneficiaries Reached " ) , " value_reached " ) ,
( T ( " Activity Date (Planned " ) , " date " ) ,
( T ( " Activity Status " ) , " status_id " ) ,
]
if r . interactive :
s3 . crud_strings [ " req_need_response_line " ] = Storage (
#label_create = T("Add Activity"),
title_list = T ( " Activities " ) ,
#title_display = T("Activity"),
#title_update = T("Edit Activity"),
#title_upload = T("Import Activities"),
#label_list_button = T("List Activities"),
#label_delete_button = T("Delete Activity"),
#msg_record_created = T("Activity added"),
#msg_record_modified = T("Activity updated"),
msg_record_deleted = T ( " Activity deleted " ) ,
msg_list_empty = T ( " No Activities currently registered " ) ,
)
#if r.method == "report":
# # In report drilldown, include the (Location) after quantity_delivered
# # => Needs to be a VF as we can't read the record from within represents
# #table.quantity_delivered.represent =
#
# from s3 import S3Represent, s3_fieldmethod
#
# # @ToDo: Option for gis_LocationRepresent which doesn't show level/parent, but supports translation
# gis_represent = S3Represent(lookup = "gis_location")
#
# def quantity_delivered_w_location(row):
# quantity_delivered = row["req_need_response_line.quantity_delivered"]
# location_id = row["req_need_response_line.location_id"]
# if not location_id:
# location_id = row["req_need_response_line.coarse_location_id"]
# if not location_id:
# location_id = row["req_need_response.location_id"]
# location = gis_represent(location_id)
# return "%s (%s)" % (quantity_delivered, location)
#
# table.quantity_delivered_w_location = s3_fieldmethod("quantity_delivered_w_location",
# quantity_delivered_w_location,
# # over-ride the default represent of s3_unicode to prevent HTML being rendered too early
# #represent = lambda v: v,
# )
# list_fields.insert(9, (T("Items Delivered"), "quantity_delivered_w_location"))
#else:
list_fields . insert ( 9 , ( T ( " Items Delivered " ) , " quantity_delivered " ) )
# Exclude the Disaster column from PDF exports
if r . representation != " pdf " :
list_fields . insert ( 0 , ( T ( " Disaster " ) , " need_response_id$event__link.event_id " ) )
s3db . configure ( " req_need_response_line " ,
filter_widgets = filter_widgets ,
# We create a custom Create Button to create a Need Response not a Need Response Line
listadd = False ,
list_fields = list_fields ,
)
return result
s3 . prep = prep
# Custom postp
standard_postp = s3 . postp
def postp ( r , output ) :
# Call standard postp
if callable ( standard_postp ) :
output = standard_postp ( r , output )
if r . interactive and r . method == " summary " :
from gluon import A , DIV
from s3 import s3_str
#from s3 import S3CRUD, s3_str
# Normal Action Buttons
#S3CRUD.action_buttons(r)
# Custom Action Buttons
auth = current . auth
deletable = current . db ( auth . s3_accessible_query ( " delete " , " req_need_response_line " ) ) . select ( table . id )
restrict_d = [ str ( row . id ) for row in deletable ]
s3 . actions = [ { " label " : s3_str ( T ( " Open " ) ) ,
" _class " : " action-btn " ,
" url " : URL ( f = " need_response " , vars = { " line " : " [id] " } ) ,
} ,
{ " label " : s3_str ( T ( " Delete " ) ) ,
" _class " : " delete-btn " ,
" url " : URL ( args = [ " [id] " , " delete " ] ) ,
" restrict " : restrict_d ,
} ,
]
# Custom Create Button
add_btn = DIV ( DIV ( DIV ( A ( T ( " Add Activity " ) ,
_class = " action-btn " ,
_href = URL ( f = " need_response " , args = " create " ) ,
) ,
_id = " list-btn-add " ,
) ,
_class = " widget-container with-tabs " ,
) ,
_class = " section-container " ,
)
output [ " common " ] [ 0 ] = add_btn
return output
s3 . postp = postp
return attr
settings . customise_req_need_response_line_controller = customise_req_need_response_line_controller
# =============================================================================
class NeedResponseLineReportRepresent ( S3ReportRepresent ) :
"""
Custom representation of need response line records in
pivot table reports :
- show as location name
"""
def __call__ ( self , record_ids ) :
"""
Represent record_ids ( custom )
@param record_ids : req_need_response_line record IDs
@returns : a JSON - serializable dict { recordID : representation }
"""
# Represent the location IDs
resource = current . s3db . resource ( " req_need_response_line " ,
id = record_ids ,
)
rows = resource . select ( [ " id " , " coarse_location_id " , " location_id " ] ,
represent = True ,
raw_data = True ,
limit = None ,
) . rows
output = { }
for row in rows :
raw = row [ " _row " ]
if raw [ " req_need_response_line.location_id " ] :
repr_str = row [ " req_need_response_line.location_id " ]
else :
# Fall back to coarse_location_id if no GN available
repr_str = row [ " req_need_response_line.coarse_location_id " ]
output [ raw [ " req_need_response_line.id " ] ] = repr_str
return output
# END =========================================================================