Merge lp:~graeme-acm/sahana-eden/LA into lp:sahana-eden

Proposed by Graeme Foster
Status: Needs review
Proposed branch: lp:~graeme-acm/sahana-eden/LA
Merge into: lp:sahana-eden
Diff against target: 64092 lines (+23365/-32759) (has conflicts)
228 files modified
VERSION (+3/-1)
clean_la.cmd (+11/-0)
controllers/admin.py (+50/-2)
controllers/default.py (+662/-285)
controllers/don.py (+1041/-0)
controllers/event.py (+11/-1)
controllers/gis.py (+3/-2)
controllers/hrm.py (+224/-0)
controllers/master.py (+22/-0)
controllers/org.py (+123/-0)
controllers/project.py (+5/-7)
controllers/req.py (+23/-11)
controllers/supply.py (+16/-1)
controllers/vol.py (+2389/-176)
deployment-templates/models/000_config.py (+278/-115)
languages/ar.py (+2/-1)
languages/de.py (+135/-1)
languages/el.py (+2/-1)
languages/en-gb.py (+8/-8)
languages/es.py (+789/-6437)
languages/fr.py (+2/-1)
languages/it.py (+2/-1)
languages/ja.py (+770/-5669)
languages/ko.py (+848/-4514)
languages/pt-br.py (+2/-1)
languages/pt.py (+2/-1)
languages/ru.py (+2/-1)
languages/tl.py (+114/-22)
languages/ur.py (+2/-1)
languages/vi.py (+950/-5375)
languages/zh-cn.py (+6/-3)
languages/zh-tw.py (+1418/-5944)
models/00_db.py (+0/-1)
models/00_settings.py (+73/-29)
models/00_tables.py (+41/-61)
models/01_menu.py (+683/-227)
models/02_pr.py (+2/-0)
models/03_gis.py (+0/-1)
models/04_pr.py (+83/-6)
models/05_org.py (+550/-94)
models/06_hrm.py (+116/-11)
models/06_supply.py (+118/-72)
models/08_inv.py (+55/-3)
models/09_project.py (+205/-10)
models/asset.py (+1/-1)
models/doc.py (+1/-1)
models/don.py (+750/-0)
models/event.py (+12/-2)
models/req.py (+2386/-0)
models/vol.py (+1987/-74)
models/zzz_1st_roles.py (+204/-61)
models/zzz_1st_run.py (+85/-184)
modules/s3/codecs/xls.py (+11/-4)
modules/s3/s3aaa.py (+30/-31)
modules/s3/s3cfg.py (+4/-0)
modules/s3/s3pdf.py (+82/-14)
modules/s3/s3rest.py (+236/-0)
modules/s3/s3search.py (+7/-2)
modules/s3/s3tools.py (+99/-232)
modules/s3/s3validators.py (+3/-2)
modules/s3/s3widgets.py (+27/-154)
modules/s3/s3xml.py (+2/-2)
modules/test_utils/setup_request_environment.py (+23/-0)
private/prepopulate/default/California_L2.csv (+59/-0)
private/prepopulate/default/StandardItems.csv (+4/-0)
private/prepopulate/default/USA_L1.csv (+52/-0)
private/prepopulate/default/tasks.cfg (+5/-3)
private/prepopulate/demo/LA/California_L2.csv (+59/-0)
private/prepopulate/demo/LA/LASkillList.csv.OTHER (+62/-0)
private/prepopulate/demo/LA/USA_L1.csv (+52/-0)
private/prepopulate/demo/LA/office.csv (+16/-0)
private/prepopulate/demo/LA/organisation.csv (+8/-0)
private/prepopulate/demo/LA/people.csv (+86/-0)
private/prepopulate/demo/LA/req_req.csv.OTHER (+15/-0)
private/prepopulate/demo/LA/req_skill.csv (+12/-0)
private/prepopulate/demo/LA/sector.csv (+21/-0)
private/prepopulate/demo/LA/tasks.cfg.OTHER (+33/-0)
private/prepopulate/demo/LA/users.csv (+86/-0)
private/prepopulate/demo/LA/vol_application.csv (+41/-0)
private/prepopulate/demo/LA/vol_assignment.csv (+41/-0)
private/prepopulate/regression/office.csv (+4/-0)
static/formats/edrm/export.xsl (+18/-0)
static/formats/edrm/import.xsl (+14/-2)
static/formats/s3csv/hrm/person.xsl (+129/-0)
static/formats/s3csv/org/office.xsl (+226/-0)
static/formats/s3csv/org/officela.xsl (+261/-0)
static/formats/s3csv/org/organisation.xsl (+91/-0)
static/formats/s3csv/org/sector.xsl (+38/-0)
static/formats/s3csv/req/req.xsl (+32/-21)
static/formats/s3csv/req/req_skill.xsl (+70/-0)
static/formats/s3csv/vol/application.xsl (+76/-0)
static/formats/s3csv/vol/assignment.xsl (+74/-0)
static/formats/s3csv/vol/contact.xsl (+75/-0)
static/formats/s3csv/vol/req.xsl (+77/-0)
static/index.html (+81/-0)
static/scripts/S3/S3.js (+1/-1)
static/scripts/S3/S3.min.js (+1/-1)
static/scripts/S3/anytimec.js (+0/-789)
static/scripts/S3/i18n/jquery.dataTables.de.js (+17/-0)
static/scripts/S3/i18n/jquery.dataTables.es.js (+17/-0)
static/scripts/S3/i18n/jquery.dataTables.ja.js (+17/-0)
static/scripts/S3/i18n/jquery.dataTables.ko.js (+17/-0)
static/scripts/S3/i18n/jquery.dataTables.tl.js (+17/-0)
static/scripts/S3/i18n/jquery.dataTables.vn.js (+17/-0)
static/scripts/S3/i18n/jquery.dataTables.zh_TW.js (+17/-0)
static/scripts/S3/jquery.ba-resize.js (+249/-0)
static/scripts/S3/jquery.ba-resize.min.js (+9/-0)
static/scripts/S3/jquery.hoverIntent.js (+106/-0)
static/scripts/S3/jquery.hoverIntent.minified.js (+9/-0)
static/scripts/S3/jquery.pstrength.1.3.js (+7/-5)
static/scripts/S3/jquery.pstrength.1.3.min.js (+1/-1)
static/scripts/S3/s3.dataTables.js (+30/-5)
static/scripts/S3/s3.dataTables.min.js (+111/-110)
static/scripts/S3/s3.select_object.js (+136/-0)
static/scripts/S3/s3.select_person.js (+1/-1)
static/scripts/S3/s3.select_person.min.js (+1/-1)
static/styles/S3/anytime.css (+0/-777)
static/styles/S3/anytimec.css (+0/-44)
static/styles/S3/sahana.css (+994/-836)
static/styles/S3/sahana.min.css (+3/-1)
tests/selenium/language-tests/LanguageFileTests (+16/-0)
tests/selenium/language-tests/donate (+87/-0)
tests/selenium/language-tests/visitor (+281/-0)
tests/selenium/language-tests/volunteer (+496/-0)
tests/selenium/selenium-version (+2/-2)
tests/unit_tests/controllers/hrm.py (+233/-0)
tests/unit_tests/models/01_menu.py (+125/-0)
views/_create.html (+2/-2)
views/_delete.html (+1/-1)
views/_display.html (+2/-2)
views/_list.html (+36/-0)
views/_list_create.html (+3/-3)
views/_merge.html (+2/-2)
views/_ocr_page_upload.html (+1/-1)
views/_ocr_upload.html (+1/-1)
views/_search.html (+2/-2)
views/_update.html (+2/-2)
views/admin/export_data.html (+1/-1)
views/admin/groups.html (+1/-1)
views/admin/import_data.html (+1/-1)
views/admin/index.html (+1/-1)
views/admin/role_edit.html (+1/-1)
views/admin/role_list.html (+1/-1)
views/admin/role_users.html (+1/-1)
views/admin/settings.html (+2/-1)
views/admin/users.html (+1/-1)
views/assess/basic_assess.html (+1/-1)
views/assess/index.html (+1/-1)
views/asset/index.html (+1/-1)
views/auth/_login.html (+1/-1)
views/breadcrumbs.html (+6/-0)
views/budget/budget_staff_bundle_header.html (+1/-1)
views/budget/bundle_kit_item_header.html (+1/-1)
views/budget/kit_item_header.html (+1/-1)
views/building/adminLevel.html (+1/-1)
views/building/index.html (+1/-1)
views/building/report.html (+1/-1)
views/building/timeline.html (+1/-1)
views/cr/index.html (+1/-1)
views/default/about.html (+1/-1)
views/default/contact.html (+7/-17)
views/default/disclaimer.html (+13/-0)
views/default/faq.html (+9/-0)
views/default/help.html (+11/-2)
views/default/index.html (+24/-59)
views/default/register.html (+14/-0)
views/default/sitemap.html (+5/-0)
views/default/user.html (+1/-1)
views/default/why.html (+8/-0)
views/delphi/index.html (+1/-1)
views/don/index.html (+69/-0)
views/dvi/index.html (+1/-1)
views/dvr/index.html (+1/-1)
views/errors/index.html (+1/-1)
views/event/index.html (+1/-1)
views/flood/index.html (+1/-1)
views/footer.html (+15/-7)
views/formats.html (+17/-0)
views/gis/catalogue_toolbar.html (+1/-1)
views/gis/legend.html (+11/-11)
views/gis/location_duplicates.html (+1/-1)
views/gis/location_resolve.html (+1/-1)
views/hrm/index.html (+1/-1)
views/importer/index.html (+1/-1)
views/inner_form.html (+109/-0)
views/inv/index.html (+1/-1)
views/irs/index.html (+1/-1)
views/key.html (+1/-1)
views/l10n.js (+0/-1)
views/layout.html (+66/-87)
views/list_create_ext.html (+1/-1)
views/list_ext.html (+1/-1)
views/master/index.html (+15/-0)
views/mobile/settings_update.html (+1/-1)
views/mpr/index.html (+1/-1)
views/msg/_compose.html (+1/-1)
views/msg/api_settings_update.html (+1/-1)
views/msg/contacts.html (+1/-1)
views/msg/email_settings_update.html (+1/-1)
views/msg/group_user_header.html (+1/-1)
views/msg/index.html (+1/-1)
views/msg/modem_settings_update.html (+1/-1)
views/msg/outbox_create.html (+1/-1)
views/msg/setting_display.html (+1/-1)
views/msg/setting_update.html (+1/-1)
views/msg/sms_to_smtp_settings_update.html (+1/-1)
views/msg/tropo_settings_update.html (+1/-1)
views/org/index.html (+1/-1)
views/patient/index.html (+1/-1)
views/pr/index.html (+1/-1)
views/pr/person_duplicates.html (+1/-1)
views/pr/person_presence_list.html (+1/-1)
views/pr/person_presence_list_create.html (+1/-1)
views/pr/person_resolve.html (+1/-1)
views/project/index.html (+1/-1)
views/project/project_search.html (+1/-1)
views/req/index.html (+2/-2)
views/req/req_assignment_update.html (+33/-0)
views/req/req_item_inv_item.html (+1/-1)
views/scenario/index.html (+1/-1)
views/supply/index.html (+26/-0)
views/survey/index.html (+1/-1)
views/ticket/index.html (+1/-1)
views/vehicle/index.html (+1/-1)
views/vol/index.html (+5/-29)
views/vol/profile.html (+10/-0)
views/vol/register.html (+11/-0)
views/vol/req_assignment_update.html (+32/-0)
Text conflict in VERSION
Text conflict in controllers/default.py
Text conflict in controllers/project.py
Text conflict in controllers/req.py
Text conflict in deployment-templates/models/000_config.py
Text conflict in models/01_menu.py
Text conflict in models/04_pr.py
Text conflict in models/05_org.py
Text conflict in models/06_hrm.py
Text conflict in models/06_supply.py
Text conflict in models/08_inv.py
Text conflict in models/09_project.py
Text conflict in models/req.py
Text conflict in models/vol.py
Text conflict in models/zzz_1st_roles.py
Text conflict in modules/s3/s3rest.py
Conflict adding files to private/prepopulate/demo/LA.  Created directory.
Conflict because private/prepopulate/demo/LA is not versioned, but has versioned children.  Versioned directory.
Contents conflict in private/prepopulate/demo/LA/LASkillList.csv
Contents conflict in private/prepopulate/demo/LA/req_req.csv
Contents conflict in private/prepopulate/demo/LA/tasks.cfg
Text conflict in private/prepopulate/regression/office.csv
Text conflict in static/formats/s3csv/hrm/person.xsl
Text conflict in static/formats/s3csv/org/office.xsl
Text conflict in static/formats/s3csv/org/organisation.xsl
Conflict adding file static/formats/s3csv/org/sector.xsl.  Moved existing file to static/formats/s3csv/org/sector.xsl.moved.
Text conflict in static/styles/S3/sahana.min.css
Text conflict in views/_list.html
Text conflict in views/formats.html
Conflict adding file views/supply.  Moved existing file to views/supply.moved.
To merge this branch: bzr merge lp:~graeme-acm/sahana-eden/LA
Reviewer Review Type Date Requested Status
Fran Boon Pending
Review via email: mp+70544@code.launchpad.net

Description of the change

The demo data for prepopulating for a LA

Probably need to add more data but this gives:

L1 & L2 data (list provided)
Organisations (6)
Offices (15)
users (5)
HRM people (5)
HRM skills (list provided 64)
requests donations 3
request items (6)
requests volunteers 2
request skills (2)

To post a comment you must log in.
lp:~graeme-acm/sahana-eden/LA updated
2360. By graeme-acm

merge la

2361. By graeme-acm

merge la

2362. By graeme-acm

add callback for specific reports, allow for different data sources in the pdf table

2363. By graeme-acm

add raw data mode for pdf tables and some cell styling

2364. By graeme-acm

add vol assignments plus some bug fixes in s3import and appadmin

2365. By graeme-acm

fixed vol assignments

2366. By graeme-acm

merge la

2367. By graeme-acm

volunteer roster report

2368. By graeme-acm

volunteer roster report, and vol application prepop

2369. By graeme-acm

merge la

2370. By graeme-acm

merge la

2371. By graeme-acm

volunteer roster report, and vol application prepop

2372. By graeme-acm

merge la

2373. By graeme-acm

volunteer roster report, and vol application prepop

2374. By graeme-acm

merge la

2375. By graeme-acm

merge la

2376. By graeme-acm

prepopulate fix and some bug fixes

2377. By graeme-acm

vol assignment form

2378. By graeme-acm

merge la, fix importer bug

2379. By graeme-acm

vol assignment form

2380. By graeme-acm

merge la

2381. By graeme-acm

vol assignment form

2382. By graeme-acm

merge la

2383. By graeme-acm

volunteer assignment form

2384. By graeme-acm

merge la

2385. By graeme-acm

merge trunk

2386. By graeme-acm

fixes to prepopulate and some pdf reports

2387. By graeme-acm

make prepopulate flag a simple numerical flag

2388. By graeme-acm

merge trunk

2389. By graeme-acm

fix for dateutils and re_req import

2390. By graeme-acm

merge trunk

2391. By graeme-acm

fix for pre-populate flag in 000_config

2392. By graeme-acm

merge trunk

2393. By graeme-acm

minor bug fix

2394. By graeme-acm

merge trunk

2395. By graeme-acm

merge trunk

2396. By graeme-acm

changes to vol assignment pdf - see logs

2397. By graeme-acm

add volunteer certificate

2398. By graeme-acm

fixed bug in volunteer roster

2399. By graeme-acm

fixed bug set margin and then used margins in volunteer assignment report

2400. By graeme-acm

redo the certificate

2401. By graeme-acm

merge trunk

2402. By graeme-acm

merge trunk

2403. By graeme-acm

vol & don certificates

2404. By graeme-acm

merge trunk

2405. By graeme-acm

donation certificate

2406. By graeme-acm

merge trunk

2407. By graeme-acm

logo in volunteer badge

2408. By graeme-acm

date represent change and vol assignmnet pdf tweak

2409. By graeme-acm

fix date represent for utc

2410. By graeme-acm

various fixes logs 152, 227 & 276

2411. By graeme-acm

various logs.

2412. By graeme-acm

merge trunk

2413. By graeme-acm

fix personal menu to give it maximum space available

2414. By graeme-acm

bug fix when adding donation form button (if no rheader bang)

2415. By graeme-acm

some work on the donation form plus fix to log 298

2416. By graeme-acm

merge trunk

2417. By graeme-acm

donation request from

2418. By graeme-acm

restrict an org to commit vols to the slots available

2419. By graeme-acm

log 306 - Excel colours

2420. By graeme-acm

change prepopulate to use new importer code (actual change rolled back until it works with the demos that we have)

2421. By graeme-acm

added a link for printing of a volunteer certificate

2422. By graeme-acm

breadcrumbs and warnings were overlapping

2423. By graeme-acm

merge trunk - resolve conflict

2424. By graeme-acm

fix emergency contacts on pre-populate

2425. By graeme-acm

merge trunk

2426. By graeme-acm

Update Help add FAQ

2427. By graeme-acm

merge trunk

2428. By graeme-acm

fix string %(descriptors)s

2429. By graeme-acm

merge trunk

2430. By graeme-acm

merge trunk

2431. By graeme-acm

donation certificate

2432. By graeme-acm

donation req signature

2433. By graeme-acm

donation add cert and request button and add signature line for certificate

2434. By graeme-acm

removed comment, confirmation received

2435. By graeme-acm

added on validate to the create org popup

2436. By graeme-acm

merge trunk

2437. By graeme-acm

merge trunk

2438. By graeme-acm

merge trunk

2439. By graeme-acm

merge trunk

2440. By graeme-acm

fix for log 347 vol ass form check in and check out time

2441. By graeme-acm

added selenium scripts used to generate the language file

2442. By graeme-acm

merge trunk

2443. By graeme-acm

minor tweaks to PDF and xls output

Unmerged revisions

2443. By graeme-acm

minor tweaks to PDF and xls output

2442. By graeme-acm

merge trunk

2441. By graeme-acm

added selenium scripts used to generate the language file

2440. By graeme-acm

fix for log 347 vol ass form check in and check out time

2439. By graeme-acm

merge trunk

2438. By graeme-acm

merge trunk

2437. By graeme-acm

merge trunk

2436. By graeme-acm

merge trunk

2435. By graeme-acm

added on validate to the create org popup

2434. By graeme-acm

removed comment, confirmation received

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'VERSION'
--- VERSION 2011-11-17 22:53:42 +0000
+++ VERSION 2011-11-18 07:40:33 +0000
@@ -1,1 +1,3 @@
1r2906 (2011-11-17 22:53:41)
2\ No newline at end of file1\ No newline at end of file
2<<<<<<< TREE
3r2906 (2011-11-17 22:53:41)=======
4r2928 (2011-11-17 09:42:19)>>>>>>> MERGE-SOURCE
35
=== added file 'clean_la.cmd'
--- clean_la.cmd 1970-01-01 00:00:00 +0000
+++ clean_la.cmd 2011-11-18 07:40:33 +0000
@@ -0,0 +1,11 @@
1@echo off
2rem CHOICE Do you want to delete and reinitialise the Sahana Eden Database
3rem if ERRORLEVEL N goto end
4
5rd /Q /S compiled
6
7del databases\*.* /Q
8del errors\*.* /Q
9del sessions\*.* /Q
10python ..\..\web2py.py -S la -M -R applications\la\static\scripts\tools\noop.py
11PAUSE
0\ No newline at end of file12\ No newline at end of file
113
=== modified file 'controllers/admin.py'
--- controllers/admin.py 2011-10-16 02:20:28 +0000
+++ controllers/admin.py 2011-11-18 07:40:33 +0000
@@ -73,6 +73,37 @@
7373
7474
75# -----------------------------------------------------------------------------75# -----------------------------------------------------------------------------
76def register_onaccept(form):
77 """
78 LA-specific:
79 Ensure manually-created users get added to 'Staff' role &
80 have an HRM record created.
81 """
82 # Usual Registration Tasks
83 # (PR record, Authenticated Role, Contacts)
84 person = auth.s3_register(form)
85
86 # LA-specific
87 # Add to 'Staff' role
88 table = db.auth_group
89 STAFF = db(table.uuid == "STAFF").select(table.id,
90 limitby=(0, 1)).first().id
91 table = db.pr_person
92 person_uuid = db(table.id == person).select(table.uuid,
93 limitby=(0, 1)).first().uuid
94 table = db.auth_user
95 query = (table.person_uuid == person_uuid)
96 user = db(query).select(table.id,
97 limitby=(0, 1)).first().id
98 table = db.auth_membership
99 table.insert(user_id = user,
100 group_id = STAFF)
101
102 # Create an HRM record so that the user appears in human_resource_id() lookups
103 table = db.hrm_human_resource
104 table.insert(person_id=person)
105
106# -----------------------------------------------------------------------------
76@auth.s3_requires_membership(1)107@auth.s3_requires_membership(1)
77def user():108def user():
78 """ RESTful CRUD controller """109 """ RESTful CRUD controller """
@@ -84,7 +115,10 @@
84 s3mgr.configure(tablename,115 s3mgr.configure(tablename,
85 main="first_name",116 main="first_name",
86 # Add users to Person Registry & 'Authenticated' role:117 # Add users to Person Registry & 'Authenticated' role:
87 create_onaccept = auth.s3_register)118 create_onaccept = register_onaccept)
119
120 # Staff don't need a Mobile Phone
121 deployment_settings.auth.registration_requests_mobile_phone = False
88122
89 def disable_user(r):123 def disable_user(r):
90 if not r.id:124 if not r.id:
@@ -116,7 +150,7 @@
116 table = auth.settings.table_user150 table = auth.settings.table_user
117 query = (table.id == r.id)151 query = (table.id == r.id)
118 db(query).update(registration_key = "")152 db(query).update(registration_key = "")
119153
120 session.confirmation = T("User Account has been Approved")154 session.confirmation = T("User Account has been Approved")
121 redirect(URL(args=[]))155 redirect(URL(args=[]))
122156
@@ -751,6 +785,20 @@
751 return response.stream(portable_app)785 return response.stream(portable_app)
752786
753# =============================================================================787# =============================================================================
788# LA Code
789# =============================================================================
790@auth.s3_requires_membership(1)
791def rostermail():
792 """
793 Email Addresses for the Volunteer Roster to be sent to
794 """
795
796 return s3_rest_controller("vol", resourcename)
797
798
799
800
801# =============================================================================
754# Deprecated Code below here802# Deprecated Code below here
755# =============================================================================803# =============================================================================
756@auth.s3_requires_membership(1)804@auth.s3_requires_membership(1)
757805
=== modified file 'controllers/default.py'
--- controllers/default.py 2011-11-14 23:42:57 +0000
+++ controllers/default.py 2011-11-18 07:40:33 +0000
@@ -25,6 +25,7 @@
2525
26 return response.download(request, db)26 return response.download(request, db)
2727
28<<<<<<< TREE
28# =============================================================================29# =============================================================================
29def register_validation(form):30def register_validation(form):
30 """ Validate the fields in registration form """31 """ Validate the fields in registration form """
@@ -105,293 +106,17 @@
105 T("This setting can only be controlled by the Administrator.")))106 T("This setting can only be controlled by the Administrator.")))
106107
107# =============================================================================108# =============================================================================
109=======
110# -----------------------------------------------------------------------------
111>>>>>>> MERGE-SOURCE
108def index():112def index():
109 """ Main Home Page """113 """ Main Home Page """
110114
111 title = deployment_settings.get_system_name()115 title = deployment_settings.get_system_name()
112 response.title = title116 response.title = title
113117
114 if deployment_settings.has_module("cr"):118 return dict(title = title)
115 s3mgr.load("cr_shelter")119
116 SHELTERS = s3.crud_strings["cr_shelter"].subtitle_list
117 else:
118 SHELTERS = ""
119
120 # Menu Boxes
121 menu_btns = [#div, label, app, function
122 ["facility", SHELTERS, "cr", "shelter"],
123 ["facility", T("Warehouses"), "inv", "warehouse"],
124 ["facility", T("Hospitals"), "hms", "hospital"],
125 ["facility", T("Offices"), "org", "office"],
126 ["sit", T("Incidents"), "irs", "ireport"],
127 ["sit", T("Assessments"), "assess", "assess"],
128 ["sit", T("Assets"), "asset", "asset"],
129 ["sit", T("Inventory Items"), "inv", "inv_item"],
130 ["dec", T("Gap Map"), "project", "gap_map"],
131 ["dec", T("Gap Report"), "project", "gap_report"],
132 ["dec", T("Requests"), "req", "req"],
133 ["res", T("Projects"), "project", "project"],
134 ["res", T("Activities"), "project", "assess"],
135 ["res", T("Commitments"), "req", "commit"],
136 ["res", T("Sent Shipments"), "inv", "send"],
137 ["res", T("Received Shipments"), "inv", "recv"],
138 ]
139
140 # Change to (Mitigation)/Preparedness/Response/Recovery?
141 menu_divs = {"facility": DIV( H3(T("Facilities")),
142 _id = "facility_box", _class = "menu_box"),
143 "sit": DIV( H3(T("Situation")),
144 _id = "menu_div_sit", _class = "menu_div"),
145 "dec": DIV( H3(T("Decision")),
146 _id = "menu_div_dec", _class = "menu_div"),
147 "res": DIV( H3(T("Response")),
148 _id = "menu_div_res", _class = "menu_div"),
149 }
150
151 for div, label, app, function in menu_btns:
152 if deployment_settings.has_module(app):
153 # @ToDo: Also check permissions (e.g. for anonymous users)
154 menu_divs[div].append(A( DIV(label,
155 _class = "menu-btn-r"),
156 _class = "menu-btn-l",
157 _href = URL(app,function)
158 )
159 )
160
161 div_arrow = DIV(IMG(_src = "/%s/static/img/arrow_blue_right.png" % \
162 request.application),
163 _class = "div_arrow")
164 sit_dec_res_box = DIV(menu_divs["sit"],
165 div_arrow,
166 menu_divs["dec"],
167 div_arrow,
168 menu_divs["res"],
169 _id = "sit_dec_res_box",
170 _class = "menu_box fleft swidth"
171 #div_additional,
172 )
173 facility_box = menu_divs["facility"]
174 facility_box.append( A( IMG(_src = "/%s/static/img/map_icon_128.png" % \
175 request.application),
176 _href = URL(c="gis", f="index"),
177 _title = T("Map")
178 )
179 )
180
181 datatable_ajax_source = ""
182 # Check logged in AND permissions
183 if AUTHENTICATED in session.s3.roles and \
184 auth.s3_has_permission("read", db.org_organisation):
185 org_items = organisation()
186 datatable_ajax_source = "/%s/default/organisation.aaData" % \
187 request.application
188 response.s3.actions = None
189 response.view = "default/index.html"
190 auth.permission.controller = "org"
191 auth.permission.function = "site"
192 permitted_facilities = auth.permission.permitted_facilities(redirect_on_error=False)
193 manage_facility_box = ""
194 if permitted_facilities:
195 facility_list = s3_represent_facilities(db, permitted_facilities,
196 link=False)
197 facility_opts = [OPTION(opt[1], _value = opt[0])
198 for opt in facility_list]
199 if facility_list:
200 manage_facility_box = DIV(H3(T("Manage Your Facilities")),
201 SELECT(_id = "manage_facility_select",
202 _style = "max-width:400px;",
203 *facility_opts
204 ),
205 A(T("Go"),
206 _href = URL(c="default", f="site",
207 args=[facility_list[0][0]]),
208 #_disabled = "disabled",
209 _id = "manage_facility_btn",
210 _class = "action-btn"
211 ),
212 _id = "manage_facility_box",
213 _class = "menu_box fleft")
214 response.s3.jquery_ready.append( """
215$('#manage_facility_select').change(function() {
216 $('#manage_facility_btn').attr('href', S3.Ap.concat('/default/site/', $('#manage_facility_select').val()));
217})""" )
218 else:
219 manage_facility_box = DIV()
220
221 org_box = DIV( H3(T("Organizations")),
222 A(T("Add Organization"),
223 _href = URL(c="org", f="organisation",
224 args=["create"]),
225 _id = "add-btn",
226 _class = "action-btn",
227 _style = "margin-right: 10px;"),
228 org_items["items"],
229 _id = "org_box",
230 _class = "menu_box fleft"
231 )
232 else:
233 manage_facility_box = ""
234 org_box = ""
235
236 # @ToDo: Replace this with an easily-customisable section on the homepage
237 #settings = db(db.s3_setting.id == 1).select(limitby=(0, 1)).first()
238 #if settings:
239 # admin_name = settings.admin_name
240 # admin_email = settings.admin_email
241 # admin_tel = settings.admin_tel
242 #else:
243 # # db empty and prepopulate is false
244 # admin_name = T("Sahana Administrator").xml(),
245 # admin_email = "support@Not Set",
246 # admin_tel = T("Not Set").xml(),
247
248 # Login/Registration forms
249 self_registration = deployment_settings.get_security_self_registration()
250 registered = False
251 login_form = None
252 login_div = None
253 register_form = None
254 register_div = None
255 if AUTHENTICATED not in session.s3.roles:
256 # This user isn't yet logged-in
257 if request.cookies.has_key("registered"):
258 # This browser has logged-in before
259 registered = True
260
261 # Provide a login box on front page
262 request.args = ["login"]
263 auth.messages.submit_button = T("Login")
264 login_form = auth()
265 login_div = DIV(H3(T("Login")),
266 P(XML("%s <b>%s</b> %s" % (T("Registered users can"),
267 T("login"),
268 T("to access the system")))))
269
270 if self_registration:
271 # Provide a Registration box on front page
272 request.args = ["register"]
273 if deployment_settings.get_terms_of_service():
274 auth.messages.submit_button = T("I accept. Create my account.")
275 else:
276 auth.messages.submit_button = T("Register")
277 register_form = auth()
278 register_div = DIV(H3(T("Register")),
279 P(XML("%s <b>%s</b>" % (T("If you would like to help, then please"),
280 T("sign-up now")))))
281
282 # Add client-side validation
283 s3_register_validation()
284
285 if session.s3.debug:
286 response.s3.scripts.append( "%s/jquery.validate.js" % s3_script_dir )
287 else:
288 response.s3.scripts.append( "%s/jquery.validate.min.js" % s3_script_dir )
289 if request.env.request_method == "POST":
290 post_script = """// Unhide register form
291 $('#register_form').removeClass('hide');
292 // Hide login form
293 $('#login_form').addClass('hide');"""
294 else:
295 post_script = ""
296 register_script = """
297 // Change register/login links to avoid page reload, make back button work.
298 $('#register-btn').attr('href', '#register');
299 $('#login-btn').attr('href', '#login');
300 %s
301 // Redirect Register Button to unhide
302 $('#register-btn').click(function() {
303 // Unhide register form
304 $('#register_form').removeClass('hide');
305 // Hide login form
306 $('#login_form').addClass('hide');
307 });
308
309 // Redirect Login Button to unhide
310 $('#login-btn').click(function() {
311 // Hide register form
312 $('#register_form').addClass('hide');
313 // Unhide login form
314 $('#login_form').removeClass('hide');
315 });""" % post_script
316 response.s3.jquery_ready.append(register_script)
317
318 if deployment_settings.frontpage.rss:
319 response.s3.external_stylesheets.append( "http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.css" )
320 response.s3.scripts.append( "http://www.google.com/jsapi?key=notsupplied-wizard" )
321 response.s3.scripts.append( "http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.js" )
322 counter = 0
323 feeds = ""
324 for feed in deployment_settings.frontpage.rss:
325 counter += 1
326 feeds = "".join((feeds,
327 "{title: '%s',\n" % feed["title"],
328 "url: '%s'}" % feed["url"]))
329 # Don't add a trailing comma for old IEs
330 if counter != len(deployment_settings.frontpage.rss):
331 feeds += ",\n"
332 feed_control = "".join(("""
333function LoadDynamicFeedControl() {
334 var feeds = [
335 """, feeds, """
336 ];
337 var options = {
338 // milliseconds before feed is reloaded (5 minutes)
339 feedCycleTime : 300000,
340 numResults : 5,
341 stacked : true,
342 horizontal : false,
343 title : '""", str(T("News")), """'
344 };
345 new GFdynamicFeedControl(feeds, 'feed-control', options);
346}
347// Load the feeds API and set the onload callback.
348google.load('feeds', '1');
349google.setOnLoadCallback(LoadDynamicFeedControl);"""))
350 response.s3.js_global.append( feed_control )
351
352 return dict(title = title,
353
354 sit_dec_res_box = sit_dec_res_box,
355 facility_box = facility_box,
356 manage_facility_box = manage_facility_box,
357 org_box = org_box,
358
359 r = None, # Required for dataTable to work
360 datatable_ajax_source = datatable_ajax_source,
361 #admin_name=admin_name,
362 #admin_email=admin_email,
363 #admin_tel=admin_tel,
364 self_registration=self_registration,
365 registered=registered,
366 login_form=login_form,
367 login_div=login_div,
368 register_form=register_form,
369 register_div=register_div
370 )
371
372# -----------------------------------------------------------------------------
373def organisation():
374 """
375 Function to handle pagination for the org list on the homepage
376 """
377
378 table = db.org_organisation
379 table.id.label = T("Organization")
380 table.id.represent = organisation_represent
381
382 response.s3.dataTable_sPaginationType = "two_button"
383 response.s3.dataTable_sDom = "rtip" #"frtip" - filter broken
384 response.s3.dataTable_iDisplayLength = 25
385
386 s3mgr.configure("org_organisation",
387 listadd = False,
388 addbtn = True,
389 super_entity = db.pr_pentity,
390 linkto = "/%s/org/organisation/%s" % (request.application,
391 "%s"),
392 list_fields = ["id",])
393
394 return s3_rest_controller("org", "organisation")
395# -----------------------------------------------------------------------------120# -----------------------------------------------------------------------------
396def site():121def site():
397 """122 """
@@ -410,7 +135,7 @@
410 args = [id]))135 args = [id]))
411 else:136 else:
412 raise HTTP(404)137 raise HTTP(404)
413138
414# -----------------------------------------------------------------------------139# -----------------------------------------------------------------------------
415def message():140def message():
416 #if "verify_email_sent" in request.args:141 #if "verify_email_sent" in request.args:
@@ -447,12 +172,13 @@
447 _table_user = auth.settings.table_user172 _table_user = auth.settings.table_user
448 if request.args and request.args(0) == "profile":173 if request.args and request.args(0) == "profile":
449 #_table_user.organisation.writable = False174 #_table_user.organisation.writable = False
450 _table_user.utc_offset.readable = True175 #_table_user.utc_offset.readable = True
451 _table_user.utc_offset.writable = True176 #_table_user.utc_offset.writable = True
177 pass
452178
453 login_form = register_form = None179 login_form = register_form = None
454 if request.args and request.args(0) == "login":180 if request.args and request.args(0) == "login":
455 auth.messages.submit_button = T("Login")181 auth.messages.submit_button = T("Sign In")
456 form = auth()182 form = auth()
457 login_form = form183 login_form = form
458 if s3.crud.submit_style:184 if s3.crud.submit_style:
@@ -577,10 +303,25 @@
577 xlwt_version=xlwt_version303 xlwt_version=xlwt_version
578 )304 )
579305
306# =============================================================================
307# LA Custom Views
308# =============================================================================
309def why():
310 """ Custom View """
311 response.title = T("Why?")
312 return dict()
313
314# -----------------------------------------------------------------------------
315def contact():
316 """ Custom View """
317 response.title = T("Contact us")
318 return dict()
319
580# -----------------------------------------------------------------------------320# -----------------------------------------------------------------------------
581def help():321def help():
582 """ Custom View """322 """ Custom View """
583 response.title = T("Help")323 response.title = T("Help")
324<<<<<<< TREE
584 return dict()325 return dict()
585326
586# -----------------------------------------------------------------------------327# -----------------------------------------------------------------------------
@@ -623,5 +364,641 @@
623 response.title = T("Contact us")364 response.title = T("Contact us")
624 return dict()365 return dict()
625366
367=======
368 entries = []
369 question = T("How do I register as a volunteer?")
370 reply = T("Follow these steps, to register:")
371 list = []
372 list.append(T("On the Home Page, click the 'Volunteer' link. Review the 'List of Requests for Volunteers'. To select a %(request)s (Volunteer Task), click on %(apply)s; OR You can register by clicking the 'Register' link located on the top of the web page.") % dict(request="<i>%s</i>" % T("Request for Volunteers"),
373 apply = "<strong>%s</strong>" % T("'APPLY'")))
374 list.append(T("Enter your information into the Required Fields. After you have entered your information, click %(accept)s to register.") % dict(accept="<strong>%s</strong" % T("'I ACCEPT, CREATE MY ACCOUNT'")))
375 entry = (question, reply, list)
376 entries.append(entry)
377 question = T("How do I update my Profile, Skills and Emergency Details?")
378 reply = T("After you are signed-in, please follow these steps to edit your profile: ")
379 list = []
380 list.append(T("On the top menu, click %(volunteer)s.") % dict(volunteer="<strong>%s</strong>" % T("VOLUNTEER")))
381 list.append(T("On the left menu, click %(profile)s .") % dict(profile="<strong>%s</strong>" % T("'My Profile'")))
382 list.append(T("On this page, you can update your profile."))
383 list.append(T("Additional information like %(notifications)s and other volunteer agency affiliations also can be updated in this page.") % dict(notifications="<strong>%s</strong>" % T("Notifications")))
384 list.append(T("Then click %(save)s") % dict(save="<strong>%s</strong>" % T("Save")))
385 list.append(T("On the left menu, click %(skills)s.") % dict(skills="<strong>%s</strong>" % T("Skills")))
386 list.append(T("Click the %s sign next to the skill(s) that best describes how you can support the City.") % "<strong>'+'</strong>")
387 list.append(T("You may also search for a skill by providing the first few characters in the search box. (Example: When searching for 'Driving' skills, enter the first letters of the word)."))
388 list.append(T("If your skill(s) is not listed, you may enter it in the %(extraSkills)s field below.") % dict(extraSkills="<strong>%s</strong>" % T("Skills")))
389 list.append(T("Then click %(save)s") % dict(save="<strong>%s</strong>") % T("Save"))
390 list.append(T("You may also update your Emergency Contacts information by clicking on 'Emergency Contacts' located on the left menu."))
391 list.append(T("Then click %(save)s") % dict(save="<strong>%s</strong>") % T("Save"))
392 entry = (question, reply, list)
393 entries.append(entry)
394 question = T("How do I apply for a Volunteer Request after I have registered with Give2LA?")
395 reply = T("You can apply by clicking the %(signin)s link located on the top of the web page.") % dict(signin="<strong>%s</strong>" % T("'Sign-In'"))
396 list = []
397 list.append(T("Enter your E-Mail and Password information."))
398 list.append(T("Review the 'List of Requests for Volunteers'."))
399 list.append(T("To select a Volunteer Task, click on %(apply)s.") % dict(apply="<strong>%s</strong>") % T("'APPLY'"))
400 list.append(T("Review the 'Volunteer Assignment Details'. Enter your Emergency Contact information."))
401 list.append(T("Download the Give2LA Volunteer Registration Forms, complete the forms, and take them with you to your Volunteer Assignment."))
402 list.append(T("Then click %(commit)s.") % dict(commit="<strong>%s</strong>") % T("Commit"))
403 list.append(T("Review the Volunteer Application details."))
404 list.append(T("Then click %(form)s and take them with you to your Volunteer Assignment.") % dict(form="<strong>%s</strong>" % T("'Print Volunteer Assignment Form'")))
405 entry = (question, reply, list)
406 entries.append(entry)
407 question = T("Can I provide feedback or evaluation for an assignment after volunteering?")
408 reply = T("Yes. After you have signed-in, follow these steps:")
409 list = []
410 list.append(T("On the top menu, click %(volunteer)s.") % dict(volunteer="<strong>%s</strong>") % T("VOLUNTEER"))
411 list.append(T("On the left menu, click %(assignments)s.") % dict(assignments="<strong>%s</strong>") % T("'My Assignments'"))
412 list.append(T("Click on the 'Details' button of the Volunteer Task you have completed."))
413 list.append(T("Scroll down to the bottom of the screen to get to 'Evaluation of Event'."))
414 list.append(T("Enter the evaluation details; and click %(save)s") % dict(save="<strong>%s</strong>") % T("Save"))
415 entry = (question, reply, list)
416 entries.append(entry)
417 question = T("I would like to register my corporation for donations, what is the process?")
418 reply = T("Follow these steps, to register")
419 list = []
420 list.append(T("Locate the %(register)s for Corporations and Organizations on the Home Page and click on it.") % dict(register="<strong>%s</strong>" % T("'CLICK HERE TO REGISTER'")))
421 list.append(T("Enter the Mandatory details and click on the button %(accept)s at the bottom of the screen to register") % dict(accept="<strong>%s</strong" % T("'I ACCEPT, CREATE MY ACCOUNT'")))
422 entry = (question, reply, list)
423 entries.append(entry)
424
425 return dict(entries=entries)
426
427# -----------------------------------------------------------------------------
428def faq():
429 """ Custom View """
430 donateLink = A(T("Donate Page"), _href=URL(c="don", f="index"))
431
432 response.title = T("Frequently Asked Questions")
433 entries = []
434 question = T("Is there a minimum age limit to volunteer?")
435 reply = T("Yes, you have to be at least 18 years of age to Volunteer.")
436 entry = (question, reply)
437 entries.append(entry)
438 question = T("What is the Privacy policy of Give2LA?")
439 reply = T("Please refer to the %(privacy)s") % dict(privacy=A(T("Privacy Policy"),
440 _href=URL(c="default", f="disclaimer")))
441 entry = (question, reply)
442 entries.append(entry)
443 question = T("Can I bring a friend to volunteer?")
444 reply = T("Yes, but your friend must also %(register)s and apply to the same Volunteer Assignment.") % dict(register=A(T("Register"),
445 _href=URL(c="vol", f="register")))
446 entry = (question, reply)
447 entries.append(entry)
448 question = T("Will I get any food or reimbursements for expenses while volunteering?")
449 reply = T("No, unless it is otherwise stated on the Volunteer Assignment.")
450 entry = (question, reply)
451 entries.append(entry)
452 question = T("Can I donate cash to support the City of Los Angeles?")
453 reply = T("Yes, you can donate cash to the %(laepf)s who support the City of Los Angeles or other partner organizations listed on the %(donate)s. These links will take you directly to the organization's website to complete the cash donation transaction.") % dict(laepf="<a href=http://laemergencypreparednessfoundation.org/>LAEPF</a>", donate=donateLink)
454 entry = (question, reply)
455 entries.append(entry)
456 question = T("What is the process for donating in-kind Items?")
457 reply = T("The City of Los Angeles prefers cash donations. In-kind items can be donated directly to the organization(s) listed under Donate Items or through any Upcoming Donation Drive on the %(donate)s") % dict(donate=donateLink)
458 entry = (question, reply)
459 entries.append(entry)
460 question = T("Do I have to be a U.S. citizen or legal U.S. resident to volunteer?")
461 reply = T("Yes. You must be a U.S. citizen, legal U.S. resident, or have gained legal entry into the United States.")
462 entry = (question, reply)
463 entries.append(entry)
464 question = T("Do I have to live in the City of Los Angeles to volunteer?")
465 reply = T("No, anyone may register to support the City of Los Angeles' volunteer efforts.")
466 entry = (question, reply)
467 entries.append(entry)
468 question = T("Is my donation tax deductible?")
469 reply = T("Yes. All donations are tax deductible. The partner organization that receives your donation will provide a receipt for your donation. Please make sure you obtain your tax receipt from the organization and keep it in a safe place for tax purposes. The City of Los Angeles will not issue receipts for your donation.")
470 entry = (question, reply)
471 entries.append(entry)
472
473 return dict(entries=entries)
474
475# -----------------------------------------------------------------------------
476def sitemap():
477 """ Custom View """
478 response.title = T("Site Map")
479 return dict()
480
481# -----------------------------------------------------------------------------
482def disclaimer():
483 """ Custom View """
484 response.title = T("Disclaimer")
485 return dict()
486
487# -----------------------------------------------------------------------------
488def register():
489 """
490 Registration for Organisations
491 - custom form
492 """
493
494 # Which type of organisation are we registering?
495 don = False
496 vol = False
497 if "type" in request.vars:
498 if request.vars.type == "don":
499 don = True
500 elif request.vars.type == "vol":
501 vol = True
502 auth.settings.registration_requires_approval = True
503
504 auth.messages.submit_button = T("I accept. Create my account.")
505 request.args = ["register"]
506 _table_user.language.default = T.accepted_language
507 _table_user.language.readable = False
508 _table_user.language.writable = False
509 form = auth()
510 form.attributes["_id"] = "regform"
511 # Custom class for Submit Button
512 form[0][-1][0][0]["_class"] = "accept-button"
513
514 # Cancel button
515 form[0][-1][0].append(BR())
516 #form[0][-1][1].append(INPUT(_type="reset", _value=T("Cancel")))
517 form[0][-1][0].append(INPUT(_type="button",
518 _value=T("Cancel"),
519 _class="wide-grey-button",
520 _onClick="javascript: history.go(-1)"))
521
522 formstyle = s3.crud.formstyle
523
524 # Organisation
525 if form.errors.organisation:
526 organisation_error = DIV(form.errors.organisation,
527 _id="organisation__error",
528 _class="error",
529 _style="display: block;")
530 else:
531 organisation_error = ""
532 if don:
533 label = T("Corporation/Organization Name")
534 else:
535 label = T("Organization Name")
536 row = formstyle(id = "organisation",
537 label = LABEL("%s:" % label,
538 SPAN(" *", _class="req")),
539 widget = DIV(INPUT(_name="organisation",
540 _id="organisation",
541 _class="string"),
542 organisation_error),
543 comment = "")
544 form[0].insert(0, row)
545
546 # Industry Sector
547 if vol:
548 hidden = True
549 widget = INPUT(_name="sector_id",
550 _id="sector_id",
551 _class="string")
552 else:
553 from gluon.sqlhtml import OptionsWidget
554 hidden = False
555 widget = OptionsWidget.widget(db.org_organisation.sector_id,
556 value="")
557 # dropdown
558 row = formstyle(id = "sector_id",
559 label = LABEL("%s:" % T("Industry Sector")),
560 widget = widget,
561 comment = "",
562 hidden = hidden)
563 form[0].insert(1, row)
564 # freetext box for not listed
565 row = formstyle(id = "sector_other",
566 label = LABEL("%s:" % T("Other Sector not listed")),
567 widget = INPUT(_name="sector_other",
568 _id="sector_other",
569 _class="string"),
570 comment = "",
571 hidden = hidden)
572 form[0].insert(2, row)
573
574
575 # Primary Contact Person section
576 row = TR(TD(LABEL(T("Primary Contact")),
577 _colspan="3",
578 _class="subheading"))
579 form[0][2].append(row)
580 row = formstyle(id = "middle_name",
581 label = LABEL("%s:" % T("Middle Name")),
582 widget = INPUT(_name="middle_name",
583 _id="middle_name",
584 _class="string"),
585 comment = "")
586 form[0][4].append(row)
587
588 row = formstyle(id = "secondary_email",
589 label = LABEL("%s:" % T("Secondary Email")),
590 widget = INPUT(_name="secondary_email",
591 _id="secondary_email",
592 _class="string"),
593 comment = "")
594 form[0][12].append(row)
595
596 # What are you offering?
597 if don or vol:
598 hidden = True
599 else:
600 hidden = False
601 row = formstyle(id = "offer",
602 hidden = hidden,
603 label = LABEL("%s:" % T("We can offer"),
604 SPAN(" *", _class="req")),
605 widget = (T("Items"),
606 INPUT(_type="checkbox",
607 _value="on",
608 value="on" if don else "",
609 _name="has_items",
610 _id="has_items",
611 _class="boolean"),
612 T("Volunteers"),
613 INPUT(_type="checkbox",
614 _value="on",
615 value="on" if vol else "",
616 _name="vols",
617 _id="vols",
618 _class="boolean"),
619 ),
620 comment = "")
621 form[0][12].append(row)
622
623 # Phone
624 mobile_phone_widget = INPUT(_name="mobile_phone",
625 _id="",
626 _class="string")
627 if form.errors.mobile_phone:
628 mobile_phone_error = DIV(form.errors.mobile_phone,
629 _id="mobile_phone__error",
630 _class="error",
631 _style="display: block;")
632 # Can't wrap widget in a DIV for client-side validation, so only do so
633 # when server-side validation happens
634 mobile_phone_widget = DIV(mobile_phone_widget,
635 mobile_phone_error)
636
637 if form.errors.work_phone:
638 work_phone_error = DIV(form.errors.work_phone,
639 _id="work_phone__error",
640 _class="error",
641 _style="display: block;")
642 else:
643 work_phone_error = ""
644 row = formstyle(id = "phone",
645 label = LABEL("%s:" % T("Work Phone")),
646 widget = DIV(INPUT(_name="work_phone",
647 _id="",
648 _class="string"),
649 work_phone_error),
650 comment = "")
651 form[0][12].append(row)
652 row = formstyle(id = "phone",
653 label = LABEL("%s:" % current.deployment_settings.get_ui_label_mobile_phone(),
654 SPAN(" *", _class="req")),
655 widget = mobile_phone_widget,
656 comment = "")
657 form[0][12].append(row)
658
659 # Address
660 row = TR(TD(LABEL(T("Corporation/Organization Address")),
661 _colspan="3",
662 _class="subheading"))
663 form[0][12].append(row)
664 if form.errors.address1:
665 address1_error = DIV(form.errors.address1,
666 _id="address1__error",
667 _class="error",
668 _style="display: block;")
669 else:
670 address1_error = ""
671 row = formstyle(id = "address1",
672 label = LABEL("%s:" % T("Address 1"),
673 SPAN(" *", _class="req")
674 ),
675 widget = (INPUT(_name="address1",
676 _id="address1",
677 _class="string"),
678 address1_error),
679 comment = "")
680 form[0][12].append(row)
681 row = formstyle(id = "address2",
682 label = LABEL("%s:" % T("Address 2")),
683 widget = INPUT(_name="address2",
684 _id="address2",
685 _class="string"),
686 comment = "")
687 form[0][12].append(row)
688 row = formstyle(id = "city",
689 label = LABEL("%s:" % T("City"),
690 SPAN(" *", _class="req")),
691 widget = INPUT(_name="city",
692 _id = "city",
693 _class = "string"),
694 comment = "")
695 form[0][12].append(row)
696 states = S3LocationDropdownWidget(level="L1",
697 default="California",
698 empty=False)
699 widget = states(db.pr_address.location_id, None)
700 row = formstyle(id = "state",
701 label = LABEL("%s:" % T("State"),
702 SPAN(" *", _class="req")),
703 widget = widget,
704 comment = "")
705 form[0][12].append(row)
706 if form.errors.zip:
707 zip_error = DIV(form.errors.zip,
708 _id="zip__error",
709 _class="error",
710 _style="display: block;")
711 else:
712 zip_error = ""
713 row = formstyle(id = "zip",
714 label = LABEL("%s:" % T("Zip"),
715 SPAN(" *", _class="req")
716 ),
717 widget = ( INPUT(_name="zip",
718 _id="zip",
719 _class="string"),
720 zip_error
721 ),
722 comment = "")
723 form[0][12].append(row)
724
725
726 #form[0][-2].append(TR(TD(LABEL(T("Terms of Service:"),
727 # _id="terms_of_service__label"),
728 # _class="w2p_fl"),
729 # TD(LABEL(TEXTAREA(deployment_settings.get_terms_of_service(),
730 # _onfocus="this.rows=10",
731 # _readonly="readonly",
732 # _style="width:100%;text-align:",
733 # _cols="80", _rows="10"),
734 # _id="terms_of_service"),
735 # _class="w2p_fw",
736 # _colspan="2"),
737 # _id="terms_of_service__row"))
738
739 # Add client-side validation
740 # simplified copy of s3_register_validation()
741 script = "".join(( """
742var required = '""", str(T("This field is required.")), """';
743$('#regform').validate({
744 errorClass: 'req',
745 rules: {
746 first_name: {
747 required: true
748 },
749 last_name: {
750 required: true
751 },
752 email: {
753 required: true,
754 email: true
755 },
756 organisation: {
757 required: true
758 },
759 mobile_phone: {
760 required: true
761 },
762 address1: {
763 required: true
764 },
765 city: {
766 required: true
767 },
768 zip: {
769 required: true
770 },
771 password: {
772 required: true
773 },
774 password_two: {
775 required: true,
776 equalTo: '.password:first'
777 }
778 },
779 messages: {
780 first_name: '""", str(T("Enter your firstname")), """',
781 last_name: required,
782 email: {
783 required: '""", str(T("Please enter a valid email address")), """',
784 minlength: '""", str(T("Please enter a valid email address")), """'
785 },
786 mobile_phone: required,
787 address1: required,
788 city: required,
789 zip: required,
790 password: {
791 required: '""", str(T("Provide a password")), """'
792 },
793 password_two: {
794 required: '""", str(T("Repeat your password")), """',
795 equalTo: '""", str(T("Enter the same password as above")), """'
796 }
797 },
798 errorPlacement: function(error, element) {
799 error.appendTo( element.parent().next() );
800 },
801 submitHandler: function(form) {
802 form.submit();
803 }
804});""" ))
805 response.s3.jquery_ready.append( script )
806
807 if session.s3.debug:
808 response.s3.scripts.append( "%s/jquery.validate.js" % s3_script_dir )
809 response.s3.scripts.append( "%s/jquery.pstrength.1.3.js" % s3_script_dir )
810 else:
811 response.s3.scripts.append( "%s/jquery.validate.min.js" % s3_script_dir )
812 response.s3.scripts.append( "%s/jquery.pstrength.1.3.min.js" % s3_script_dir )
813
814 response.s3.jquery_ready.append("$('.password:first').pstrength();\n")
815 response.s3.js_global.append("".join((
816 "S3.i18n.password_chars = '%s';\n" % T("The minimum number of characters is "),
817 "S3.i18n.very_weak = '%s';\n" % T("Very Weak"),
818 "S3.i18n.weak = '%s';\n" % T("Weak"),
819 "S3.i18n.medium = '%s';\n" % T("Medium"),
820 "S3.i18n.strong = '%s';\n" % T("Strong"),
821 "S3.i18n.very_strong = '%s';\n" % T("Very Strong"),
822 "S3.i18n.too_short = '%s';\n" % T("Too Short"),
823 "S3.i18n.unsafe_password = '%s';\n" % T("Unsafe Password Word!"),
824 )))
825
826 response.title = T("Register")
827 response.s3.has_required = True
828
829 return dict(form=form)
830
831# -----------------------------------------------------------------------------
832def register_validation(form):
833 """ Validate the custom fields in registration form """
834 # Name
835 if "organisation" in request.post_vars and request.post_vars.organisation:
836 # Check not in use
837 table = db.org_organisation
838 query = (table.name == request.post_vars.organisation)
839 name = db(query).select(table.id, limitby=(0, 1)).first()
840 if name:
841 form.errors.organisation = T("Organisation Name is already in use")
842 else:
843 form.errors.organisation = T("Organisation Name is required")
844 # Phone
845 if "work_phone" in request.post_vars and request.post_vars.work_phone:
846 regex = re.compile(single_phone_number_pattern)
847 if not regex.match(request.post_vars.work_phone):
848 form.errors.work_phone = T("Invalid phone number")
849 if "mobile_phone" in request.post_vars and request.post_vars.mobile_phone:
850 regex = re.compile(single_phone_number_pattern)
851 if not regex.match(request.post_vars.mobile_phone):
852 form.errors.mobile_phone = T("Invalid phone number")
853 else:
854 form.errors.mobile_phone = T("Phone number is required")
855 # Address
856 if not request.post_vars.address1:
857 form.errors.address1 = T("Address is required")
858 if not request.post_vars.city:
859 form.errors.city = T("City is required")
860 if not request.post_vars.zip:
861 form.errors.zip = T("Zip is required")
862
863 return
864
865# -----------------------------------------------------------------------------
866def register_onaccept(form):
867 # Usual Registration Tasks
868 # (PR record, Authenticated Role, Contacts)
869 person = auth.s3_register(form)
870
871 # LA-specific
872 ptable = db.pr_person
873 query = (ptable.id == person)
874
875 db(query).update(middle_name=request.post_vars.middle_name)
876
877 pe = db(query).select(ptable.pe_id,
878 limitby=(0, 1)).first().pe_id
879
880 # Organisation
881 organisation = request.post_vars.organisation
882 if "vols" in request.post_vars and request.post_vars.vols == "on":
883 has_vols = True
884 else:
885 has_vols = False
886 if "has_items" in request.post_vars and request.post_vars.has_items == "on":
887 has_items = True
888 else:
889 has_items = False
890
891 # Phone
892 table = db.pr_contact
893 work_phone = request.post_vars.work_phone
894 mobile_phone = request.post_vars.mobile_phone
895 if mobile_phone:
896 # Don't auto-subscribe to SMS (priority 10)
897 table.insert(pe_id = pe,
898 contact_method = "SMS",
899 value = mobile_phone,
900 priority=10)
901 if work_phone:
902 table.insert(pe_id = pe,
903 contact_method = "WORK_PHONE",
904 value = work_phone)
905
906 # Address
907 address1 = request.post_vars.address1
908 address2 = request.post_vars.address2
909 #if address2:
910 # address = "%s\n%s" % (address1,
911 # address2)
912 #else:
913 # address = address1
914 city = request.post_vars.city
915 state = request.post_vars.location_id
916 zip = request.post_vars.zip
917 if request.post_vars.sector_other:
918 sector_other = "Sector: %s" % request.post_vars.sector_other
919 else:
920 sector_other = ""
921 otable = db.org_organisation
922 org = otable.insert(name = organisation,
923 has_vols = has_vols,
924 has_items = has_items,
925 #phone=phone,
926 address=address1,
927 address_2=address2,
928 L3=city,
929 L1=state,
930 postcode=zip,
931 sector_id=request.post_vars.sector_id,
932 comments=sector_other)
933 record = Storage(id=org)
934 s3mgr.model.update_super(otable, record)
935 auth.s3_set_record_owner(otable, org)
936 # For OrgDons which don't require approval
937 if auth.user:
938 # Update the session
939 auth.user.organisation_id = org
940 user_id = auth.user.id
941 else:
942 user_id = form.vars.id
943
944 # Create HRM
945 table = db.hrm_human_resource
946 hrm = table.insert(person_id = person,
947 organisation_id = org,
948 focal_point = True,
949 owned_by_user = user_id)
950 record = Storage(id=hrm)
951 s3mgr.model.update_super(table, record)
952 auth.s3_set_record_owner(table, hrm)
953
954 # Set the Roles
955 person = db(query).select(ptable.uuid,
956 limitby=(0, 1)).first()
957 if not person:
958 # Error
959 return
960 utable = db[auth.settings.table_user]
961 query = (utable.person_uuid == person.uuid)
962 db(query).update(organisation_id = org)
963 user = db(query).select(utable.id,
964 limitby=(0, 1)).first()
965 if not user:
966 # Error
967 return
968 mtable = db[auth.settings.table_membership]
969 gtable = db[auth.settings.table_group]
970 _org = db(otable.id == org).select(otable.owned_by_organisation,
971 limitby=(0, 1)).first()
972 if _org:
973 mtable.insert(user_id = user.id,
974 group_id = _org.owned_by_organisation)
975
976 if has_vols:
977 OrgVol = db(gtable.uuid == ORG_VOL).select(gtable.id,
978 limitby=(0, 1)).first()
979 if OrgVol:
980 mtable.insert(user_id = user.id,
981 group_id = OrgVol.id)
982 # Go to the Contacts page so that a secondary contact can be added
983 # Flag that we've come from registration for subsequent workflow
984 #redirect(URL(c="vol", f="organisation", args=[org, "human_resource"],
985 # vars={"register":1}))
986
987 if has_items:
988 OrgDon = db(gtable.uuid == ORG_DON).select(gtable.id,
989 limitby=(0, 1)).first()
990 if OrgDon:
991 mtable.insert(user_id = user.id,
992 group_id = OrgDon.id)
993 # Go to the Contacts page so that a secondary contact can be added
994 # Flag that we've come from registration for subsequent workflow
995 redirect(URL(c="don", f="organisation", args=[org, "human_resource"],
996 vars={"register":1}))
997
998# -----------------------------------------------------------------------------
999#auth.settings.registration_requires_approval = True
1000auth.settings.register_onvalidation = register_validation
1001auth.settings.register_onaccept = register_onaccept
1002>>>>>>> MERGE-SOURCE
6261003
627# END =========================================================================1004# END =========================================================================
6281005
=== added file 'controllers/don.py'
--- controllers/don.py 1970-01-01 00:00:00 +0000
+++ controllers/don.py 2011-11-18 07:40:33 +0000
@@ -0,0 +1,1041 @@
1# -*- coding: utf-8 -*-
2
3"""
4 Donations (LA Specific)
5
6 @author: Michael Howden (michael@sahanafoundation.org)
7 @date-created: 2011-08-02
8"""
9
10
11module = request.controller
12resourcename = request.function
13
14if not deployment_settings.has_module(module):
15 raise HTTP(404, body="Module disabled: %s" % module)
16
17# Options Menu (available in all Functions)
18shn_menu(module)
19
20# Load Models
21s3mgr.load("don_collect")
22# -----------------------------------------------------------------------------
23def index():
24 """ Custom View """
25 if s3_has_role(STAFF) or s3_has_role(BOC):
26 redirect(URL(f="req"))
27 else:
28 response.menu_options = []
29 if session.s3.debug:
30 response.s3.scripts.append( "%s/jquery.hoverIntent.js" % s3_script_dir )
31 else:
32 response.s3.scripts.append( "%s/jquery.hoverIntent.minified.js" % s3_script_dir )
33
34 response.title = T("Donate")
35 response.s3.jquery_ready.append("""
36 $(".donate-popup").css("display", "none");
37 $(".organizations-list li a").hoverIntent(donateFadeIn, donateFadeOut);
38 """)
39 response.s3.js_global.append("""
40 function donateFadeIn(){$(this).next(".donate-popup").fadeIn();}
41 function donateFadeOut(){$(this).next(".donate-popup").fadeOut();}
42 """)
43
44 # Get Donation Drives List
45 table = db.don_collect
46 query = ( ( table.end_datetime > request.utcnow ) &
47 ( table.deleted == False )
48 )
49 rows = db(query).select( table.start_datetime,
50 table.end_datetime,
51 table.site_id,
52 orderby = table.start_datetime
53 )
54 if rows:
55 list = []
56 offset = IS_UTC_OFFSET.get_offset_value(session.s3.utc_offset)
57 for row in rows:
58 if offset:
59 start_datetime = row.start_datetime + datetime.timedelta(seconds=offset)
60 end_datetime = row.end_datetime + datetime.timedelta(seconds=offset)
61
62 start_date = start_datetime.strftime("%b %d")
63 start_time = start_datetime.strftime("%I:%M %p")
64 end_date = end_datetime.strftime("%b %d")
65 end_time = end_datetime.strftime("%I:%M %p")
66
67 site = shn_site_represent(row.site_id, address = True)
68
69 if start_date == end_date:
70 list.append( LI( SPAN( start_date, _class = "date"),
71 " %s - %s" % (start_time, end_time),
72 site,
73 BR()
74 )
75 )
76 else:
77 list.append( LI( SPAN( start_date, _class = "date" ),
78 " %s - " % start_time,
79 SPAN( end_date, _class = "date" ),
80 " %s" % end_time,
81 site,
82 BR()
83 )
84 )
85 donation_drives = TAG[""](*list)
86 else:
87 donation_drives = P(T("No Donation Drives Scheduled. Please check back later"))
88
89 return dict(donation_drives = donation_drives)
90
91# -----------------------------------------------------------------------------
92def don_organisation_represent(id):
93 if isinstance(id, Row):
94 # Do not repeat the lookup if already done by IS_ONE_OF or RHeader
95 org = id
96 else:
97 table = db.org_organisation
98 query = (table.id == id)
99 org = db(query).select(table.name,
100 limitby = (0, 1)).first()
101 if org:
102 return A(org.name,
103 _href = URL(c="don", f="organisation", args = [id]))
104 else:
105 return NONE
106
107# -----------------------------------------------------------------------------
108def match():
109 # Get Req Resource Details
110 tablename, req_id = request.vars.viewing.split(".")
111
112 # create fake resource for rheader
113 s3mgr.load("req_req")
114 req = db(db.req_req.id == req_id).select(limitby = (0, 1)).first()
115 r = Storage()
116 r.record = req
117 r.representation = "html"
118 r.name = "don"
119 r.function = "match"
120 r.vars = request.vars
121 rheader = req_rheader(r)
122
123 # Get Item Filter
124 req_item = db(db.req_req_item.req_id == req_id).select(db.req_req_item.item_id,
125 limitby = [0,1]
126 ).first()
127 if req_item:
128 item_id = req_item.item_id
129 else:
130 item_id = None
131 response.s3.filter = (db.don_don_item.item_id == item_id)
132
133 # Configure don_don_item list
134 db.don_don_item.organisation_id.represent = don_organisation_represent
135 s3mgr.configure("don_don_item",
136 insertable = False,
137 list_fields = ["id",
138 "organisation_id",
139 "item_id",
140 "quantity",
141 "type",
142 "comments"]
143 )
144 response.s3.actions = [dict(url = URL(c="don", f="req",
145 args = [req_id, "commit"],
146 vars = dict(don_item_id = "[id]")
147 ),
148 _class = "action-btn",
149 label = str(T("Select")),
150 )
151 ]
152
153 output = don_item()
154
155 # Customize form
156 output["rheader"] = rheader
157 output["title"] = T("Request for Donations Details")
158 output["subtitle"] = T("Matching Resources in Virtual Donation Inventory")
159
160 return output
161# -----------------------------------------------------------------------------
162def req_summary(r):
163 rtable = db.req_req
164 itable = db.req_req_item
165 ctable = db.req_commit
166 req = r.record
167 item = req.req_req_item.select().first() or Storage()
168 commit = req.req_commit.select().first() or Storage()
169
170 item_str = response.s3.concat_item_pack_quantity( item.item,
171 item.item_pack,
172 item.quantity)
173
174 summary = TABLE( TR( TH( rtable.status.label ),
175 rtable.status.represent(req.status),
176 TH( ctable.status.label ),
177 ctable.status.represent(commit.status),
178 ),
179 #TR( TH( rtable.event_id.label ),
180 # rtable.event_id.represent(req.event_id),
181 # TH( rtable.incident_id.label ),
182 # rtable.incident_id.represent(req.incident_id),
183 # ),
184 TR( TH( rtable.request_number.label ),
185 req.request_number,
186 TH( rtable.priority.label ),
187 rtable.priority.represent( req.priority ),
188 ),
189 TR( TH( rtable.date_required.label ),
190 req.date_required,
191 TH( rtable.site_id.label ),
192 rtable.site_id.represent( req.site_id ),
193 ),
194 TR( TH( itable.item.label ),
195 item_str,
196 TH( itable.item_id.label ),
197 itable.item_id.represent( item.item_id ),
198 ),
199 TR( #TH( rtable.purpose.label ),
200 #req.purpose,
201 TH( itable.specs.label ),
202 item.specs,
203 ),
204 )
205 return summary
206# -----------------------------------------------------------------------------
207def req_form(r):
208 form_btns = DIV( BUTTON(T("Request for Donation Form"),
209 _class = "accept-button",
210 _onClick = "javascript: window.location='%s'" % \
211 URL(c = request.controller,
212 f = "req_print",
213 args = r.id
214 )
215 ),
216 # Also in controllers/vol.py - DRY
217 A( IMG( _src = "/%s/static/img/get_adobe_reader.png" % request.application,
218 _title = "%s - %s" % (T("Get Adobe Reader"),
219 T("This link will open a new browser window.")),
220 _alt = T("Get Adobe Reader"),
221 _width = 158,
222 _height = 39,
223 _style = "float:right;"),
224 _href="http://www.adobe.com/products/acrobat/readstep2.html",
225 _target="_blank"),
226 )
227
228 ftable = db.req_fulfill
229 query = (ftable.req_id == r.id)
230 frecord = db(query).select(limitby=(0, 1)).first()
231 if frecord and frecord.datetime_fulfill != None:
232 form_btns.append( BUTTON (T("Donation Certificate"),
233 _class = "accept-button",
234 _onClick = "javascript: window.location='%s'" % \
235 URL(c = request.controller,
236 f = "req_print",
237 args = [r.id, True]
238 )
239 ))
240 return form_btns
241# -----------------------------------------------------------------------------
242def req_rheader(r):
243 """
244 Resource Header for Requests for Donations
245 - Staff View
246 """
247 record = r.record
248 if r.representation == "html" and record:
249 tabs = [(T("Details"), None)]
250 req_item_tab_label = T("Resource")
251 tabs.append((req_item_tab_label, "req_item"))
252 tabs.append((T("Find Match"), "match/"))
253 if deployment_settings.get_req_use_commit():
254 tabs.append((T("Donation"), "commit"))
255 tabs.append(( T("Received"), "fulfill"))
256 tabs.append(( T("Surplus"), "surplus_item"))
257 if deployment_settings.has_module("doc"):
258 tabs.append((T("Documents"), "document"))
259
260 rheader_tabs = s3_rheader_tabs(r, tabs)
261
262 site_id = request.vars.site_id
263 if site_id:
264 site_name = shn_site_represent(site_id, show_link = False)
265 commit_btn = TAG[""](
266 A( T("Commit from %s") % site_name,
267 _href = URL(c = "req",
268 f = "commit_req",
269 args = [r.id],
270 vars = dict(site_id = site_id)
271 ),
272 _class = "action-btn"
273 ),
274 A( T("Send from %s") % site_name,
275 _href = URL(c = "req",
276 f = "send_req",
277 args = [r.id],
278 vars = dict(site_id = site_id)
279 ),
280 _class = "action-btn"
281 )
282 )
283 #else:
284 # commit_btn = A( T("Commit"),
285 # _href = URL(c = "req",
286 # f = "commit",
287 # args = ["create"],
288 # vars = dict(req_id = r.id)
289 # ),
290 # _class = "action-btn"
291 # )
292 response.s3.rfooter = commit_btn
293
294 rheader = DIV( req_summary(r),
295 req_form(r)
296 )
297
298 rheader.append(rheader_tabs)
299
300 return rheader
301 #else:
302 # No Record means that we are either a Create or List Create
303 # Inject the helptext script
304 # Removed because causes an error if validation fails twice
305 # return response.s3.req_helptext_script
306 return None
307# -----------------------------------------------------------------------------
308def req():
309 """
310 /don/req
311 """
312 s3mgr.load("req_req")
313 req_table = db.req_req
314
315 req_type = 1
316 req_table.type.default = req_type
317 query = (db.req_req.type == req_type)
318 if response.s3.filter:
319 response.s3.filter = response.s3.filter & query
320 else:
321 response.s3.filter = query
322 # -------------------------------------------------------------------------------------------
323 s3mgr.configure("req_req",
324 list_fields = ["id",
325 #"priority",
326 "status",
327 (T("BOC Status"), "req_commit_status"),
328 "created_on",
329 "date_required",
330 (T("Resource"), "item"),
331 "site_id",
332 ],
333 orderby = ["created_on"])
334
335 s3mgr.load("req_req")
336
337 # -------------------------------------------------------------------------------------------
338 ADD_ITEM_REQUEST = T("Make a Request for Donations")
339 LIST_ITEM_REQUEST = T("List Requests for Donations")
340 s3.crud_strings["req_req"] = Storage(
341 title_create = ADD_ITEM_REQUEST,
342 title_display = T("Request for Donations Details"),
343 title_list = LIST_ITEM_REQUEST,
344 title_update = T("Edit Request for Donations"),
345 title_search = T("Search Requests for Donations"),
346 subtitle_create = ADD_ITEM_REQUEST,
347 subtitle_list = T("Requests for Donations"),
348 label_list_button = LIST_ITEM_REQUEST,
349 label_create_button = ADD_ITEM_REQUEST,
350 label_delete_button = T("Delete Request for Donations"),
351 msg_record_created = T("Request for Donations Added"),
352 msg_record_modified = T("Request for Donations Updated"),
353 msg_record_deleted = T("Request for Donations Canceled"),
354 msg_list_empty = T("No Requests for Donations")
355 )
356
357 # Request for Donation labels
358 req_table.purpose.label = T("What the Resources will be used for")
359 req_table.site_id.label =T("Deliver To Facility")
360 req_table.request_for_id.label = T("Deliver To Person")
361 req_table.created_on.label = T("Pushed to BOC")
362
363 if "document" in request.args:
364 s3mgr.load("doc_document")
365
366 def prep(r):
367 # Remove type from list_fields
368 list_fields = s3mgr.model.get_config("req_req",
369 "list_fields")
370 try:
371 list_fields.remove("type")
372 except:
373 # It has already been removed.
374 # This can happen if the req controller is called
375 # for a second time, such as when printing reports
376 # see vol.print_assignment()
377 pass
378 s3mgr.configure(tablename, list_fields=list_fields)
379
380
381 if r.interactive:
382 # Set Fields and Labels
383 req_table.type.readable = False
384 req_table.type.writable = False
385
386
387 if r.method != "create" and False: # @ToDo: Remove "and False" - this has been added for training to allow records to be edit
388 # Disable Edit for fields where WebEOC is Master
389 req_table.event_id.writable = False
390 req_table.incident_id.writable = False
391 req_table.request_number.writable = False
392 req_table.priority.writable = False
393 req_table.site_id.writable = False
394 req_table.request_for_id.writable = False
395 req_table.date_required.writable = False
396 req_table.date_required_until.writable = False
397 req_table.purpose.writable = False
398 req_table.date.writable = False
399 req_table.requester_id.writable = False
400 req_table.approved_by_id.writable = False
401 req_table.comments.writable = False
402 req_table.cancel.writable = False
403
404 if r.record and r.record.req_req_item.count():#r.component and r.component.name == "req_item":
405 # Is this component being updated (not created)
406 req_item_table = db.req_req_item
407 #req_item_table.item.writable = False
408 req_item_table.item_pack_id.writable = False
409 req_item_table.quantity.writable = False
410
411 elif r.record and r.record.req_req_skill.count():#r.component and r.component.name == "req_skill":
412 # Is this component being updated (not created)
413 req_skill_table = db.req_req_skill
414 req_skill_table.skill_id.writable = False
415 req_skill_table.quantity.writable = False
416
417 #req_table.recv_by_id.label = T("Delivered To")
418
419 # Update Donated By from selection on Match tab
420 don_item_id = request.vars.don_item_id
421 if r.component and r.component.name == "commit" and don_item_id:
422 request.vars.pop("don_item_id")
423 don_item = db(db.don_don_item.id == don_item_id
424 ).select(db.don_don_item.organisation_id,
425 limitby=[0,1]).first()
426 if don_item:
427 db.req_commit.donated_by_id.default = don_item.organisation_id
428 db(db.req_commit.req_id == r.id).update(donated_by_id = don_item.organisation_id)
429 if r.component and r.component.name == "req_item":
430 s3mgr.s3.crud.submit_button = T("Save&Find Match")
431 match_url = URL(c="don", f = "match",
432 vars = dict(viewing="req_req.%s" % r.id)
433 )
434 s3mgr.configure("req_req_item",
435 update_next = match_url,
436 create_next = match_url
437 )
438
439 if r.method != "update" and r.method != "read":
440 if not r.component:
441 # Hide fields which don't make sense in a Create form
442 # - includes one embedded in list_create
443 # - list_fields over-rides, so still visible within list itself
444 response.s3.req_create_form_mods()
445
446 # Get the default Facility for this user
447 # @ToDo: Use site_id in User Profile (like current organisation_id)
448 if deployment_settings.has_module("hrm"):
449 query = (db.hrm_human_resource.person_id == s3_logged_in_person())
450 site = db(query).select(db.org_site.id,
451 limitby=(0, 1)).first()
452 if site:
453 r.table.site_id.default = site.id
454
455 elif r.component.name == "document":
456 s3.crud.submit_button = T("Add")
457 table = r.component.table
458 # @ToDo: Fix for Link Table
459 #table.date.default = r.record.date
460 #if r.record.site_id:
461 # stable = db.org_site
462 # query = (stable.id == r.record.site_id)
463 # site = db(query).select(stable.location_id,
464 # stable.organisation_id,
465 # limitby=(0, 1)).first()
466 # if site:
467 # table.location_id.default = site.location_id
468 # table.organisation_id.default = site.organisation_id
469
470 elif r.component.name == "req_item":
471 table = r.component.table
472 table.site_id.writable = table.site_id.readable = False
473 response.s3.req_hide_quantities(table)
474
475 if r.component:
476 if r.component.name == "document" or \
477 r.component.name == "req_item" or \
478 r.component.name == "req_skill":
479 # Limit site_id to facilities the user has permissions for
480 # @ToDo: Non-Item requests shouldn't be bound to a Facility?
481 auth.permission.permitted_facilities(table=r.table,
482 error_msg=T("You do not have permission for any facility to make a request."))
483 else:
484 # Limit site_id to facilities the user has permissions for
485 # @ToDo: Non-Item requests shouldn't be bound to a Facility?
486 auth.permission.permitted_facilities(table=r.table,
487 error_msg=T("You do not have permission for any facility to make a request."))
488
489 return True
490 response.s3.prep = prep
491
492 # Post-process
493 def postp(r, output):
494 if r.interactive:
495 s3_action_buttons(r)
496 if r.component and r.component.name == "req_item":
497 req_item_don_item_btn = dict(url = URL(c = "req",
498 f = "req_item_don_item",
499 args = ["[id]"]
500 ),
501 _class = "action-btn",
502 label = str(T("Find")), # Change to Fulfil? Match?
503 )
504 response.s3.actions.append(req_item_don_item_btn)
505 return output
506
507 response.s3.postp = postp
508
509 output = s3_rest_controller("req", "req", rheader=req_rheader)
510 return output
511# -----------------------------------------------------------------------------
512def req_print():
513 """ Print Donation Request Form """
514 s3mgr.load("req_req")
515 r = s3base.S3Request(s3mgr,
516 prefix="req",
517 name="req",
518 extension="pdf",
519 args = request.args[0])
520 if len(request.args) > 1:
521 s3mgr.configure("req_req",
522 callback = response.s3.donationCertificate,
523 formname = T("Donation Certificate"),
524 header = response.s3.donCertBorder,
525 footer = lambda x, y: None,
526 )
527 else:
528 s3mgr.configure("req_req",
529 callback = response.s3.donationRequest,
530 formname = T("Request for Donations"),
531 footer = response.s3.donationFooter
532 )
533 return r()
534
535# -----------------------------------------------------------------------------
536
537def loan():
538 """ Loans REST Controller """
539
540 s3mgr.load("req_commit")
541 ctable = db.req_commit
542
543 # Filter for Loans
544 response.s3.filter = (ctable.status == 9 )
545 s3mgr.configure("req_commit",
546 list_fields = ["donated_by_id",
547 "specs",
548 # Site virtual Field?
549 "datetime_return",
550 ],
551 orderby = ["datetime_return"])
552 output = s3_rest_controller("req", "commit")
553 if isinstance(output, dict):
554 output["title"] = T("Donations on Loan Report")
555 output["subtitle"] = T("Donations on Loan")
556 response.s3.actions = [dict(url = URL(c = "don",
557 f = "req",
558 args = ["commit","[id]"],
559 ),
560 _class = "action-btn",
561 label = str(T("Open")),
562 ),
563 ]
564 return output
565
566# -----------------------------------------------------------------------------
567s3mgr.configure("don_don_item",
568 list_fields = ["id",
569 "organisation_id",
570 "item_category_id",
571 "item_id",
572 "pack_value",
573 "quantity",
574 ]
575 )
576
577ADD_ITEM = T("Add Donation Resource")
578LIST_ITEMS = T("List Donation Resources")
579s3.crud_strings["don_don_item"] = Storage(
580 title_create = ADD_ITEM,
581 title_display = T("Donation Resource Details"),
582 title_list = LIST_ITEMS,
583 title_update = T("Edit Donation Resource"),
584 title_search = T("Search Donation Resources"),
585 subtitle_create = ADD_ITEM,
586 subtitle_list = T("Donation Resources"),
587 label_list_button = LIST_ITEMS,
588 label_create_button = ADD_ITEM,
589 label_delete_button = T("Remove Donation Resource"),
590 msg_record_created = T("Donation Resource Added"),
591 msg_record_modified = T("Donation Resource updated"),
592 msg_record_deleted = T("Donation Resource removed"),
593 msg_list_empty = T("No Donation Resources for this Corporation"))
594
595ADD_GOODS = T("In the event of a declared disaster we MAY be able to donate the following Goods:")
596LIST_GOODS = T("List Donation Goods")
597s3.crud_strings["don_good"] = Storage(
598 title_create = ADD_GOODS,
599 title_display = T("Donation Good Details"),
600 title_list = LIST_GOODS,
601 title_update = T("Edit Donation Goods"),
602 title_search = T("Search Donation Goods"),
603 subtitle_create = ADD_GOODS,
604 subtitle_list = T("Donate Goods"),
605 label_list_button = LIST_GOODS,
606 label_create_button = ADD_GOODS,
607 label_delete_button = T("Remove Donation Goods"),
608 msg_record_created = T("Donation Goods Added"),
609 msg_record_modified = T("Donation Goods updated"),
610 msg_record_deleted = T("Donation Goods removed"),
611 msg_list_empty = T("No Donation Goods for this Corporation"))
612
613ADD_SERVICE = T("In the event of a declared disaster we MAY be able to donate the following Services:")
614LIST_SERVICES = T("List Donation Services")
615s3.crud_strings["don_service"] = Storage(
616 title_create = ADD_SERVICE,
617 title_display = T("Donation Service Details"),
618 title_list = LIST_SERVICES,
619 title_update = T("Edit Donation Service"),
620 title_search = T("Search Donation Services"),
621 subtitle_create = ADD_SERVICE,
622 subtitle_list = T("Donate Services"),
623 label_list_button = LIST_SERVICES,
624 label_create_button = ADD_SERVICE,
625 label_delete_button = T("Remove Donation Service"),
626 msg_record_created = T("Donation Service Added"),
627 msg_record_modified = T("Donation Service updated"),
628 msg_record_deleted = T("Donation Service removed"),
629 msg_list_empty = T("No Donation Services for this Corporation"))
630
631ADD_FACILITY = T("In the event of a declared disaster we MAY be able to donate the following Facilities:")
632LIST_FACILITYS = T("List Donation Facilities")
633s3.crud_strings["don_facility"] = Storage(
634 title_create = ADD_FACILITY,
635 title_display = T("Donation Facility Details"),
636 title_list = LIST_FACILITYS,
637 title_update = T("Edit Donation Facility"),
638 title_search = T("Search Donation Facilities"),
639 subtitle_create = ADD_FACILITY,
640 subtitle_list = T("Donate Facilities"),
641 label_list_button = LIST_FACILITYS,
642 label_create_button = ADD_FACILITY,
643 label_delete_button = T("Remove Donation Facility"),
644 msg_record_created = T("Donation Facility Added"),
645 msg_record_modified = T("Donation Facility updated"),
646 msg_record_deleted = T("Donation Facility removed"),
647 msg_list_empty = T("No Donation Facilities for this Corporation"))
648
649# -----------------------------------------------------------------------------
650def don_item_filter(don_item_add_filter_func):
651 """
652 Filter donated 'items' by category
653 Services = category 'SERVICES'
654 Facilities = category 'FACILITY'
655 Goods = everything else
656 """
657 itable = db.don_don_item
658 ctable = db.supply_item_category
659
660 query = (ctable.code == "FACILITY")
661 facility_cat_id = db(query).select(ctable.id,
662 limitby = (0, 1),
663 cache = gis.cache).first().id
664 query = (ctable.code == "SERVICES")
665 service_cat_id = db(query).select(ctable.id,
666 limitby = (0, 1),
667 cache = gis.cache).first().id
668
669 itable.organisation_id.widget = None # Implement SearchACWidget for Organisations
670 itable.organisation_id.requires = IS_NULL_OR(IS_ONE_OF(db, "org_organisation.id",
671 organisation_represent,
672 orderby="org_organisation.name",
673 sort=True,
674 filterby = "has_items",
675 filter_opts = [True])
676 )
677 itable.item_id.widget = None
678
679 if not s3_has_role(STAFF):
680 # Only Staff can add Categories
681 itable.item_category_id.comment = ""
682 # Only Staff can add Item Types
683 # @ToDo: Allow adding Items to 'OTHER' category
684 itable.item_id.comment = ""
685 # Only Staff can add Item Units
686 # @ToDo: Should Units for Services/Facilities be hardcoded/hidden?
687 # (always day/ea)
688 comment = DIV(_class="tooltip",
689 _title="%s|%s" % (T("Resource Units"),
690 T("The way in which an item is normally distributed")))
691 script = SCRIPT(
692"""
693S3FilterFieldChange({
694 'FilterField': 'item_id',
695 'Field': 'item_pack_id',
696 'FieldResource':'item_pack',
697 'FieldPrefix': 'supply',
698 'msgNoRecords': S3.i18n.no_packs,
699 'fncPrep': fncPrepItem,
700 'fncRepresent': fncRepresentItem
701});""")
702 itable.item_pack_id.comment = TAG[""](comment, script)
703
704 item_type = request.vars.item
705 if item_type == "goods":
706 s3.crud_strings["don_don_item"] = s3.crud_strings["don_good"]
707
708 itable.lead_time.readable = True
709 itable.lead_time.writable = True
710 itable.type.readable = True
711 itable.type.writable = True
712 itable.item_category_id.requires = IS_NULL_OR(IS_ONE_OF(db,
713 "supply_item_category.id",
714 "%(name)s",
715 not_filterby = "id",
716 not_filter_opts = [facility_cat_id, service_cat_id],
717 sort=True))
718 response.s3.jquery_ready = [
719"""
720$(document).ready(function() {
721 S3FilterFieldChange({
722 'FilterField': 'item_category_id',
723 'Field': 'item_id',
724 'FieldResource':'item',
725 'FieldPrefix': 'supply',
726 //'url': S3.Ap.concat('/req/req_item_packs/'),
727 //'msgNoRecords': S3.i18n.no_packs,
728 //'fncPrep': fncPrepItem,
729 //'fncRepresent': fncRepresentItem
730 });
731});
732"""
733]
734 query = (itable.item_category_id != facility_cat_id) & \
735 (itable.item_category_id != service_cat_id)
736 don_item_add_filter_func( query )
737 elif item_type in ["services", "facilities"]:
738 if item_type == "services":
739 s3.crud_strings["don_don_item"] = s3.crud_strings["don_service"]
740
741 item_category_filter = service_cat_id
742 itable.item_id.label = T("Service Type")
743 if s3_has_role(STAFF):
744 itable.item_id.comment = DIV(A(T("Add Service Type"),
745 _class="colorbox",
746 _href=URL(c="supply", f="item",
747 args="create",
748 vars=dict(format="popup")),
749 _target="top",
750 _title=T("Add Service Type")))
751 itable.quantity.label = T("Duration of Donated Services")
752 itable.item_pack_id.label = T("Unit of Time")
753 itable.item_pack_id.readable = True
754 itable.item_pack_id.writable = True
755 itable.pack_value.label = T("Estimated Value ($) per Unit of Time")
756
757 elif item_type == "facilities":
758 s3.crud_strings["don_don_item"] = s3.crud_strings["don_facility"]
759
760 item_category_filter = facility_cat_id
761 itable.item_id.label = T("Facility Type")
762 if s3_has_role(STAFF):
763 itable.item_id.comment = DIV(A(T("Add Facility Type"),
764 _class="colorbox",
765 _href=URL(c="supply", f="item",
766 args="create",
767 vars=dict(format="popup")),
768 _target="top",
769 _title=T("Add Facility Type")))
770 itable.specs.label = T("Specifications (Square Feet, Building Type, Stories, Services)")
771
772 itable.item_category_id.readable = itable.item_category_id.writable = False
773 itable.item_category_id.default = item_category_filter
774
775 itable.item_id.requires = IS_ONE_OF(db, "supply_item.id",
776 lambda id: response.s3.item_represent(id,
777 show_um = False,
778 show_link = False),
779 filterby = "item_category_id",
780 filter_opts = [item_category_filter],
781 sort=True)
782
783 query = (itable.item_category_id == item_category_filter)
784 don_item_add_filter_func( query )
785# -----------------------------------------------------------------------------
786def organisation():
787 """
788 /org/organisation/ corporation
789 """
790
791 otable = db.org_organisation
792
793 otable.acronym.readable = False
794 otable.acronym.writable = False
795 otable.sector_id.readable = True
796 otable.sector_id.writable = True
797 org_has_items_field = otable.has_items
798 org_has_items_field.default = True
799 response.s3.filter = (org_has_items_field == True)
800
801 if not s3_has_role(STAFF):
802 # Tweak the breadcrumb
803 breadcrumbs[2] = (T("Organization Profile"), False,
804 URL(c=request.controller,
805 f=request.function,
806 args=request.args))
807
808 def corporation_rheader(r, tabs = []):
809 """ Corporation rheader """
810
811 if r.representation == "html":
812
813 if r.record is None:
814 # List or Create form: rheader makes no sense here
815 return None
816
817 tabs = [(T("Basic Details"), None),
818 (T("Contacts"), "human_resource"),
819 (T("Donate Goods"), "don_item", dict(item="goods")),
820 (T("Donate Services "), "don_item", dict(item="services")),
821 (T("Donate Facilities "), "don_item", dict(item="facilities")),
822 ]
823 if "register" not in request.vars:
824 tabs.append( (T("Donations"), "commit") )
825 rheader_tabs = s3_rheader_tabs(r, tabs)
826
827 organisation = r.record
828 if organisation.sector_id:
829 _sectors = org_sector_represent(organisation.sector_id)
830 else:
831 _sectors = None
832
833 if deployment_settings.get_ui_cluster():
834 sector_label = T("Cluster(s)")
835 else:
836 sector_label = T("Sector(s)")
837
838 rheader = DIV(TABLE(
839 TR(
840 TH("%s: " % T("Corporation")),
841 organisation.name,
842 TH("%s: " % sector_label),
843 _sectors
844 )),
845 rheader_tabs
846 )
847 return rheader
848 return None
849
850 ADD_CORPORATION = T("Add Corporation / Organization")
851 LIST_CORPORATIONS = T("List Corporations & Organizations")
852 s3.crud_strings["org_organisation"] = Storage(
853 title_create = ADD_CORPORATION,
854 title_display = T("Corporation / Organization Details"),
855 title_list = LIST_CORPORATIONS,
856 title_update = T("Edit Corporation / Organization"),
857 title_search = T("Search Corporations & Organizations"),
858 subtitle_create = T("Add New Corporation / Organization"),
859 subtitle_list = T("Corporations & Organizations"),
860 label_list_button = LIST_CORPORATIONS,
861 label_create_button = ADD_CORPORATION,
862 label_delete_button = T("Delete Corporation / Organization"),
863 msg_record_created = T("Corporation / Organization added"),
864 msg_record_modified = T("Corporation / Organization updated"),
865 msg_record_deleted = T("Corporation / Organization deleted"),
866 msg_list_empty = T("No Corporations & Organizations currently registered"))
867
868 def prep(r):
869 don_item_filter(lambda query:
870 r.resource.add_component_filter("don_item", query))
871 if r.component:
872 if r.component.name == "don_item":
873 itable = db.don_don_item
874 itable.currency.readable = False
875 elif r.component.name == "human_resource":
876 hrtable = db.hrm_human_resource
877 hrtable.type.writable = hrtable.type.readable = False
878 hrtable.status.writable = hrtable.status.readable = False
879 hrtable.focal_point.writable = hrtable.focal_point.readable = False
880 response.s3.jquery_ready.append("$('#hrm_human_resource_person_id__row1').hide();")
881
882 s3.crud_strings["hrm_human_resource"] = Storage(
883 title_create = T("Add Contact"),
884 title_display = T("Contact Details"),
885 title_list = T("Contacts"),
886 title_update = T("Edit Contact"),
887 title_search = T("Search Contacts"),
888 subtitle_create = T("Additional Contacts (optional)"),
889 subtitle_list = T("Contacts"),
890 label_list_button = T("List Contacts"),
891 label_create_button = T("Add Contacts"),
892 label_delete_button = T("Delete Contact"),
893 msg_record_created = T("Contact added"),
894 msg_record_modified = T("Contact updated"),
895 msg_record_deleted = T("Contact deleted"),
896 msg_no_match = T("No Contacts Found"),
897 msg_list_empty = T("Currently there are no Contact registered"))
898
899 # Donation Organization Regisration Workflow
900 if "register" in request.vars:
901 # Only force the open on 1st run
902 response.s3.show_listadd = True
903 s3mgr.configure("hrm_human_resource",
904 create_next = URL(c="don", f="organisation",
905 args = [r.record.id, "don_item"],
906 vars = dict(item="goods"))
907 )
908
909 # Add req to Corporations as Donations
910 s3mgr.configure("req_commit",
911 insertable = False,
912 editable = False,
913 deletable = False,
914 )
915
916 s3mgr.configure( "org_organisation",
917 list_fields = ["id",
918 "name",
919 #"type",
920 "sector_id",
921 #"country",
922 #"website"
923 ])
924
925 # req CRUD strings
926 REQ = T("Donation")
927 #ADD_REQ = T("Add Donation")
928 LIST_REQ = T("List Donations")
929 s3.crud_strings["req_req"] = Storage(
930 #title_create = ADD_REQ,
931 title_display = T("Donation Details"),
932 title_list = LIST_REQ,
933 #title_update = T("Edit Donation"),
934 title_search = T("Search Donations"),
935 #subtitle_create = ADD_REQ,
936 subtitle_list = T("Donations"),
937 label_list_button = LIST_REQ,
938 #label_create_button = ADD_REQ,
939 #label_delete_button = T("Remove Donations"),
940 #msg_record_created = T("Donation Added"),
941 #msg_record_modified = T("Donation updated"),
942 #msg_record_deleted = T("Donation removed"),
943 msg_list_empty = T("No Donations from this Corporation"))
944
945 if not s3_has_role(STAFF):
946 response.s3.donate_cash_link =True
947
948 return organisation_controller(organisation_rheader = corporation_rheader,
949 org_prep = prep)
950
951# -----------------------------------------------------------------------------
952def don_item():
953 """ REST Controller """
954
955 def don_item_add_filter_func(query):
956 response.s3.filter = query
957 don_item_filter(don_item_add_filter_func)
958
959 # Tweak the breadcrumb
960 type = request.get_vars.item
961 if type == "goods":
962 label = T("Goods")
963 elif type == "services":
964 label = T("Services")
965 elif type == "facilities":
966 label = T("Facilities")
967 else:
968 # Error!
969 label = ""
970 breadcrumbs[2] = (label, False,
971 URL(c=request.controller,
972 f=request.function,
973 vars=request.vars))
974
975 def postp(r, output):
976 # maintain the ?items= type
977 if "type" in request.vars:
978 response.s3.actions = [
979 dict(label=str(UPDATE),
980 _class="action-btn",
981 url=URL(args = ["[id]"] + ["update"],
982 vars=request.vars)),
983 ]
984 return output
985 response.s3.postp = postp
986
987 output = s3_rest_controller(module, "don_item")
988 return output
989
990# -----------------------------------------------------------------------------
991def collect():
992 """ REST Controller """
993 def prep(r):
994 s3mgr.configure("don_collect",
995 list_fields = ["id",
996 "start_datetime",
997 "end_datetime",
998 "site_id",
999 "organisation_id",
1000 ])
1001 return True
1002
1003 response.s3.prep = prep
1004 output = s3_rest_controller(module, resourcename)
1005 return output
1006
1007# -----------------------------------------------------------------------------
1008def distribute():
1009 """ REST Controller """
1010 output = s3_rest_controller(module, resourcename)
1011 return output
1012
1013# -----------------------------------------------------------------------------
1014def profile():
1015 """ Organisation Profile """
1016 return organisation_profile()
1017
1018# -----------------------------------------------------------------------------
1019################################################################################
1020### Hook to call get the donation certificate
1021################################################################################
1022#def certprint():
1023# """ Print Cert TEST """
1024# s3mgr.load("don_distribute")
1025# r = s3base.S3Request(s3mgr,
1026# prefix="don",
1027# name="distribute",
1028# extension="pdf")
1029# s3mgr.configure("don_distribute",
1030# callback = response.s3.donationCertificate,
1031# formname = "Donation Certificate",
1032# header = response.s3.donCertBorder,
1033# footer = lambda x, y: None,
1034# )
1035# return r()
1036################################################################################
1037###
1038################################################################################
1039
1040
1041# END =========================================================================
0\ No newline at end of file1042\ No newline at end of file
11043
=== modified file 'controllers/event.py'
--- controllers/event.py 2011-10-13 16:40:31 +0000
+++ controllers/event.py 2011-11-18 07:40:33 +0000
@@ -32,6 +32,16 @@
32 redirect(URL(f="event", args="create"))32 redirect(URL(f="event", args="create"))
3333
34# =============================================================================34# =============================================================================
35# Incidents
36# =============================================================================
37def incident():
38 """ RESTful CRUD controller """
39
40 tablename = "event_incident"
41 s3mgr.load(tablename)
42 return s3_rest_controller(module, resourcename)
43
44# =============================================================================
35# Events45# Events
36# =============================================================================46# =============================================================================
37def event():47def event():
@@ -184,7 +194,7 @@
184 tabs.append((T("Map Configuration"), "config"))194 tabs.append((T("Map Configuration"), "config"))
185195
186 rheader = lambda r, tabs=tabs: event_rheader(r, tabs)196 rheader = lambda r, tabs=tabs: event_rheader(r, tabs)
187 output = s3_rest_controller("event", resourcename,197 output = s3_rest_controller(module, resourcename,
188 rheader=rheader)198 rheader=rheader)
189 return output199 return output
190200
191201
=== modified file 'controllers/gis.py'
--- controllers/gis.py 2011-11-12 23:58:22 +0000
+++ controllers/gis.py 2011-11-18 07:40:33 +0000
@@ -98,7 +98,7 @@
98 catalogue_toolbar = False98 catalogue_toolbar = False
9999
100 # @ToDo: Make these configurable100 # @ToDo: Make these configurable
101 search = True101 search = False
102 googleEarth = True102 googleEarth = True
103 googleStreetview = True103 googleStreetview = True
104 catalogue_layers = True104 catalogue_layers = True
@@ -127,7 +127,8 @@
127 search=search,127 search=search,
128 catalogue_layers=catalogue_layers,128 catalogue_layers=catalogue_layers,
129 mouse_position = mouse_position,129 mouse_position = mouse_position,
130 print_tool = print_tool130 print_tool = print_tool,
131 collapsed = True
131 )132 )
132133
133 return map134 return map
134135
=== modified file 'controllers/hrm.py'
--- controllers/hrm.py 2011-11-17 14:39:04 +0000
+++ controllers/hrm.py 2011-11-18 07:40:33 +0000
@@ -1033,4 +1033,228 @@
1033 redirect_vars = {fieldname: id},1033 redirect_vars = {fieldname: id},
1034 title_name = title)1034 title_name = title)
10351035
1036# =============================================================================
1037# Adding a human resource inline
1038# =============================================================================
1039
1040def create_inline():
1041
1042 # arguments ?
1043 formstyle = s3_formstyle
1044 field_name = field.name
1045
1046 # Set up fields
1047 pr_person = db.pr_person
1048 hrm_human_resource = db.hrm_human_resource
1049
1050 fields = [
1051 pr_person.first_name,
1052 pr_person.middle_name,
1053 pr_person.last_name,
1054
1055 hrm_human_resource.job_title,
1056 ]
1057
1058 emailRequired = (
1059 request.controller == "hrm" and
1060 deployment_settings.get_hrm_email_required()
1061 )
1062
1063 if emailRequired:
1064 email_validator = IS_EMAIL()
1065 else:
1066 email_validator = IS_NULL_OR(IS_EMAIL())
1067
1068 email_field_name = "email_address"
1069 mobile_phone_field_name = "mobile_phone"
1070 fields.extend([
1071 Field(
1072 "organisation_id",
1073 notnull=True,
1074 requires = hrm_human_resource.organisation_id.requires,
1075 label = hrm_human_resource.organisation_id.label,
1076 represent = hrm_human_resource.organisation_id.represent,
1077 ),
1078 Field(
1079 email_field_name,
1080 notnull=emailRequired,
1081 requires=email_validator,
1082 label=T("Email Address")
1083 ),
1084 Field(
1085 mobile_phone_field_name,
1086 label=T("Mobile Phone Number")
1087 )
1088 ])
1089
1090 labels, required = s3_mark_required(fields)
1091 if required:
1092 response.s3.has_required = True
1093
1094 form = SQLFORM.factory(table_name="hrm_human_resource",
1095 labels=labels,
1096 formstyle=formstyle,
1097 separator = "",
1098 *fields)
1099
1100 # JavaScript
1101 def add_script(script_name):
1102 response.s3.scripts.append(
1103 "%s/%s" % (response.s3.script_dir, script_name)
1104 )
1105
1106 result = dict(
1107 form = TAG[""](
1108 # to stop some browsers appying a default table style to unstyled tables
1109 XML("""<style type="text/css">table { font-size:inherit; }</style>"""),
1110 form
1111 ),
1112 created_object_id = None,
1113 created_object_representation = "",
1114 errors = form.errors
1115 )
1116
1117 accepted = form.accepts(request.vars)#, session):
1118
1119 # more validation, don't let other validation errors upset this,
1120 # as the user wants to see all errors in one go
1121 pr_contact = db.pr_contact
1122 pr_person = db.pr_person
1123 def var(name):
1124 return request.vars.get(name, None)
1125
1126 def check_request_var_matches_value_if_given(var_name, value):
1127 if var(var_name):
1128 if var(var_name) != value:
1129 if not form.errors.has_key(var_name):
1130 form.errors[var_name] = (
1131 T("There is a existing record, but the %(property)s is different. "
1132 "(Clearing this field allows use of the existing record)")
1133 ) % dict(
1134 property = var_name.replace("_", " ")
1135 )
1136
1137 def existing(*query):
1138 return db(*query).select().first()
1139
1140 existing_mobile_phone_contact = None
1141 existing_person = None
1142 existing_human_resource = None
1143
1144 # look for a person with the same email address
1145 email_address = var(email_field_name)
1146 if email_address:
1147 existing_email_contact = existing(
1148 (pr_contact.contact_method == "EMAIL") &
1149 (pr_contact.value == email_address)
1150 )
1151 if existing_email_contact is not None:
1152 # check every other contact detail matches, otherwise complain
1153
1154 # mobile phone
1155 existing_mobile_phone_contact = existing(
1156 (pr_contact.contact_method == "MOBILE PHONE") &
1157 (pr_contact.pe_id == existing_email_contact.pe_id)
1158 )
1159 if existing_mobile_phone_contact is not None:
1160 check_request_var_matches_value_if_given(
1161 "mobile_phone",
1162 existing_mobile_phone_contact.value
1163 )
1164
1165 # person details
1166 existing_person = existing(
1167 pr_person.pe_id == existing_email_contact.pe_id
1168 )
1169 if existing_person is not None:
1170 check_request_var_matches_value_if_given(
1171 "first_name",
1172 existing_person.first_name
1173 )
1174 check_request_var_matches_value_if_given(
1175 "middle_name",
1176 existing_person.middle_name
1177 )
1178 check_request_var_matches_value_if_given(
1179 "last_name",
1180 existing_person.last_name
1181 )
1182
1183 # human resource
1184 existing_human_resource = existing(
1185 hrm_human_resource.person_id == existing_person.id
1186 )
1187 if existing_human_resource is not None:
1188 check_request_var_matches_value_if_given(
1189 "job_title",
1190 existing_human_resource.job_title
1191 )
1192 check_request_var_matches_value_if_given(
1193 "organisation_id",
1194 existing_human_resource.organisation_id
1195 )
1196
1197 if accepted: # create objects as necessary
1198 # an email address is assumed to uniquely identify a person
1199 # however, there is no guarantee that a person has an email address
1200 if existing_email_contact is None:
1201 # there is no pr_pentity
1202 pe_id = db.pr_pentity.insert(
1203 ).pe_id
1204
1205 db.pr_contact.insert(
1206 pe_id = pe_id,
1207 contact_method = "EMAIL",
1208 value = email_address,
1209 )
1210 else:
1211 contact_id = existing_email_contact.id
1212 pe_id = existing_email_contact.pe_id
1213
1214 assert pe_id is not None
1215
1216 if existing_mobile_phone_contact is None:
1217 if var(mobile_phone_field_name):
1218 db.pr_contact.insert(
1219 pe_id = pe_id,
1220 contact_method = "MOBILE PHONE",
1221 value = var(mobile_phone_field_name)
1222 )
1223
1224 if existing_person is None:
1225 person_id = db.pr_person.insert(
1226 pe_id = pe_id,
1227 first_name = var("first_name"),
1228 middle_name = var("middle_name"),
1229 last_name = var("last_name")
1230 )
1231 else:
1232 person_id = existing_person.id
1233
1234 if form.errors:
1235 response.flash = "form is invalid"
1236 else:
1237 if existing_human_resource:
1238 result.update(
1239 created_object_id = existing_human_resource.id,
1240 created_object_representation = hrm_human_resource_represent(existing_human_resource)
1241 )
1242 # nothing needs adding?
1243 else:
1244 created_human_resource = db.hrm_human_resource.insert(
1245 person_id = person_id,
1246 job_title = var("job_title"),
1247 organisation_id = var("organisation_id")
1248 )
1249 db.commit()
1250 result.update(
1251 created_object_id = created_human_resource.id,
1252 created_object_representation = hrm_human_resource_represent(created_human_resource)
1253 )
1254 response.flash = T("form accepted")
1255
1256 result["vars"] = form.vars
1257 response.view="inner_form.html"
1258 return result
1259
1036# END =========================================================================1260# END =========================================================================
10371261
=== added file 'controllers/master.py'
--- controllers/master.py 1970-01-01 00:00:00 +0000
+++ controllers/master.py 2011-11-18 07:40:33 +0000
@@ -0,0 +1,22 @@
1# -*- coding: utf-8 -*-
2
3"""
4 Master Data - Controllers
5
6 @author: Fran
7"""
8
9module = request.controller
10
11if module not in deployment_settings.modules:
12 raise HTTP(404, body="Module disabled: %s" % module)
13
14# Options Menu (available in all Functions' Views)
15shn_menu(module)
16
17def index():
18 "Module's Home Page"
19
20 module_name = deployment_settings.modules[module].name_nice
21 response.title = module_name
22 return dict(module_name=module_name)
023
=== modified file 'controllers/org.py'
--- controllers/org.py 2011-10-28 22:01:42 +0000
+++ controllers/org.py 2011-11-18 07:40:33 +0000
@@ -159,4 +159,127 @@
159159
160 return output160 return output
161161
162
163# =============================================================================
164def add_site_inline():
165 """ Form to be pulled in by AJAX by the S3AddObjectWidget """
166 formstyle = s3_formstyle
167 field_name = field.name
168
169 # Set up fields
170 org_office = db.org_office
171
172 field_names = [
173 "type",
174 "name",
175 "address",
176 "address_2",
177 "L3",
178 "L1",
179 "postcode",
180 "phone1",
181 ]
182 fields = []
183 for field_name in field_names:
184 fields.append(getattr(org_office, field_name))
185
186 labels, required = s3_mark_required(fields)
187 if required:
188 response.s3.has_required = True
189
190 form = SQLFORM.factory(table_name="org_office",
191 labels=labels,
192 formstyle=formstyle,
193 separator = "",
194 *fields)
195
196 # change submit button text
197 submit_line = form[0][-1][0]
198 submit_button = submit_line[0]
199 submit_button.attributes["_value"] = T("Save")
200
201 # add cancel and reset buttons
202 submit_line.append(
203 INPUT(_type="button", _value=T("Cancel"), _onclick="close_iframe()")
204 )
205 submit_line.append(
206 INPUT(_type="reset", _value=T("Clear"))
207 )
208
209 # JavaScript
210 def add_script(script_name):
211 response.s3.scripts.append(
212 "%s/%s" % (response.s3.script_dir, script_name)
213 )
214
215 result = dict(
216 form = TAG[""](
217 # to stop some browsers appying a default table style to unstyled tables
218 XML("""<style type="text/css">table { font-size:inherit; }</style>"""),
219 form
220 ),
221 created_object_id = None,
222 created_object_representation = "",
223 errors = form.errors
224 )
225
226 accepted = form.accepts(request.vars)#, session):
227 # more validation, don't let other validation errors upset this,
228 # as the user wants to see all errors in one go
229 def var(name):
230 return request.vars.get(name, None)
231 def check_request_var_matches_value_if_given(var_name, value):
232 if var(var_name):
233 if var(var_name) != value:
234 if not form.errors.has_key(var_name):
235 form.errors[var_name] = (
236 T("There is a existing record, but the %(property)s is different. "
237 "(Clearing this field allows use of the existing record)")
238 ) % dict(
239 property = var_name.replace("_", " ")
240 )
241 def existing(*query):
242 return db(*query).select().first()
243 # look for an office with the same name
244 name = var("name")
245 if name:
246 existing_office = existing(
247 org_office.name == name
248 )
249 if existing_office is not None:
250 for field_name in field_names:
251 check_request_var_matches_value_if_given(
252 field_name,
253 getattr(existing_office, field_name)
254 )
255 else:
256 existing_office = None
257 if accepted:
258 # create objects as necessary
259 if form.errors:
260 response.flash = "form is invalid"
261 else:
262 if existing_office is not None:
263 result.update(
264 created_object_id = existing_office.id,
265 created_object_representation = existing_office.name
266 )
267 # nothing needs adding?
268 else:
269 created_office = db.org_office.insert(
270 **dict(
271 (field_name, var(field_name)) for field_name in field_names
272 )
273 )
274 db.commit()
275 result.update(
276 created_object_id = created_office.id,
277 created_object_representation = created_office.name
278 )
279 response.flash = T("form accepted")
280
281 result["vars"] = form.vars
282 response.view="inner_form.html"
283 return result
284
162# END =========================================================================285# END =========================================================================
163286
=== modified file 'controllers/project.py'
--- controllers/project.py 2011-11-04 10:52:23 +0000
+++ controllers/project.py 2011-11-18 07:40:33 +0000
@@ -16,7 +16,6 @@
1616
17# =============================================================================17# =============================================================================
18def index():18def index():
19
20 """ Module's Home Page """19 """ Module's Home Page """
2120
22 module_name = deployment_settings.modules[module].name_nice21 module_name = deployment_settings.modules[module].name_nice
@@ -30,21 +29,18 @@
3029
31# =============================================================================30# =============================================================================
32def need():31def need():
33
34 """ RESTful CRUD controller """32 """ RESTful CRUD controller """
3533
36 return s3_rest_controller(module, resourcename)34 return s3_rest_controller(module, resourcename)
3735
38# -----------------------------------------------------------------------------36# -----------------------------------------------------------------------------
39def need_type():37def need_type():
40
41 """ RESTful CRUD controller """38 """ RESTful CRUD controller """
4239
43 return s3_rest_controller(module, resourcename)40 return s3_rest_controller(module, resourcename)
4441
45# =============================================================================42# =============================================================================
46def project():43def project():
47
48 """ RESTful CRUD controller """44 """ RESTful CRUD controller """
4945
50 tablename = "%s_%s" % (module, resourcename)46 tablename = "%s_%s" % (module, resourcename)
@@ -117,9 +113,9 @@
117 rheader = site_rheader)113 rheader = site_rheader)
118# =============================================================================114# =============================================================================
119def activity():115def activity():
120
121 """ RESTful CRUD controller """116 """ RESTful CRUD controller """
122117
118<<<<<<< TREE
123 tablename = "%s_%s" % (module, resourcename)119 tablename = "%s_%s" % (module, resourcename)
124 table = db[tablename]120 table = db[tablename]
125121
@@ -172,10 +168,13 @@
172 )168 )
173 return rheader169 return rheader
174 return None170 return None
171=======
172 # Defined in the Model for use from Multiple Controllers for unified menus
173 return response.s3.project_activity_controller()
174>>>>>>> MERGE-SOURCE
175175
176# =============================================================================176# =============================================================================
177def task():177def task():
178
179 """ RESTful CRUD controller """178 """ RESTful CRUD controller """
180179
181 # Pre-process180 # Pre-process
@@ -257,7 +256,6 @@
257256
258# =============================================================================257# =============================================================================
259def gap_report():258def gap_report():
260
261 """ Provide a Report on Gaps between Activities & Needs Assessments """259 """ Provide a Report on Gaps between Activities & Needs Assessments """
262260
263 # Get all assess_summary261 # Get all assess_summary
264262
=== modified file 'controllers/req.py'
--- controllers/req.py 2011-11-07 19:55:13 +0000
+++ controllers/req.py 2011-11-18 07:40:33 +0000
@@ -37,9 +37,13 @@
37 - custom View37 - custom View
38 """38 """
3939
40 module_name = deployment_settings.modules[module].name_nice40 if s3_has_role("ADMIN"):
41 response.title = module_name41 module_name = deployment_settings.modules[module].name_nice
42 return dict(module_name=module_name)42 response.title = module_name
43 return dict(module_name=module_name)
44
45 else:
46 redirect(URL(f="req_skill"))
4347
44# -----------------------------------------------------------------------------48# -----------------------------------------------------------------------------
45def is_affiliated():49def is_affiliated():
@@ -68,10 +72,13 @@
6872
69# -----------------------------------------------------------------------------73# -----------------------------------------------------------------------------
70def req():74def req():
71 """ REST Controller """75 """ REST Controller for non-interactive ONLY"""
7276
73 # Defined in the Model for use from Multiple Controllers for unified menus77 if "rcomponents" not in request.get_vars:
74 return response.s3.req_controller()78 request.get_vars.update(rcomponents="pr_contact")
79
80 response.s3.prep = lambda r: not r.interactive
81 return s3_rest_controller("req", "req")
7582
76# =============================================================================83# =============================================================================
77def req_item():84def req_item():
@@ -135,10 +142,10 @@
135142
136 output["title"] = T("Request Item from Available Inventory")143 output["title"] = T("Request Item from Available Inventory")
137 output["req_btn"] = A( T("Return to Request"),144 output["req_btn"] = A( T("Return to Request"),
138 _href = URL( c = "req",145 _href = URL(c = "req",
139 f = "req",146 f = "req",
140 args = [req_item.req_id, "req_item"]147 args = [req_item.req_id, "req_item"]
141 ),148 ),
142 _class = "action-btn"149 _class = "action-btn"
143 )150 )
144151
@@ -301,8 +308,13 @@
301 if r.representation == "html":308 if r.representation == "html":
302 record = r.record309 record = r.record
303 if record and r.name == "commit":310 if record and r.name == "commit":
311<<<<<<< TREE
304 tabs = [(T("Edit Details"), None)]312 tabs = [(T("Edit Details"), None)]
305313
314=======
315 tabs = [(T("Details"), None)]
316
317>>>>>>> MERGE-SOURCE
306 if record.type == 1:318 if record.type == 1:
307 tabs.append((T("Items"), "commit_item"))319 tabs.append((T("Items"), "commit_item"))
308320
309321
=== modified file 'controllers/supply.py'
--- controllers/supply.py 2011-10-29 12:26:52 +0000
+++ controllers/supply.py 2011-11-18 07:40:33 +0000
@@ -87,10 +87,25 @@
87# =============================================================================87# =============================================================================
88def item():88def item():
89 """ RESTful CRUD controller """89 """ RESTful CRUD controller """
90 itable = db.supply_item
91 if "item_category_id" in request.vars:
92 itable.item_category_id.default = request.vars.item_category_id
93 itable.item_category_id.writable = False
9094
95 # LA: Hide Extra Item Fields
96 itable.code.readable = itable.code.writable = False
97 itable.brand_id.readable = itable.brand_id.writable = False
98 itable.model.readable = itable.model.writable = False
99 itable.year.readable = itable.year.writable = False
100 itable.weight.readable = itable.weight.writable = False
101 itable.length.readable = itable.length.writable = False
102 itable.width.readable = itable.width.writable = False
103 itable.height.readable = itable.height.writable = False
104 itable.volume.readable = itable.volume.writable = False
105
91 # Sort Alphabetically for the AJAX-pulled dropdown106 # Sort Alphabetically for the AJAX-pulled dropdown
92 s3mgr.configure("supply_item",107 s3mgr.configure("supply_item",
93 orderby=db.supply_item.name)108 orderby=itable.name)
94109
95 # Defined in the Model for use from Multiple Controllers for unified menus110 # Defined in the Model for use from Multiple Controllers for unified menus
96 return response.s3.supply_item_controller()111 return response.s3.supply_item_controller()
97112
=== modified file 'controllers/vol.py' (properties changed: +x to -x)
--- controllers/vol.py 2011-10-13 16:40:31 +0000
+++ controllers/vol.py 2011-11-18 07:40:33 +0000
@@ -2,8 +2,6 @@
22
3"""3"""
4 Volunteer Module4 Volunteer Module
5 - A 'My Sahana' view of an individual Volunteer's Data, Tasks, etc
6 (Ability for Anonymous users to sign-up as a Volunteer?)
7"""5"""
86
9module = request.controller7module = request.controller
@@ -19,8 +17,11 @@
19def index():17def index():
20 """ Module's Home Page """18 """ Module's Home Page """
2119
22 # Default to the Personal profile20 if s3_has_role(STAFF):
23 return person()21 response.view = "vol/index.html"
22 return dict()
23 else:
24 redirect(URL(c="vol", f="req_skill"))
2425
25# -----------------------------------------------------------------------------26# -----------------------------------------------------------------------------
26# People27# People
@@ -28,150 +29,41 @@
28def person():29def person():
29 """30 """
30 Person Controller31 Person Controller
31 - allows a person to view/update the details held about them32 - List of Volunteers
32 """33 """
3334
35 module = "pr"
34 resourcename = "person"36 resourcename = "person"
37 tablename = "pr_person"
38 table = db[tablename]
39
40 response.s3.filter = (table.volunteer == True)
3541
36 # Load Model42 # Load Model
37 s3mgr.load("pr_address")43 s3mgr.load("pr_address")
38 s3mgr.load("hrm_skill")44 s3mgr.load("vol_skill")
3945
40 s3.crud.submit_button = T("Next")46 s3mgr.model.add_component("vol_skill",
4147 pr_person="person_id")
42 s3mgr.model.add_component("hrm_certification",48
43 pr_person="person_id")49 s3mgr.configure("vol_skill",
4450 deletable = False)
45 s3mgr.model.add_component("hrm_competency",51
46 pr_person="person_id")52 tabs = [ (T("Basic Details"), None),
4753 (T("Skills"), "skill"),
48 s3mgr.model.add_component("hrm_credential",54 (T("Organizational Affiliations"), "organisation"),
49 pr_person="person_id")55 (T("Address"), "address"),
5056 (T("Contact Details"), "contact"),
51 s3mgr.model.add_component("hrm_training",57 ]
52 pr_person="person_id")58
5359 rheader = lambda r: vol_pr_rheader(r, tabs=tabs)
54 s3mgr.model.add_component("hrm_experience",60
55 pr_person="person_id")61 output = s3_rest_controller(module, resourcename, rheader=rheader)
5662
57 # Q: Are volunteers assigned to a specific organisation outside of a specific Event?
58 # Yes, some are: CERT
59 s3mgr.model.add_component("hrm_human_resource",
60 pr_person="person_id")
61
62 # Configure human resource table
63 # - for Positions
64 tablename = "hrm_human_resource"
65 table = db[tablename]
66 table.type.readable = True
67 table.type.writable = False
68 table.location_id.writable = False # Populated from pr_address
69 table.location_id.readable = False
70 s3mgr.configure(tablename,
71 list_fields=["id",
72 "organisation_id",
73 "job_title",
74 "status"])
75
76 # Configure person table
77 # - hide fields
78 tablename = "pr_person"
79 table = db[tablename]
80 table.pe_label.readable = False
81 table.pe_label.writable = False
82 table.missing.readable = False
83 table.missing.writable = False
84 table.age_group.readable = False
85 table.age_group.writable = False
86 s3mgr.configure(tablename,
87 # Wizard: Move to next Tab after Save
88 update_next = URL(args=["[id]", "address"]),
89 deletable=False)
90
91 # Configure for personal mode
92 s3.crud_strings[tablename].update(
93 title_display = T("Personal Profile"),
94 title_update = T("Personal Profile"))
95 # People can view their own HR data, but not edit it
96 db.hrm_human_resource.organisation_id.readable = True
97 s3mgr.configure("hrm_human_resource",
98 insertable = False,
99 editable = False,
100 deletable = False)
101 s3mgr.configure("hrm_certification",
102 insertable = True,
103 editable = True,
104 deletable = True)
105 s3mgr.configure("hrm_credential",
106 insertable = False,
107 editable = False,
108 deletable = False)
109 s3mgr.configure("hrm_competency",
110 insertable = True, # Can add unconfirmed
111 editable = False,
112 deletable = False)
113 s3mgr.configure("hrm_training", # Can add but not provide grade
114 insertable = True,
115 editable = False,
116 deletable = False)
117 s3mgr.configure("hrm_experience",
118 insertable = False,
119 editable = False,
120 deletable = False)
121 s3mgr.configure("pr_group_membership",
122 insertable = False,
123 editable = False,
124 deletable = False)
125 tabs = [(T("Person Details"), None),
126 (T("Addresses"), "address"),
127 (T("Certificates"), "certification"),
128 (T("Contact Information"), "contact"),
129 #(T("Skills"), "competency"),
130 #(T("Credentials"), "credential"),
131 #(T("Trainings"), "training"),
132 #(T("Mission Record"), "experience"),
133 #(T("Positions"), "human_resource"),
134 #(T("Teams"), "group_membership")
135 ]
136
137 # Prepare CRUD
138 def prep(r):
139 if r.interactive:
140 resource = r.resource
141 r.resource.build_query(id=s3_logged_in_person())
142 if resource.count() == 1:
143 resource.load()
144 r.record = resource.records().first()
145 if r.record:
146 r.id = r.record.id
147 if r.component:
148 if r.component.name == "address":
149 s3mgr.configure("pr_address",
150 create_next = URL(args=[str(r.id), "certification"]))
151 elif r.component.name == "certification":
152 r.component.table.certificate_id.comment = None
153 r.component.table.organisation_id.readable = False
154 s3mgr.configure("hrm_certification",
155 create_next = URL(args=[str(r.id), "contact"]))
156 #elif r.component.name == "contact":
157 # s3mgr.configure("pr_contact",
158 # create_next = URL(# args=[str(r.id), ""]))
159
160 return True
161 else:
162 # This controller is only for interactive use
163 redirect(URL(f='default', c="index"))
164 response.s3.prep = prep
165
166 rheader = lambda r, tabs=tabs: vol_rheader(r, tabs)
167
168 output = s3_rest_controller("pr", resourcename,
169 native=False,
170 rheader=rheader)
171 return output63 return output
17264
173# -----------------------------------------------------------------------------65# -----------------------------------------------------------------------------
174def vol_rheader(r, tabs=[]):66def vol_pr_rheader(r, tabs=[]):
175 """ Resource headers for component views """67 """ Resource headers for component views """
17668
177 rheader = None69 rheader = None
@@ -190,46 +82,2367 @@
190 TH(""),82 TH(""),
191 ""),83 ""),
19284
193 TR(TH("%s: " % T("Date of Birth")),
194 "%s" % (s3_date_represent(person.date_of_birth) or T("unknown")),
195 TH(""),
196 ""),
197
198 ), rheader_tabs)85 ), rheader_tabs)
19986
200 return rheader87 return rheader
20188
202# -----------------------------------------------------------------------------89# =============================================================================
203# Tasks90def organisation():
204# -----------------------------------------------------------------------------91 """
205def task():92 Org Controller for OrgAdmins
20693 """
207 """ Allow a volunteer to View the details of their own tasks """94
20895 table = db.org_organisation
209 tablename = "project_task"96
210 s3mgr.load(tablename)97 table.acronym.readable = False
211 table = db[tablename]98 table.acronym.writable = False
21299 org_has_vols_field = table.has_vols
213 my_person_id = s3_logged_in_person()100 org_has_vols_field.default = True
214101 response.s3.filter = (org_has_vols_field == True)
215 if not my_person_id:102
216 session.error = T("No person record found for current user.")103 if "register" in request.vars:
217 redirect(URL(f="index"))104 response.s3.show_listadd = True
218105 output = organisation_controller(organisation_rheader = organisation_rheader)
219 table.person_id.default = my_person_id106
220107 if isinstance(output, dict):
221 response.s3.filter = (table.person_id == my_person_id)108 output["title"] = T("Edit Organization Profile")
222109 return output
223 s3.crud_strings[tablename].title_list = T("My Tasks")110
224 s3.crud_strings[tablename].subtitle_list = T("Task List")111# -----------------------------------------------------------------------------
225 s3.crud_strings[tablename].msg_list_empty = T("No tasks currently assigned")112def organisation_rheader(r, tabs = []):
226113 """ Organisation rheader """
227 s3mgr.configure(tablename,114
228 insertable = False,115 if r.representation == "html":
229 editable = False,116
230 deletable = False)117 if r.record is None:
231118 # List or Create form: rheader makes no sense here
232 return s3_rest_controller("project", "task")119 return None
120
121 tabs = [(T("Basic Details"), None),
122 (T("Contacts"), "human_resource"),
123 #(T("Activities"), "activity")
124 ]
125 rheader_tabs = s3_rheader_tabs(r, tabs)
126
127 organisation = r.record
128
129 rheader = DIV(TABLE(
130 TR(
131 TH("%s: " % T("Organization")),
132 organisation.name,
133 ),
134 ),
135 rheader_tabs
136 )
137 return rheader
138 return None
139
140# =============================================================================
141def vol_sidebar():
142 """ Sidebar for people who aren't logged-in """
143
144 request.args = ["login"]
145 loginform = auth()
146 loginform.attributes["_id"] = "loginform"
147 request.args = []
148
149 if not response.menu_left:
150 response.menu_left = DIV()
151
152 if not auth.is_logged_in():
153 response.menu_left.append(
154 DIV(
155 P(T("Already registered?"),
156 BR(),
157 "%s:" % T("Sign in here")),
158 #loginform,
159 FORM(
160 LABEL(T("Email"), _for="email"),
161 INPUT(_type="text", _name="email", _title=T("Email")),
162 LABEL(T("Password"), _for="password"),
163 INPUT(_type="password", _name="password", _title=T("Password")),
164 A(SPAN(T("Sign In")),
165 _href="#",
166 _onclick="$('#sign-in-menu form').submit();",
167 _class="sign-in-button"),
168 loginform.custom.end,
169 _action="", _enctype="multipart/form-data", _method="post"),
170 _id="sign-in-menu",
171 _class="sub-menu"))
172 response.menu_left.append(
173 DIV(
174 P("%s:" % T("Other Volunteering Opportunities"), _class="osm-title"),
175 UL(
176 LI(
177 A(
178 DIV("American Red Cross", _class="link-name"),
179 DIV(
180 H3("redcrossla.org"),
181 IMG(_src="/%s/static/img/la/logo_arc.png" % request.application, _width="87", _height="29", _alt="American Red Cross Logo"),
182 P(T("Rooted in over a century's tradition of service to the community, the American Red Cross is one of the world's most renowned humanitarian organizations. American Red Cross volunteers assist with community emergency preparedness, services to the armed forces, emergency and disaster response, blood services, health and safety education, international services and other support volunteer services.")),
183 _class="other-popup"),
184 _href="http://redcrossla.org", _target="_blank",
185 _title="American Red Cross - %s" % T("Link will open to new Window"))
186 ),
187 LI(
188 A(
189 DIV("CERT", _class="link-name"),
190 DIV(
191 H3("www.cert-la.com"),
192 IMG(_src="/%s/static/img/la/logo_cert.png" % request.application, _width="101", _height="100", _alt="CERT Logo"),
193 P(T("The Los Angeles Fire Department Community Emergency Response Training Program (CERT), has been educating the citizens of Los Angeles in Disaster Preparedness since 1987.")),
194 _class="other-popup"),
195 _href="http://www.cert-la.com", _target="_blank",
196 _title="CERT - %s" % T("Link will open to new Window"))
197 ),
198 LI(
199 A(
200 DIV("LA County Disaster Healthcare Volunteers", _class="link-name"),
201 DIV(
202 H3("www.lacountydhv.org"),
203 IMG(_src="/%s/static/img/la/logo_dhv.png" % request.application, _width="88", _height="30", _alt="Disaster Healthcare Volunteers"),
204 P(T("LA County Disaster Healthcare Volunteers, comprised of 4 volunteer units, is led by the County of LA Departments of Health Services, Emergency Medical Services Agency and Public Health Emergency Preparedness and Response Program. It is specifically for licensed medical, health, mental health, and other volunteers who want to volunteer their professional skills for public health emergencies or other large scale disasters. Actively licensed health professionals are encouraged to register with one of the four units (MRC LA, LA County Surge Unit, Long Beach MRC, Beach Cities Health District MRC) on the State of California Disaster Healthcare Volunteers (DHV) site in advance of the next disaster.")),
205 _class="other-popup"),
206 _href="http://www.lacountydhv.org", _target="_blank",
207 _title="Disaster Healthcare Volunteers - %s" % T("Link will open to new Window"))
208 ),
209 LI(
210 A(
211 DIV("L.A. Works", _class="link-name"),
212 DIV(
213 H3("www.laworks.com"),
214 IMG(_src="/%s/static/img/la/laworks.png" % request.application, _width="47", _height="40", _alt="L.A. Works Logo"),
215 P(T("L.A. Works is a 501(c)3 nonprofit, volunteer action center that creates and implements hands-on community service projects throughout the greater LA area.")),
216 _class="other-popup"),
217 _href="http://www.laworks.com", _target="_blank",
218 _title="L.A. Works - %s" % T("Link will open to new Window"))
219 ),
220 LI(
221 A(
222 DIV("Public Health Emergency Volunteer Network", _class="link-name"),
223 DIV(
224 H3("publichealth.lacounty.gov"),
225 IMG(_src="/%s/static/img/la/logo_phev.png" % request.application, _width="121", _height="30", _alt="Public Health Emergency Volunteer (PHEV) Network"),
226 P(T("The purpose of the Public Health Emergency Volunteer (PHEV) Network is to increase the coordination and collaboration with established community volunteer units that are willing to assist the Department of Public Health in responding to public health emergencies by creating a system to engage, train, and deploy these groups.")),
227 _class="other-popup"),
228 _href="http://publichealth.lacounty.gov/eprp/volview.htm", _target="_blank",
229 _title="Public Health Emergency Volunteer (PHEV) Network - %s" % T("Link will open to new Window"))
230 ),
231 LI(
232 A(
233 DIV("VCLA", _class="link-name"),
234 DIV(
235 H3("www.vcla.net"),
236 IMG(_src="/%s/static/img/la/vcla.png" % request.application, _width="40", _height="40", _alt="VCLA Logo"),
237 P(T("The Volunteer Center of Los Angeles (VCLA) is one of the largest civic action centers in the nation. We are the volunteer hub that connects people, communities, resources and businesses across Los Angeles. Our mission is to change lives and communities by connecting volunteers with community needs to make Los Angeles a safer, greener, healthier and more hopeful place to live and work.")),
238 _class="other-popup"),
239 _href="http://www.vcla.net", _target="_blank",
240 _title="VCLA - %s" % T("Link will open to new Window"))
241 )
242 ),
243 _class="other-sub-menu")
244 )
245 if session.s3.debug:
246 response.s3.scripts.append( "%s/jquery.hoverIntent.js" % s3_script_dir )
247 else:
248 response.s3.scripts.append( "%s/jquery.hoverIntent.minified.js" % s3_script_dir )
249
250 response.s3.jquery_ready.append("""
251$('.other-popup').css('display', 'none');
252$('.tooltip .message').css('display', 'none');
253$('.other-sub-menu li a').hoverIntent(menuFadeIn, menuFadeOut);
254$('.tooltip a').hoverIntent(tooltipFadeIn, tooltipFadeOut);""")
255 response.s3.js_global.append("""
256// For Popup Panels for the Other Menu
257function menuFadeIn(){$(this).children('.other-popup').fadeIn();}
258function menuFadeOut(){$(this).children('.other-popup').fadeOut();}
259// For Tooltop Panels for the Other Menu
260function tooltipFadeIn(){$(this).next('.message').fadeIn();}
261function tooltipFadeOut(){$(this).next('.message').fadeOut();}""")
262
263# -----------------------------------------------------------------------------
264def register():
265 """ Custom Registration Form """
266
267 auth.messages.submit_button = T("I accept. Create my account.")
268 request.args = ["register"]
269 db[auth.settings.table_user].language.default = T.accepted_language
270 # @ToDo: Make use to the SQLFORM.createform function instead of inserting fields?
271 form = auth()
272 form.attributes["_id"] = "regform"
273 # Custom class for Submit Button
274 form[0][-1][0][0]["_class"] = "accept-button"
275
276 # Cancel button
277 form[0][-1][0].append(BR())
278 #form[0][-1][0].append(INPUT(_type="reset", _value=T("Cancel")))
279 form[0][-1][0].append(INPUT(_type="button",
280 _value=T("Cancel"),
281 _class="wide-grey-button",
282 _onClick="javascript: history.go(-1)"))
283
284 formstyle = s3.crud.formstyle
285
286 # Medical note
287 row = formstyle(id = "",
288 label = "",
289 widget = DIV("%s:" % T("If you are a Medical or Health Professional and wish to volunteer in a professional capacity, please register at"),
290 BR(),
291 A("LA County Disaster Healthcare Volunteers",
292 _href="http://www.lacountydhv.org",
293 _target="_blank"),
294 BR(),
295 BR(),
296 "%s:" % T("Individuals or Volunteer Units/Organizations interested in assisting during public health emergencies (i.e. Mass vaccine/medication dispensing sites or PODs) please register at"),
297 BR(),
298 A("LA County Department of Public Health Emergency Preparedness and Response Program",
299 _href="http://publichealth.lacounty.gov/eprp/volview.htm",
300 _target="_blank"),
301 _style="width: 400px;",
302 ),
303 comment = "")
304 form[0].insert(0, row)
305
306 # Middle Name
307 row = formstyle(id = "middle_name",
308 label = LABEL("%s:" % T("Middle Name"),
309 _for="middle_name"),
310 widget = INPUT(_name="middle_name",
311 _id="middle_name",
312 _class="string"),
313 comment = "")
314 form[0][2].append(row)
315
316 # Phone
317 phone_opts = {
318 "SMS": current.deployment_settings.get_ui_label_mobile_phone(),
319 "HOME_PHONE": T("Home phone"),
320 "WORK_PHONE": T("Work phone")
321 }
322 if form.errors.phone:
323 phone_error = DIV(form.errors.phone,
324 _id="phone__error",
325 _class="error",
326 _style="display: block;")
327 else:
328 phone_error = ""
329 phone_widget = (INPUT(_name="phone",
330 _id="",
331 _class="string"),
332 SELECT(OPTION(current.deployment_settings.get_ui_label_mobile_phone(), _value="SMS"),
333 OPTION(T("Home phone"), _value="HOME_PHONE"),
334 OPTION(T("Work phone"), _value="WORK_PHONE"),
335 requires=IS_IN_SET(phone_opts),
336 value="SMS",
337 _name="phone_type",
338 _alt="Phone Type",
339 _id="phone_type"),
340 phone_error
341 )
342 phone_help = DIV(_class="tooltip",
343 _title="%s|%s" % (T("Phone"),
344 T("if you provide your Cell phone then you can choose to subscribe to SMS notifications by selecting 'My Profile' once you have completed registration.")))
345 row = formstyle(id = "phone",
346 label = LABEL("%s:" % T("Phone"),
347 SPAN(" *", _class="req"),
348 _for="phone"),
349 widget = phone_widget,
350 comment = phone_help)
351 form[0][11].append(row)
352
353 # Address
354 if form.errors.address1:
355 address1_error = DIV(form.errors.address1,
356 _id="address1__error",
357 _class="error",
358 _style="display: block;")
359 else:
360 address1_error = ""
361 row = formstyle(id = "address1",
362 label = LABEL("%s:" % T("Address 1"),
363 SPAN(" *", _class="req"),
364 _for="address1"),
365 widget = (INPUT(_name="address1",
366 _id="address1",
367 _class="string"),
368 address1_error),
369 comment = "")
370 form[0][11].append(row)
371 row = formstyle(id = "address2",
372 label = LABEL("%s:" % T("Address 2"),
373 _for="address2"),
374 widget = INPUT(_name="address2",
375 _id="address2",
376 _class="string"),
377 comment = "")
378 form[0][11].append(row)
379 row = formstyle(id = "city",
380 label = LABEL("%s:" % T("City"),
381 SPAN(" *", _class="req"),
382 _for="city"),
383 widget = INPUT(_name="city",
384 _id = "city",
385 _class = "string"),
386 comment = "")
387 form[0][11].append(row)
388 states = S3LocationDropdownWidget(level="L1",
389 default="California",
390 empty=False)
391 widget = states(db.pr_address.location_id, None)
392 row = formstyle(id = "state",
393 label = LABEL("%s:" % T("State"),
394 SPAN(" *", _class="req"),
395 _for="location_id"),
396 widget = widget,
397 comment = "")
398 form[0][11].append(row)
399 if form.errors.zip:
400 zip_error = DIV(form.errors.zip,
401 _id="zip__error",
402 _class="error",
403 _style="display: block;")
404 else:
405 zip_error = ""
406 row = formstyle(id = "zip",
407 label = LABEL("%s:" % T("Zip"),
408 SPAN(" *", _class="req"),
409 _for="zip"
410 ),
411 widget = ( INPUT(_name="zip",
412 _id="zip",
413 _class="string"),
414 zip_error
415 ),
416 comment = "")
417 form[0][11].append(row)
418
419
420 #form[0][-2].append(TR(TD(LABEL(T("Terms of Service:"),
421 # _id="terms_of_service__label"),
422 # _class="w2p_fl"),
423 # TD(LABEL(TEXTAREA(deployment_settings.get_terms_of_service(),
424 # _onfocus="this.rows=10",
425 # _readonly="readonly",
426 # _style="width:100%;text-align:",
427 # _cols="80", _rows="10"),
428 # _id="terms_of_service"),
429 # _class="w2p_fw",
430 # _colspan="2"),
431 # _id="terms_of_service__row"))
432
433 # Eighteen
434 if form.errors.eighteen:
435 eighteen_error = DIV(form.errors.eighteen,
436 _id="eighteen__error",
437 _class="error",
438 _style="display: block;")
439 else:
440 eighteen_error = ""
441 label = LABEL(#"%s:" % T("I am 18 or over"),
442 T("I am 18 or over"),
443 SPAN(" *", _class="req"),
444 _for="eighteen",
445 _style="display: inline;",
446 _id="eighteen__label")
447 widget = INPUT(_type="checkbox",
448 _value="on",
449 _name="eighteen",
450 _id="eighteen",
451 _class="boolean")
452 #row = formstyle(id = "eighteen",
453 # label = label,
454 # widget = (widget,
455 # eighteen_error),
456 # comment = "")
457 row = TR(TD(widget, label, eighteen_error),
458 TD(),
459 _id="eighteen")
460 form[0][-2].append(row)
461
462 # US Citizen
463 if form.errors.citizen:
464 citizen_error = DIV(form.errors.citizen,
465 _id="citizen__error",
466 _class="error",
467 _style="display: block;")
468 else:
469 citizen_error = ""
470 label = LABEL(#"%s:" % T("I am a U.S. Citizen"),
471 T("I am a U.S. Citizen"),
472 SPAN(" *", _class="req"),
473 _for="citizen",
474 _style="display: inline;",
475 _id="citizen__label")
476 widget = INPUT(_type="checkbox",
477 _value="on",
478 _name="citizen",
479 _id="citizen",
480 _class="boolean")
481 #row = formstyle(id = "citizen",
482 # label = label,
483 # widget = (widget,
484 # citizen_error),
485 # comment = "")
486 row = TR(TD(widget, label, citizen_error),
487 TD(),
488 _id="citizen")
489 form[0][-2].append(row)
490
491 # Privacy Policy
492 row = formstyle(id = "",
493 label = "",
494 widget = DIV(XML(T("By clicking on 'I accept' below you are agreeing to the %(privacy_policy)s.") % \
495 dict(privacy_policy = A(T("Privacy Policy"),
496 _href = URL(c="default",
497 f="disclaimer#privacy"),
498 _target = "_blank"
499 )
500 )
501 ),
502 _style="width: 300px;",
503 ),
504 comment = "")
505 form[0][-2].append(row)
506
507 # Add client-side validation
508 # simplified copy of s3_register_validation()
509 script = "".join(( """
510var required = '""", str(T("This field is required.")), """';
511$('#regform').validate({
512 errorClass: 'req',
513 rules: {
514 first_name: {
515 required: true
516 },
517 last_name: {
518 required: true
519 },
520 phone: {
521 required: true
522 },
523 email: {
524 required: true,
525 email: true
526 },
527 address1: {
528 required: true
529 },
530 city: {
531 required: true
532 },
533 zip: {
534 required: true
535 },
536 password: {
537 required: true
538 },
539 password_two: {
540 required: true,
541 equalTo: '.password:first'
542 },
543 eighteen: {
544 required: true
545 },
546 citizen: {
547 required: true
548 }
549 },
550 messages: {
551 first_name: '""", str(T("Enter your firstname")), """',
552 last_name: required,
553 phone: required,
554 email: {
555 required: '""", str(T("Please enter a valid email address")), """',
556 minlength: '""", str(T("Please enter a valid email address")), """'
557 },
558 address1: required,
559 city: required,
560 zip: required,
561 password: {
562 required: '""", str(T("Provide a password")), """'
563 },
564 password_two: {
565 required: '""", str(T("Repeat your password")), """',
566 equalTo: '""", str(T("Enter the same password as above")), """'
567 },
568 eighteen: '""", str(T("If you are under the age 18, you may not register to apply to be a volunteer. Thank you for your interest in our volunteer opportunities.")), """',
569 citizen: '""", str(T("If you are not a US citizen, you may not register to apply to be a volunteer. Thank you for your interest in our volunteer opportunities.")), """',
570 },
571 errorPlacement: function(error, element) {
572 error.appendTo( element.parent().next() );
573 },
574 submitHandler: function(form) {
575 form.submit();
576 }
577});""" ))
578 response.s3.jquery_ready.append( script )
579
580 if session.s3.debug:
581 response.s3.scripts.append( "%s/jquery.validate.js" % s3_script_dir )
582 response.s3.scripts.append( "%s/jquery.pstrength.1.3.js" % s3_script_dir )
583 else:
584 response.s3.scripts.append( "%s/jquery.validate.min.js" % s3_script_dir )
585 response.s3.scripts.append( "%s/jquery.pstrength.1.3.min.js" % s3_script_dir )
586
587 response.s3.jquery_ready.append("$('.password:first').pstrength();\n")
588 response.s3.js_global.append("".join((
589 "S3.i18n.password_chars = '%s';\n" % T("The minimum number of characters is "),
590 "S3.i18n.very_weak = '%s';\n" % T("Very Weak"),
591 "S3.i18n.weak = '%s';\n" % T("Weak"),
592 "S3.i18n.medium = '%s';\n" % T("Medium"),
593 "S3.i18n.strong = '%s';\n" % T("Strong"),
594 "S3.i18n.very_strong = '%s';\n" % T("Very Strong"),
595 "S3.i18n.too_short = '%s';\n" % T("Too Short"),
596 "S3.i18n.unsafe_password = '%s';\n" % T("Unsafe Password Word!"),
597 )))
598
599 # Add sidebar for login box & other volunteering opportunities
600 vol_sidebar()
601
602 response.s3.donate_cash_link = True
603
604 response.title = T("Register")
605 response.s3.has_required = True
606
607 return dict(form=form)
608
609# -----------------------------------------------------------------------------
610def register_validation(form):
611 """ Validate the custom fields in registration form """
612 # Terms of Service
613 if "eighteen" not in request.post_vars or request.post_vars.eighteen != "on":
614 form.errors.eighteen = T("If you are under the age 18, you may not register to apply to be a volunteer. Thank you for your interest in our volunteer opportunities.")
615 if "citizen" not in request.post_vars or request.post_vars.citizen != "on":
616 form.errors.citizen = T("If you are not a U.S. citizen, you may not register to apply to be a volunteer. Thank you for your interest in our volunteer opportunities.")
617 # Phone
618 if "phone" in request.post_vars and request.post_vars.phone:
619 regex = re.compile(single_phone_number_pattern)
620 if not regex.match(request.post_vars.phone):
621 form.errors.phone = T("Invalid phone number")
622 else:
623 form.errors.phone = T("Phone number is required")
624 # Address
625 if not request.post_vars.address1:
626 form.errors.address1 = T("Address is required")
627 if not request.post_vars.city:
628 form.errors.city = T("City is required")
629 if not request.post_vars.zip:
630 form.errors.zip = T("Zip is required")
631
632 return
633
634# -----------------------------------------------------------------------------
635def register_onaccept(form):
636 # Usual Registration Tasks
637 # (PR record, Authenticated Role, Contacts)
638 person = auth.s3_register(form)
639
640 # LA-specific
641 table = db.pr_person
642 query = (table.id == person)
643
644 db(query).update(volunteer=True,
645 middle_name=request.post_vars.middle_name)
646
647 pe = db(query).select(table.pe_id,
648 limitby=(0, 1)).first().pe_id
649
650 # Phone
651 table = db.pr_contact
652 phone = request.post_vars.phone
653 phone_type = request.post_vars.phone_type
654 # Don't auto-subscribe to SMS (priority 10)
655 table.insert(pe_id = pe,
656 contact_method = phone_type,
657 value = phone,
658 priority=10)
659
660 # Address
661 table = db.gis_location
662 address1 = request.post_vars.address1
663 address2 = request.post_vars.address2
664 if address2:
665 address = "%s\n%s" % (address1,
666 address2)
667 else:
668 address = address1
669 city = request.post_vars.city
670 location = request.post_vars.location_id
671 state = db(table.id == location).select(table.id,
672 table.name,
673 cache=gis.cache,
674 limitby=(0, 1)).first()
675 if state:
676 statename = state.name
677 else:
678 # Duff data - not USA
679 statename = "unknown"
680 zip = request.post_vars.zip
681 county = ""
682 if city:
683 query = (table.name == city) & \
684 (table.level == "L3") & \
685 (table.path.like("%%/%s/%%" % state))
686 _city = db(query).select(table.id,
687 table.parent,
688 limitby=(0, 1)).first()
689 if _city:
690 if _city.parent != state:
691 query = (table.id == _city.parent)
692 county = db(query).select(table.name,
693 limitby=(0, 1)).first().name
694 elif state:
695 _city = table.insert(name=city, level="L3", parent=state.id)
696 gis.update_location_tree(_city, state.id)
697 else:
698 usa = db(table.code == "US").select(table.id,
699 limitby=(0, 1)).first().id
700 _city = table.insert(name=city, level="L3", parent=usa)
701 gis.update_location_tree(_city, usa)
702 else:
703 _city = None
704 location = table.insert(addr_street=address, addr_postcode=zip, parent=_city)
705 gis.update_location_tree(location, _city)
706 s3mgr.load("pr_address")
707 table = db.pr_address
708 table.insert(pe_id = pe,
709 location_id = location,
710 address=address,
711 postcode=zip,
712 L3=city,
713 L2=county,
714 L1=statename,
715 L0="United States")
716
717# -----------------------------------------------------------------------------
718auth.settings.register_onvalidation = register_validation
719auth.settings.register_onaccept = register_onaccept
720auth.settings.register_next = URL(c="vol", f="skill", args=["create"])
721
722# Organisation widget for use in Registration Screen
723# NB User Profile is only editable by Admin - using User Management
724org_widget = IS_ONE_OF(db, "org_organisation.id",
725 organisation_represent,
726 orderby="org_organisation.name",
727 sort=True)
728if deployment_settings.get_auth_registration_organisation_mandatory():
729 _table_user.organisation_id.requires = org_widget
730else:
731 _table_user.organisation_id.requires = IS_NULL_OR(org_widget)
732
733# =============================================================================
734def profile():
735 """ Custom Profile Screen """
736
737 if not auth.is_logged_in():
738 redirect(URL(f="user", args="login"))
739 elif s3_has_role(ORG_VOL):
740 #return organisation_profile()
741 redirect(URL(f="organisation", args=[auth.user.organisation_id]))
742
743 # Only show admin-set fields if there is data
744 table = db.auth_user
745 if not auth.user.organisation_id:
746 # Not relevant to Volunteers
747 table.organisation_id.readable = False
748 if not auth.user.site_id:
749 # Only relevant to Field Staff
750 table.site_id.readable = False
751
752 # Validate the custom fields
753 auth.settings.profile_onvalidation = profile_validation
754
755 # Process the custom fields
756 auth.settings.profile_onaccept = profile_onaccept
757
758 auth.messages.profile_save_button = "Save"
759
760 request.args = ["profile"]
761 form = auth()
762
763 # Custom class for Submit Button
764 form[0][-1][1][0]["_class"] = "submit-button"
765
766 # Lookup the Person
767 id = auth.s3_logged_in_person()
768 table = db.pr_person
769 person = db(table.id == id).select(table.pe_id,
770 table.middle_name,
771 table.volunteer,
772 limitby=(0, 1)).first()
773
774 row = TR(TD(LABEL("%s:" % table.middle_name.label, _for="middle_name")),
775 TD(INPUT(_name="middle_name",
776 _id="middle_name",
777 _class="string",
778 _value=person.middle_name)))
779 form[0][0].append(row)
780
781 # Lookup the Contacts
782 table = db.pr_contact
783 query = (table.pe_id == person.pe_id) & \
784 (table.deleted == False)
785 contacts = db(query).select(table.contact_method,
786 table.value,
787 table.priority)
788 cell = ""
789 home = ""
790 work = ""
791 sms_enabled = False
792 email_enabled = True
793 for contact in contacts:
794 if contact.contact_method == "SMS":
795 cell = contact.value
796 if contact.priority == 10:
797 sms_enabled = False
798 else:
799 sms_enabled = True
800 elif contact.contact_method == "EMAIL":
801 if contact.priority == 10:
802 email_enabled = False
803 else:
804 email_enabled = True
805 elif contact.contact_method == "HOME_PHONE":
806 home = contact.value
807 elif contact.contact_method == "WORK_PHONE":
808 work = contact.value
809
810 # Cell phone
811 if form.errors.mobile:
812 cell_error = DIV(form.errors.mobile,
813 _id="mobile__error",
814 _class="error",
815 _style="display: block;")
816 else:
817 cell_error = ""
818 row = TR(TD(LABEL("%s:" % msg.CONTACT_OPTS["SMS"], _for="mobile")),
819 TD(INPUT(_name="mobile",
820 _id="mobile",
821 _class="string",
822 _value=cell),
823 cell_error))
824 form[0][2].append(row)
825 # @ToDo: JS validation
826
827 if person.volunteer:
828 # Home phone
829 if form.errors.home_phone:
830 home_phone_error = DIV(form.errors.home_phone,
831 _id="home_phone__error",
832 _class="error",
833 _style="display: block;")
834 else:
835 home_phone_error = ""
836 row = TR(TD(LABEL("%s:" % msg.CONTACT_OPTS["HOME_PHONE"], _for="home_phone")),
837 TD(INPUT(_name="home_phone",
838 _id="home_phone",
839 _class="string",
840 _value=home),
841 home_phone_error))
842 form[0][2].append(row)
843 # @ToDo: JS validation
844
845 # Work phone
846 if form.errors.work_phone:
847 work_phone_error = DIV(form.errors.work_phone,
848 _id="work_phone__error",
849 _class="error",
850 _style="display: block;")
851 else:
852 work_phone_error = ""
853 row = TR(TD(LABEL("%s:" % msg.CONTACT_OPTS["WORK_PHONE"], _for="work_phone")),
854 TD(INPUT(_name="work_phone",
855 _id="work_phone",
856 _class="string",
857 _value=work),
858 work_phone_error))
859 form[0][2].append(row)
860 # @ToDo: JS validation
861
862 # Lookup the Address
863 table = db.pr_address
864 query = (table.pe_id == person.pe_id) & \
865 (table.deleted == False)
866 address = db(query).select(table.location_id,
867 limitby=(0, 1)).first()
868 address1 = ""
869 address2 = ""
870 city = ""
871 state = ""
872 zip = ""
873 if address:
874 table = db.gis_location
875 query = (table.id == address.location_id)
876 location = db(query).select(table.id,
877 table.path,
878 table.parent,
879 table.addr_street,
880 table.addr_postcode,
881 limitby=(0, 1)).first()
882 if location:
883 try:
884 address1, address2 = location.addr_street.split("\n", 1)
885 except ValueError:
886 address1 = location.addr_street
887 zip = location.addr_postcode
888 results = gis.get_parent_per_level(None, location.id, location)
889 try:
890 city = results["L3"].name
891 #except KeyError, AttributeError:
892 except:
893 pass
894 try:
895 state = results["L1"].name
896 #except KeyError, AttributeError:
897 except:
898 pass
899
900 if form.errors.address1:
901 address1_error = DIV(form.errors.address1,
902 _id="address1__error",
903 _class="error",
904 _style="display: block;")
905 else:
906 address1_error = ""
907 row = TR(TD(LABEL("%s: " % T("Address 1"),
908 SPAN("*", _class="req"),
909 _for="address1")),
910 TD(INPUT(_name="address1",
911 _id="address1",
912 _class="string",
913 _value=address1),
914 address1_error))
915 form[0][2].append(row)
916 row = TR(TD(LABEL("%s:" % T("Address 2"), _for="address2")),
917 TD(INPUT(_name="address2",
918 _id="address2",
919 _class="string",
920 _value=address2)))
921 form[0][2].append(row)
922 row = TR(TD(LABEL("%s: " % T("City"),
923 SPAN("*", _class="req"),
924 _for="city")),
925 TD(INPUT(_name="city",
926 _id="city",
927 _class="string",
928 _value=city)))
929 form[0][2].append(row)
930 states = S3LocationDropdownWidget(level="L1",
931 default=state or "California",
932 empty=False)
933 widget = states(db.pr_address.location_id, None)
934 row = TR(TD(LABEL("%s:" % T("State"),
935 SPAN("*", _class="req"),
936 _for="location_id")),
937 TD(widget))
938 form[0][2].append(row)
939 if form.errors.zip:
940 zip_error = DIV(form.errors.zip,
941 _id="zip__error",
942 _class="error",
943 _style="display: block;")
944 else:
945 zip_error = ""
946 row = TR(TD(LABEL("%s:" % T("Zip"),
947 SPAN("*", _class="req"),
948 _for="zip")),
949 TD(INPUT(_name="zip",
950 _id="zip",
951 _class="string",
952 _value=zip),
953 zip_error))
954 form[0][2].append(row)
955
956 # Notifications
957 div = DIV(TR(TD(LABEL("%s:" % T("Notifications"))),
958 TD()
959 ),
960 TR(TD(T("Receive Notifications via Email?")),
961 TD(INPUT(_type="checkbox",
962 _value="on",
963 value="on" if email_enabled else "",
964 _name="sub_email",
965 _id="sub_email",
966 _alt=T("Receive Notifications via Email?"),
967 _class="boolean"))
968 ),
969 TR(TD(T("Receive Notifications via SMS?")),
970 TD(INPUT(_type="checkbox",
971 _value="on",
972 value="on" if sms_enabled else "",
973 _name="sub_sms",
974 _id="sub_sms",
975 _alt=T("Receive Notifications via SMS?"),
976 _class="boolean")),
977 TD(DIV(_class="tooltip",
978 _title="%s|%s" % (T("Receive Notifications via SMS"),
979 T("Note that this may incur costs from your carrier."))))
980 )
981 )
982 form[0][-2].append(div)
983
984 # Affiliated Orgs
985 s3mgr.load("vol_organisation")
986 table = db.vol_organisation
987 orgs = db(table.pe_id == person.pe_id).select(table.organisations_id,
988 limitby=(0, 1)).first()
989 if orgs:
990 orgs = orgs.organisations_id
991 table = db.org_organisation
992 if orgs:
993 _orgs = db(table.id.belongs(orgs)).select(table.name)
994 else:
995 _orgs = []
996 orgs = []
997 for org in _orgs:
998 orgs.append(org.name)
999 else:
1000 orgs = []
1001
1002 div = DIV(TR(TD(),
1003 TD(B(T("Affiliation with other volunteer organizations")))),
1004 TR(TD(T("Are you affiliated with other volunteer organizations?"),
1005 " (", DIV(T("Check all that apply"),
1006 _style="display: inline;",
1007 _class="red"),
1008 ")",
1009 _colspan=2)),
1010 TR(TD("American Red Cross"),
1011 TD(INPUT(_type="checkbox",
1012 _value="on",
1013 value="on" if "American Red Cross of Greater Los Angeles" in orgs else "",
1014 _name="arc",
1015 _id="arc",
1016 _alt=T("American Red Cross"),
1017 _class="boolean"))),
1018 TR(TD("CERT"),
1019 TD(INPUT(_type="checkbox",
1020 _value="on",
1021 value="on" if "CERT Los Angeles" in orgs else "",
1022 _name="cert",
1023 _id="cert",
1024 _alt=T("CERT"),
1025 _class="boolean"))),
1026 TR(TD("Disaster Healthcare Volunteers"),
1027 TD(INPUT(_type="checkbox",
1028 _value="on",
1029 value="on" if "Disaster Healthcare Volunteers" in orgs else "",
1030 _name="dhv",
1031 _id="dhv",
1032 _alt=T("Disaster Healthcare Volunteers"),
1033 _class="boolean"))),
1034 TR(TD("L.A. Works"),
1035 TD(INPUT(_type="checkbox",
1036 _value="on",
1037 value="on" if "LA Works" in orgs else "",
1038 _name="laworks",
1039 _id="laworks",
1040 _alt=T("L.A. Works"),
1041 _class="boolean"))),
1042 TR(TD("Volunteer Center of Los Angeles"),
1043 TD(INPUT(_type="checkbox",
1044 _value="on",
1045 value="on" if "Volunteer Center of Los Angeles" in orgs else "",
1046 _name="vcla",
1047 _id="vcla",
1048 _alt=T("Volunteer Center of Los Angeles"),
1049 _class="boolean"))),
1050 )
1051 form[0][-2].append(div)
1052
1053 # Skills
1054 # - separate screen
1055
1056 response.title = T("Profile")
1057 response.s3.has_required = True
1058
1059 return dict(form=form)
1060
1061# -----------------------------------------------------------------------------
1062def profile_validation(form):
1063 """ Validate the custom fields in profile form """
1064
1065 if s3_has_role(STAFF):
1066 volunteer = False
1067 else:
1068 volunteer = True
1069
1070 # Mobile Phone
1071 if "mobile" in request.post_vars and request.post_vars.mobile:
1072 regex = re.compile(single_phone_number_pattern)
1073 if not regex.match(request.post_vars.mobile):
1074 form.errors.mobile = T("Invalid phone number")
1075 elif "sub_sms" in request.post_vars and request.post_vars.sub_sms == "on":
1076 form.errors.mobile = T("Cell phone number is required for SMS notifications")
1077 # Home Phone
1078 if "home_phone" in request.post_vars and request.post_vars.home_phone:
1079 regex = re.compile(single_phone_number_pattern)
1080 if not regex.match(request.post_vars.home_phone):
1081 form.errors.home_phone = T("Invalid phone number")
1082 # Work Phone
1083 if "work_phone" in request.post_vars and request.post_vars.work_phone:
1084 regex = re.compile(single_phone_number_pattern)
1085 if not regex.match(request.post_vars.work_phone):
1086 form.errors.work_phone = T("Invalid phone number")
1087 # Address
1088 if volunteer and not request.post_vars.address1:
1089 form.errors.address1 = T("Address is required")
1090 if volunteer and not request.post_vars.zip:
1091 form.errors.zip = T("Zip is required")
1092
1093 return
1094
1095# -----------------------------------------------------------------------------
1096def profile_onaccept(form):
1097 """ Process the custom fields """
1098
1099 if s3_has_role(STAFF):
1100 volunteer = False
1101 else:
1102 volunteer = True
1103
1104 table = db.pr_person
1105 query = (table.id == auth.s3_logged_in_person())
1106 db(query).update(middle_name=request.post_vars.middle_name)
1107 pe = db(query).select(table.pe_id,
1108 limitby=(0, 1)).first().pe_id
1109
1110 if volunteer:
1111 # Contacts / Notifications
1112 if "sub_email" in request.post_vars and \
1113 request.post_vars.sub_email == "on":
1114 email_enabled = True
1115 else:
1116 email_enabled = False
1117 if "sub_sms" in request.post_vars and \
1118 request.post_vars.sub_sms == "on":
1119 sms_enabled = True
1120 else:
1121 sms_enabled = False
1122 home_phone = request.post_vars.home_phone
1123 work_phone = request.post_vars.work_phone
1124 email = request.post_vars.email
1125 cell = request.post_vars.mobile
1126 table = db.pr_contact
1127 if email:
1128 utable = db.auth_user
1129 query = (utable.id == auth.user.id)
1130 _email = db(query).select(utable.email,
1131 limitby=(0, 1)).first().email
1132 if not _email == email:
1133 # Email has changed
1134 # Check that the new email doesn't clash
1135 query2 = (utable.email == email)
1136 test = db(query2).select(utable.id,
1137 limitby=(0, 1)).first()
1138 if not test:
1139 # update auth_user
1140 db(query).update(email=email)
1141 # update pr_contact
1142 query = (table.value == _email)
1143 if volunteer:
1144 priority = 1 if email_enabled else 10
1145 db(query).update(value=email, priority=priority)
1146 else:
1147 db(query).update(value=email)
1148 else:
1149 # Existing .requires validation prevents the user from reusing
1150 # an existing email
1151 pass
1152 elif volunteer:
1153 # Just update the notifications
1154 query = (table.value == email)
1155 priority = 1 if email_enabled else 10
1156 db(query).update(priority=priority)
1157
1158 _cell = ""
1159 _home_phone = ""
1160 _work_phone = ""
1161 query = (table.pe_id == pe) & \
1162 (table.deleted == False)
1163 contacts = db(query).select(table.contact_method,
1164 table.value)
1165 for contact in contacts:
1166 if contact.contact_method == "SMS":
1167 _cell = contact.value
1168 elif contact.contact_method == "HOME_PHONE":
1169 _home_phone = contact.value
1170 elif contact.contact_method == "WORK_PHONE":
1171 _work_phone = contact.value
1172 table = db.pr_contact
1173 base_query = (table.pe_id == pe)
1174 if volunteer:
1175 priority = 1 if sms_enabled else 10
1176 if _cell:
1177 # Update existing record
1178 query = base_query & (table.value == _cell)
1179 db(query).update(value=cell, priority=priority)
1180 elif cell:
1181 # Insert new record
1182 table.insert(pe_id=pe, contact_method="SMS", value=cell,
1183 priority=priority)
1184 if _home_phone:
1185 # Update existing record
1186 query = base_query & (table.value == _home_phone)
1187 db(query).update(value=home_phone)
1188 elif home_phone:
1189 # Insert new record
1190 table.insert(pe_id=pe, contact_method="HOME_PHONE",
1191 value=home_phone)
1192
1193 if _work_phone:
1194 # Update existing record
1195 query = base_query & (table.value == _work_phone)
1196 db(query).update(value=work_phone)
1197 elif work_phone:
1198 # Insert new record
1199 table.insert(pe_id=pe, contact_method="WORK_PHONE",
1200 value=work_phone)
1201
1202 # Address
1203 address1 = request.post_vars.address1
1204 address2 = request.post_vars.address2
1205 if address2:
1206 address = "%s\n%s" % (address1, address2)
1207 else:
1208 address = address1
1209 zip = request.post_vars.zip
1210 city = request.post_vars.city
1211 state = request.post_vars.location_id
1212 table = db.gis_location
1213 statename = db(table.id == state).select(table.name,
1214 cache=gis.cache,
1215 limitby=(0, 1)).first().name
1216 county = ""
1217 if city:
1218 query = (table.name == city) & \
1219 (table.level == "L3") & \
1220 (table.path.like("%%/%s/%%" % state))
1221 _city = db(query).select(table.id,
1222 table.parent,
1223 limitby=(0, 1)).first()
1224 if _city:
1225 if _city.parent != state:
1226 query = (table.id == _city.parent)
1227 county = db(query).select(table.name,
1228 limitby=(0, 1)).first().name
1229 else:
1230 _city = table.insert(name=city, level="L3", parent=state)
1231 gis.update_location_tree(_city, state)
1232 else:
1233 _city = None
1234 table = db.pr_address
1235 query = (table.pe_id == pe) & \
1236 (table.deleted == False)
1237 test = db(query).select(table.location_id,
1238 limitby=(0, 1)).first()
1239 if test:
1240 db(query).update(address=address,
1241 postcode=zip,
1242 L3=city,
1243 L2=county,
1244 L1=statename,
1245 L0="United States")
1246 table = db.gis_location
1247 location = test.location_id
1248 query = (table.id == location)
1249 db(query).update(addr_street=address,
1250 addr_postcode=zip,
1251 parent=_city)
1252 gis.update_location_tree(location, _city)
1253
1254 # Affiliated Organisations
1255 # Also in models/vol.py
1256 vol_orgs = ["American Red Cross of Greater Los Angeles",
1257 "CERT Los Angeles",
1258 "Disaster Healthcare Volunteers",
1259 "LA Works",
1260 "Volunteer Center of Los Angeles"]
1261 table = db.org_organisation
1262 query = (table.name.belongs(vol_orgs))
1263 orgs = db(query).select(table.id,
1264 table.name,
1265 cache=(cache.ram, 60))
1266 for org in orgs:
1267 if org.name == "American Red Cross of Greater Los Angeles":
1268 ARC = org.id
1269 elif org.name == "CERT Los Angeles":
1270 CERT = org.id
1271 elif org.name == "Disaster Healthcare Volunteers":
1272 DHV = org.id
1273 elif org.name == "LA Works":
1274 LAW = org.id
1275 elif org.name == "Volunteer Center of Los Angeles":
1276 VCLA = org.id
1277 orgs = []
1278 if "arc" in request.post_vars and request.post_vars.arc == "on":
1279 orgs.append(ARC)
1280 if "cert" in request.post_vars and request.post_vars.cert == "on":
1281 orgs.append(CERT)
1282 if "dhv" in request.post_vars and request.post_vars.dhv == "on":
1283 orgs.append(DHV)
1284 if "laworks" in request.post_vars and \
1285 request.post_vars.laworks == "on":
1286 orgs.append(LAW)
1287 if "vcla" in request.post_vars and request.post_vars.vcla == "on":
1288 orgs.append(VCLA)
1289 s3mgr.load("vol_organisation")
1290 table = db.vol_organisation
1291 query = (table.pe_id == pe)
1292 test = db(query).select(table.id,
1293 limitby=(0, 1)).first()
1294 if test:
1295 db(query).update(organisations_id = orgs)
1296 else:
1297 table.insert(pe_id = pe,
1298 organisations_id = orgs,
1299 owned_by_user = auth.user.id)
1300
1301 else:
1302 # Not a volunteer: EOC staff
1303 if _cell:
1304 # Update existing record
1305 query = base_query & (table.value == _cell)
1306 db(query).update(value=cell)
1307 elif cell:
1308 # Insert new record
1309 table.insert(pe_id=pe, contact_method="SMS", value=cell)
1310
1311# -----------------------------------------------------------------------------
1312# Skills
1313# -----------------------------------------------------------------------------
1314def skill():
1315 """
1316 Collect a Volunteer's Skills
1317 """
1318
1319 tablename = "vol_skill"
1320 s3mgr.load(tablename)
1321 table = db[tablename]
1322
1323 person = auth.s3_logged_in_person()
1324 table.person_id.default = person
1325 table.person_id.writable = table.person_id.readable = False
1326
1327 s3mgr.configure(tablename,
1328 # Workflow: Prompt for creating Emergency Contacts after adding Skills
1329 create_next = URL(f="contact", args=["my"]),
1330 update_next = URL(f="skill", args=["my"]),
1331 deletable = False,
1332 listadd = False)
1333
1334 # Parse the request
1335 if "my" in request.args:
1336 query = (table.person_id == person)
1337 record = db(query).select(table.id,
1338 limitby=(0, 1),
1339 cache = gis.cache).first()
1340 if record:
1341 r = s3mgr.parse_request(args=[str(record.id)])
1342 else:
1343 r = s3mgr.parse_request(args=["create"])
1344 else:
1345 r = s3mgr.parse_request()
1346
1347 # Execute the request
1348 output = r()
1349
1350 response.title = T("My Skills")
1351 return output
1352
1353# -----------------------------------------------------------------------------
1354# Contacts
1355# -----------------------------------------------------------------------------
1356def contact():
1357 """
1358 Emergency Contacts for the volunteer
1359 """
1360
1361 tablename = "vol_contact"
1362 s3mgr.load(tablename)
1363 table = db[tablename]
1364
1365 person = auth.s3_logged_in_person()
1366 table.person_id.default = person
1367 table.person_id.writable = table.person_id.readable = False
1368
1369 s3mgr.configure(tablename,
1370 create_next = URL(f="req_skill"),
1371 update_next = URL(f="contact", args=["my"]),
1372 deletable = False,
1373 listadd = False)
1374
1375 # Parse the request
1376 if "my" in request.args:
1377 query = (table.person_id == person)
1378 record = db(query).select(table.id,
1379 limitby=(0, 1)).first()
1380 if record:
1381 r = s3mgr.parse_request(args=[str(record.id)])
1382 else:
1383 r = s3mgr.parse_request(args=["create"])
1384 else:
1385 r = s3mgr.parse_request()
1386
1387 # Execute the request
1388 output = r()
1389
1390 response.title = T("Emergency Contact")
1391 return output
1392
1393# -----------------------------------------------------------------------------
1394# Assignments
1395# - My Assignments menu
1396# -----------------------------------------------------------------------------
1397def assignment():
1398
1399 """ Allow a Volunteer/Org to View the details of their own assignments """
1400
1401 tablename = "vol_assignment"
1402 s3mgr.load(tablename)
1403 table = db[tablename]
1404
1405 if auth.user.organisation_id:
1406 response.s3.filter = (table.organisation_id == auth.user.organisation_id)
1407 # Control List View
1408 table.person_id.readable = False
1409 table.number.readable = True
1410 table.number.label = T("Number of Volunteers Committed")
1411 else:
1412 my_person_id = s3_logged_in_person()
1413 # Control List View
1414 table.person_id.readable = False
1415
1416 if not my_person_id:
1417 session.error = T("No person record found for current user.")
1418 redirect(URL(f="index"))
1419
1420 response.s3.filter = (table.person_id == my_person_id)
1421
1422 # Filter for current/past assignments
1423 sel = ((table.checkout == None) |
1424 (table.checkout >= request.utcnow) |
1425 (table.task_evaluation == None))
1426 s3.crud_strings[tablename].update(
1427 subtitle_list = T("Current Assignments"))
1428 if "show" in request.get_vars:
1429 show = request.get_vars["show"]
1430 if show == "past":
1431 sel = ((table.checkout < request.utcnow) &
1432 (table.task_evaluation != None))
1433 s3.crud_strings[tablename].update(
1434 subtitle_list = T("Past Assignments"),
1435 msg_no_match = T("No past assignments"))
1436 response.s3.filter &= sel
1437
1438 # Post-process
1439 def postp(r, output):
1440 if r.interactive:
1441 response.s3.actions = [dict(
1442 url = URL(c = "vol",
1443 f = "req",
1444 args = ["assignment", "[id]"]),
1445 _class = "action-btn",
1446 label = str(T("Details"))
1447 )]
1448 if "show" in request.get_vars and request.get_vars["show"] == "past":
1449 response.s3.actions += [dict(
1450 url = URL(c=request.controller,
1451 f="req",
1452 args=["assignment",
1453 "[id]",
1454 "print"]),
1455 _class = "action-btn",
1456 label = str(T("Certificate"))
1457 )]
1458
1459 return output
1460 response.s3.postp = postp
1461
1462 output = s3_rest_controller("vol", "assignment")
1463 return output
1464
1465# -----------------------------------------------------------------------------
1466# Requests
1467# -----------------------------------------------------------------------------
1468def vol_req_rheader(r):
1469 """
1470 Resource Header for Requests
1471 - Volunteer view
1472 - inc Volunteer Roster
1473 """
1474
1475 if r.representation == "html":
1476 if r.name == "req":
1477 record = r.record
1478 if record:
1479 if s3_has_role(STAFF):
1480 # Show Tabs on Roster
1481 tabs = [(T("Details"), None)]
1482 if record.type == 3 and deployment_settings.has_module("hrm"):
1483 tabs.append((T("Requested Volunteers"), "req_skill"))
1484 if deployment_settings.has_module("doc"):
1485 tabs.append((T("Documents"), "document"))
1486 #if deployment_settings.get_req_use_commit():
1487 # tabs.append((T("Commitments"), "commit"))
1488 tabs.append((T("Roster"), "assignment"))
1489 try:
1490 # Remove the default_type from URLs as set within respective controller
1491 r.vars.pop("default_type")
1492 except KeyError:
1493 pass
1494 rheader_tabs = s3_rheader_tabs(r, tabs)
1495 elif not r.component:
1496 # Volunteers should only ever access Requests via the Components
1497 return
1498
1499 table = db.req_req_skill
1500 query = (table.req_id == record.id)
1501 srecord = db(query).select(table.skill_id,
1502 table.quantity,
1503 table.quantity_commit,
1504 limitby=(0, 1)).first()
1505 if srecord:
1506 skills = response.s3.hrm_multi_skill_represent(srecord.skill_id)
1507 requested = srecord.quantity
1508 required = srecord.quantity - srecord.quantity_commit
1509 else:
1510 skills = requested = required = ""
1511
1512 address = shn_site_represent(record.site_id, address=True)
1513 #table = db.org_office
1514 #query = (table.id == record.site_id)
1515 #srecord = db(query).select(table.name,
1516 # table.address,
1517 # table.postcode,
1518 # table.L3,
1519 # table.L1,
1520 # limitby=(0, 1)).first()
1521 #if srecord:
1522 # location = T("%(site)s in %(location)s") % dict(site = srecord.name,
1523 # location = record.location)
1524 # ltable = db.gis_location
1525 # query = (ltable.name == srecord.L1)
1526 # state = db(query).select(ltable.code,
1527 # limitby=(0, 1),
1528 # cache=gis.cache).first()
1529 # if state:
1530 # statecode = state.code
1531 # else:
1532 # # Not valid US data (e.g. prepopulate)
1533 # statecode = None
1534 # address = "%s, %s %s %s" % (srecord.address,
1535 # srecord.L3,
1536 # statecode,
1537 # srecord.postcode)
1538 #else:
1539 # location = address = ""
1540
1541 table = db.hrm_human_resource
1542 query = (table.id == record.request_for_id)
1543 person = db(query).select(table.person_id,
1544 limitby=(0, 1)).first()
1545 phone = email = report_to = ""
1546 if person:
1547 report_to = person_represent(person.person_id)
1548
1549 ptable = db.pr_person
1550 ctable = db.pr_contact
1551 query = (ptable.id == person.person_id) & \
1552 (ctable.pe_id == ptable.pe_id)
1553 contacts = db(query).select(ctable.contact_method,
1554 ctable.value)
1555 for contact in contacts:
1556 if contact.contact_method == "SMS":
1557 phone = contact.value
1558 elif contact.contact_method == "EMAIL":
1559 email = contact.value
1560
1561 if s3_has_role(STAFF):
1562 subtitle = T("Request Details")
1563 buttons = DIV(
1564 BUTTON(T("PRINT ROSTER"),
1565 _class="wide-grey-button",
1566 _onClick="javascript: window.location='%s'" % \
1567 URL(c=request.controller,
1568 f="req",
1569 args=[record.id,
1570 "assignment",
1571 "print"])),
1572 BUTTON(T("CANCEL REQUEST"),
1573 _class="wide-grey-button",
1574 _onClick="javascript: window.location='%s'" % \
1575 URL(c=request.controller,
1576 f="req",
1577 args=[record.id,
1578 "cancel"]))
1579 )
1580 textbox = ""
1581 else:
1582 subtitle = T("Volunteer Assignment Details")
1583 buttons = ""
1584 if r.component.name == "application":
1585 textbox = P(T("When you volunteer with Give2LA, you are an extension of the good will of the City of Los Angeles. For many survivors, volunteers are their first point of contact. Your respect, courtesy and sensitivity during these difficult times are vital. In addition, following directions, procedures, and processes given to you by your supervisor are essential; failure to do so may exclude you from future volunteer assignments."))
1586 else:
1587 give2la_forms = A( T("Give2LA Registration Forms"),
1588 _href = URL(c="static",
1589 f="Volunteer_Ethics_and_Conduct.pdf"),
1590 _target="_blank"
1591 )
1592 textbox = DIV(P(T("Thank you for Volunteering. Please print out your Volunteer Assignment Form as it contains important information about who, when, and where to report to for your Volunteer Assignment.")),
1593 P(XML(T("As a volunteer working to assist disaster survivors and in disaster recovery efforts, you will be required to fill out and sign the %(give2la_forms)s.") %
1594 dict(give2la_forms = give2la_forms) )),
1595 P(T("Please let us know in advance if you cannot report for your Volunteer Assignment by calling the Point of Contact listed above.")),
1596 )
1597
1598 if record.date_required:
1599 time_req = s3_time_represent(record.date_required,
1600 utc=True)
1601 else:
1602 time_req = ""
1603 if record.date_required_until:
1604 time_until = s3_time_represent(record.date_required_until,
1605 utc=True)
1606 else:
1607 time_until = ""
1608
1609 class DL(DIV):
1610 tag = 'dl'
1611
1612 class DT(DIV):
1613 tag = 'dt'
1614
1615 class DD(DIV):
1616 tag = 'dd'
1617
1618 rheader = DIV(
1619 textbox,
1620 H2(subtitle, _class="paper-strip"),
1621 buttons,
1622 DIV(
1623 TABLE(
1624 TR(
1625 TH(T("Request Number")),
1626 TH(T("Task")),
1627 TH(T("Date+Time")),
1628 TH(T("Required Skills")),
1629 TH(T("Request Priority")),
1630 TH(T("Location")),
1631 TH(T("Number of Volunteers"),BR(),DIV("(", T("Still Required"), "/", T("Total Requested"), ")")), # (assigned/required)
1632 _class="odd"
1633 ),
1634 TR(
1635 TD(record.request_number),
1636 TD(record.purpose),
1637 TD(B(s3_date_represent_utc(record.date_required)),
1638 BR(),
1639 "%s - %s" % (time_req,
1640 time_until),
1641 ),
1642 TD(skills),
1643 TD(response.s3.req_priority_represent(record.priority) ),
1644 TD(record.location or ""),
1645 TD(B(required),
1646 " / %s" % requested,
1647 _class="red"),
1648 _class="even"
1649 ),
1650 _class="datatable display"
1651 ),
1652 _id="table-container"
1653 ),
1654 DL(
1655 DT(T("Point of Contact")),
1656 DD(report_to,
1657 BR(),
1658 "%s: %s" % (T("Phone"),
1659 phone),
1660 BR(),
1661 "%s: %s" % (T("Email"),
1662 email),
1663 ),
1664 DT(T("Volunteering Location")),
1665 DD(#location,
1666 #BR(),
1667 address),
1668 DT(T("Comments")),
1669 DD(record.comments),
1670 _class="assignment-details"
1671 ),
1672 )
1673 if r.component and r.component.name == "assignment":
1674 if s3_has_role(STAFF):
1675 # Volunteer Roster
1676 response.s3.rfooter = DIV(
1677 BUTTON(T("CHECK-IN ALL"),
1678 _class="wide-grey-button",
1679 _onClick="javascript: window.location='%s'" % \
1680 URL(c=request.controller,
1681 f="req",
1682 args=[record.id,
1683 "assignment",
1684 "checkin"])),
1685 BUTTON(T("CHECK-OUT ALL"),
1686 _class="wide-grey-button",
1687 _onClick="javascript: window.location='%s'" % \
1688 URL(c=request.controller,
1689 f="req",
1690 args=[record.id,
1691 "assignment",
1692 "checkout"]))
1693 )
1694 else:
1695 # Volunteer Assignment
1696 assignment = r.component_id
1697 table = db.vol_assignment
1698 query = table.id == r.component_id
1699 record = db(query).select(limitby=(0, 1)).first()
1700 if not record:
1701 # Probably a Volunteer trying to use a URL for STAFF
1702 session.error = auth.permission.INSUFFICIENT_PRIVILEGES
1703 redirect(URL(c="vol", f="req_skill"))
1704 req_id = record.req_id
1705 if record.checkout != None and record.task_evaluation != None:
1706 printBtn = T("PRINT CERTIFICATE")
1707 else:
1708 printBtn = T("PRINT VOLUNTEER ASSIGNMENT FORM")
1709 if record.checkin:
1710 cancelBtn = ""
1711 else:
1712 # Only show the Cancel button if Volunteer not yet checked-in
1713 cancelBtn = BUTTON(T("CANCEL ASSIGNMENT"),
1714 _class="wide-grey-button",
1715 _onClick="javascript: window.location='%s'" % \
1716 URL(c=request.controller,
1717 f="req",
1718 args=[record.req_id,
1719 "assignment",
1720 assignment,
1721 "delete"]))
1722
1723 rheader.append(
1724 DIV(
1725 A(SPAN(printBtn),
1726 _class="big-red-arrow",
1727 _onClick="javascript: window.location='%s'" % \
1728 URL(c=request.controller,
1729 f="req",
1730 args=["assignment",
1731 assignment,
1732 "print"])),
1733 # Also in controllers/don.py - DRY
1734 A(IMG(_src="/%s/static/img/get_adobe_reader.png" % request.application,
1735 _title="%s - %s" % (T("Get Adobe Reader"),
1736 T("This link will open a new browser window.")),
1737 _alt=T("Get Adobe Reader"),
1738 _width=158,
1739 _height=39,
1740 _style="float:right;"),
1741 _href="http://www.adobe.com/products/acrobat/readstep2.html",
1742 _target="_blank"),
1743 BR(),
1744 cancelBtn
1745 )
1746 )
1747 if s3_has_role(STAFF):
1748 rheader.append(rheader_tabs)
1749
1750 return rheader
1751 return None
1752
1753# -----------------------------------------------------------------------------
1754def req():
1755 """ REST Controller """
1756
1757 s3mgr.load("req_req")
1758 default_type = 3
1759 request.vars["default_type"] = 3
1760
1761 if "skill_id" in request.get_vars:
1762 # Look up the Request from the Skill component
1763 # (since that is what is available to us within the dataTables row)
1764 table = db.req_req_skill
1765 query = (table.id == request.vars.skill_id)
1766 req = db(query).select(table.req_id,
1767 limitby=(0, 1)).first()
1768 if not req:
1769 session.error = T("Invalid Request!")
1770 redirect(URL(f="req_skill", args=[], vars={}))
1771 # @ToDo: A nicer way to do this (without a 2nd request)
1772 # simply amending request.args doesn't work
1773 # Need to rewrite to not use prep/postp but rather process r() directly
1774 redirect(URL(args = [req.req_id, "application", "create"],
1775 vars={}))
1776
1777 if "document" in request.args:
1778 s3mgr.load("doc_document")
1779
1780 req_table = db.req_req
1781 s3mgr.configure(req_table,
1782 orderby=~req_table.priority)
1783
1784 type_field = req_table.type
1785 type_field.default = int(default_type)
1786 type_field.writable = False
1787
1788 if s3_has_role(STAFF):
1789 if "assignment" in request.args or \
1790 "checkin" in request.args or \
1791 "checkout" in request.args:
1792 s3mgr.load("vol_assignment")
1793
1794 elif s3_has_role(ORG_VOL):
1795 s3mgr.load("vol_application")
1796 # Volunteer Orgs can see Public Requests & those published for them
1797 org = auth.user.organisation_id
1798 response.s3.filter = (req_table.public == True) | \
1799 (req_table.organisations_id.belongs((org,)))
1800 s3mgr.configure(req_table,
1801 editable=False), # We need the Controller/Table ACL to be editable to be able to add components
1802 if "application" in request.args:
1803 s3.crud.submit_button = T("COMMIT")
1804 table = db.vol_application
1805 table.organisation_id.default = org
1806 table.organisation_id.readable = table.organisation_id.writable = False
1807 table.number.readable = table.number.writable = True
1808 table.person_id.readable = table.person_id.writable = False
1809 field = table.team_leader_id
1810 field.readable = field.writable = True
1811 field.requires = IS_NOT_EMPTY()
1812 #table.person_id.label = T("Team Leader")
1813 #table.person_id.comment = None
1814 #table.person_id.widget = S3AddPersonWidget(
1815 # #select_existing=False
1816 # )
1817 #table.person_id.requires = IS_ADD_PERSON_WIDGET()
1818 #field = table.team_leader
1819 #field.readable = field.writable = True
1820 #field.requires = IS_NOT_EMPTY()
1821 #field = table.team_leader_contact
1822 #field.readable = field.writable = True
1823 #field.requires = IS_NOT_EMPTY()
1824 table.emergency_contact_name.readable = table.emergency_contact_name.writable = False
1825 table.emergency_contact_name.requires = []
1826 table.emergency_contact_relationship.readable = table.emergency_contact_relationship.writable = False
1827 table.emergency_contact_relationship.requires = []
1828 table.emergency_contact_phone.readable = table.emergency_contact_phone.writable = False
1829 table.emergency_contact_phone.requires = []
1830 s3.crud_strings["vol_application"].subtitle_create = ""
1831
1832 elif "assignment" in request.args:
1833 table = db.vol_assignment
1834 table.organisation_id.default = org
1835 table.organisation_id.readable = table.organisation_id.writable = False
1836 table.person_id.readable = table.person_id.writable = False
1837 # Make the component multiple=False
1838 s3mgr.model.add_component("vol_assignment",
1839 req_req=dict(joinby="req_id",
1840 multiple=False))
1841 else:
1842 s3mgr.load("vol_application")
1843 # Volunteers can only see Public Requests
1844 response.s3.filter = (req_table.public == True)
1845 s3mgr.configure(req_table,
1846 editable=False), # We need the Controller/Table ACL to be editable to be able to add components
1847 person = s3_logged_in_person()
1848 if "application" in request.args:
1849 # Check for required Skills
1850 table = db.req_req_skill
1851 query = (table.req_id == request.args[0])
1852 req = db(query).select(table.skill_id,
1853 limitby=(0, 1)).first()
1854 if req and req.skill_id:
1855 # Read the applicant's skills
1856 table = db.vol_skill
1857 query = (table.person_id == auth.s3_logged_in_person())
1858 skillset = db(query).select(table.skill_id,
1859 limitby=(0, 1)).first()
1860 gap = False
1861 if not skillset:
1862 gap = True
1863 else:
1864 for skill in req.skill_id:
1865 if not skill in skillset.skill_id:
1866 gap = True
1867 break
1868 if gap:
1869 response.warning = T("Please check that you have the required skills for this assignment as you've not specified that you have all the required skills.")
1870
1871 s3.crud.submit_button = T("COMMIT")
1872 table = db.vol_application
1873 table.person_id.default = person
1874 table.person_id.readable = table.person_id.writable = False
1875 s3.crud_strings["vol_application"].subtitle_create = ""
1876 # Read in current Emergency Contacts
1877 ctable = db.vol_contact
1878 query = (ctable.person_id == person)
1879 contacts = db(query).select(limitby=(0, 1)).first()
1880 if contacts:
1881 table.emergency_contact_name.default = contacts.emergency_contact_name
1882 table.emergency_contact_relationship.default = contacts.emergency_contact_relationship
1883 table.emergency_contact_phone.default = contacts.emergency_contact_phone
1884
1885 elif "assignment" in request.args:
1886 table = db.vol_assignment
1887 table.person_id.default = person
1888 table.person_id.readable = table.person_id.writable = False
1889 # Make the component multiple=False
1890 # @ToDo: Currently multiple=False will just return the .first() record even if inaccessible!
1891 # That would be fixed by a filter, however then UI would break.
1892 s3mgr.model.add_component("vol_assignment",
1893 req_req=dict(joinby="req_id",
1894 multiple=False))
1895
1896 def prep(r):
1897 db.req_req.status.readable = db.req_req.status.writable = False
1898
1899 # Remove type from list_fields
1900 list_fields = s3mgr.model.get_config("req_req",
1901 "list_fields")
1902 try:
1903 list_fields.remove("type")
1904 except:
1905 # It has already been removed.
1906 # This can happen if the req controller is called
1907 # for a second time, such as when printing reports
1908 # see vol.print_assignment()
1909 pass
1910 s3mgr.configure(tablename, list_fields=list_fields)
1911
1912 # @ToDo: MH - type is always 3
1913 type = ( r.record and r.record.type ) or \
1914 ( request.vars and request.vars.default_type )
1915 if type:
1916 type = int(type)
1917 req_table.type.default = int(type)
1918
1919 # Filter the query based on type
1920 if response.s3.filter:
1921 response.s3.filter = response.s3.filter & \
1922 (db.req_req.type == type)
1923 else:
1924 response.s3.filter = (db.req_req.type == type)
1925
1926 #if type == 3:
1927 s3mgr.configure("req_req",
1928 list_fields = ["id",
1929 "priority",
1930 "event_id",
1931 "purpose",
1932 "site_id",
1933 "date_required",
1934 ])
1935
1936 if r.interactive:
1937 # Set Fields and Labels depending on type
1938 # @ToDo: MH - type is always 3
1939 if type:
1940 # This prevents the type from being edited AFTER it is set
1941 req_table.type.readable = False
1942 req_table.type.writable = False
1943
1944 # @ToDo: MH - refer to crud strings here - rather than in deployment_settings
1945 crud_strings = deployment_settings.get_req_req_crud_strings(type)
1946 if crud_strings:
1947 s3.crud_strings["req_req"] = crud_strings
1948
1949 if "application" in request.args:
1950 s3.crud_strings["req_req"].title_display = T("Volunteer Application")
1951 elif "assignment" in request.args:
1952 if s3_has_role(STAFF) and not r.component_id:
1953 s3.crud_strings["req_req"].title_display = T("Volunteer Roster")
1954 else:
1955 s3.crud_strings["req_req"].title_display = T("Volunteer Assignment")
1956 atable = db.vol_assignment
1957 # @ToDo: Hide if vol hasn't yet checked-out or if time not > time_until
1958 #atable.task_evaluation.readable = False
1959
1960
1961 if r.method != "create" and False: # @ToDo: Remove "and False" - this has been added for training to allow records to be edit
1962 # Disable Edit for fields where WebEOC is Master
1963 req_table.event_id.writable = False
1964 req_table.incident_id.writable = False
1965 #req_table.incident_id.writable = True
1966 req_table.request_number.writable = False
1967 req_table.priority.writable = False
1968 req_table.site_id.writable = False
1969 req_table.request_for_id.writable = False
1970 req_table.date_required.writable = False
1971 req_table.date_required_until.writable = False
1972 req_table.purpose.writable = False
1973 req_table.date.writable = False
1974 req_table.requester_id.writable = False
1975 req_table.approved_by_id.writable = False
1976 req_table.comments.writable = False
1977 req_table.cancel.writable = False
1978
1979 if r.record and r.record.req_req_skill.count():#r.component and r.component.name == "req_skill":
1980 # Is this component being updated (not created)
1981 req_skill_table = db.req_req_skill
1982 req_skill_table.skill_id.writable = False
1983 req_skill_table.quantity.writable = False
1984
1985 # @ToDo: apply these changes via JS for the create form where type is editable
1986 #if type == 3: # Person
1987 req_table.date_required.requires = req_table.date_required.requires.other
1988 req_table.date_required_until.requires = req_table.date_required_until.requires.other
1989 req_table.location.readable = True
1990 req_table.public.readable = True
1991 req_table.organisations_id.readable = True
1992 req_table.emailed.readable = True
1993
1994 if r.method == "create" or True: # @ToDo: Remove "or True" - this has been added for training to allow records to be edit
1995 # Only enable Edit for fields where Sahana (not WebEOC) is Master
1996 req_table.location.writable = True
1997 req_table.public.writable = True
1998 req_table.organisations_id.writable = True
1999
2000 req_table.purpose.label = T("Task Details")
2001 req_table.site_id.label = T("Report To Facility")
2002 req_table.request_for_id.label = T("Point of Contact")
2003
2004 if r.method != "update" and r.method != "read":
2005 if not r.component:
2006 # Hide fields which don't make sense in a Create form
2007 # - includes one embedded in list_create
2008 # - list_fields over-rides, so still visible within list itself
2009 response.s3.req_create_form_mods()
2010
2011 # Get the default Facility for this user
2012 # @ToDo: Use site_id in User Profile (like current organisation_id)
2013 if deployment_settings.has_module("hrm"):
2014 query = (db.hrm_human_resource.person_id == s3_logged_in_person())
2015 site = db(query).select(db.org_site.id,
2016 limitby=(0, 1)).first()
2017 if site:
2018 r.table.site_id.default = site.id
2019
2020 elif r.component.name == "document":
2021 s3.crud.submit_button = T("Add")
2022 table = r.component.table
2023 # @ToDo: Fix for Link Table
2024 #table.date.default = r.record.date
2025 #if r.record.site_id:
2026 # stable = db.org_site
2027 # query = (stable.id == r.record.site_id)
2028 # site = db(query).select(stable.location_id,
2029 # stable.organisation_id,
2030 # limitby=(0, 1)).first()
2031 # if site:
2032 # table.location_id.default = site.location_id
2033 # table.organisation_id.default = site.organisation_id
2034
2035 elif r.component.name == "req_skill":
2036 #req_hide_quantities(r.component.table)
2037 table = r.component.table
2038 table.quantity_commit.writable = table.quantity_commit.readable = False
2039 table.quantity_fulfil.writable = table.quantity_fulfil.readable = False
2040
2041 if r.component:
2042 if r.component.name == "document" or \
2043 r.component.name == "req_skill":
2044 # Limit site_id to facilities the user has permissions for
2045 # @ToDo: Non-Item requests shouldn't be bound to a Facility?
2046 auth.permission.permitted_facilities(table=r.table,
2047 error_msg=T("You do not have permission for any facility to make a request."))
2048
2049 elif r.component.name == "assignment":
2050 table = db.vol_assignment
2051 # Tweak the breadcrumb
2052 if r.component.count() > 1:
2053 label = T("Roster")
2054 else:
2055 label = T("Assignment")
2056 breadcrumbs[2] = (label, False,
2057 URL(c=request.controller,
2058 f=request.function,
2059 args=request.args))
2060 if s3_has_role(STAFF):
2061 table.report_to_id.default = r.record.request_for_id
2062 else:
2063 # Volunteer can evaluate task if vol has checked-in and (checked-out or time > time_until)
2064 query = (table.id == r.component_id)
2065 assign = db(query).select(table.checkin,
2066 table.checkout,
The diff has been truncated for viewing.